Enforcer configuration follows the standard model introduced in Asp.Net Core. If you are using Asp.Net Core then the configuration code sits within the Startup code in the ConfigureServices method. If you are using a different application framework then you will need to add the Nuget package Microsoft.Extensions.DependencyInjection and create an instance of the ServiceCollection class to perform the configuration.
AddEnforcer
The starting point for configuration is the AddEnforcer extension method on ServiceCollection. This takes two parameters: a root policy name which is the Policy or PolicySet in your Alfa documents that is the starting point for policy evaluation and an Action<EnforcerOptions> which allows you to set the following options:
| Property | Description |
|---|---|
| Licensee | The name of the organisation your license has been issued to |
| LicenseKey | Your Enforcer license key |
| PolicyInformationPointFailureBehavior | The behavior you want if an AttributeValueProvider throws an exception. FailFast or Continue (default) |
| DiagnosticAttributeSensitivityLoggingLevel | When performing diagnostic logging, what level of sensitivity should attribute values be recorded in the logs. NonSensitive (default) Sensitive or PII (Personally Identifiable Information) |
The EnforcerOptions also allows you to register assemblies that contain custom functions that you have used in your Alfa policies.
AddEnforcer will add the EnvironmentAttributeValueProvider automatically so these attributes will be available to your policies without further action.
AddEnforcer Example
var services = new ServiceCollection();
services.AddEnforcer("global", o =>
{
o.PolicyInformationPointFailureBehavior = PolicyInformationPointFailureBehavior.FailFast;
o.Licensee = "<company name>";
o.LicenseKey = "<license key>";
o.AddFunctionAssembly("CustomFunctions");
o.AddFunctionAssembly(Assembly.GetExecutingAssembly());
});
AddEnforcer returns an EnforcerBuilder which acts as the base for the rest of the configuration to be specified. The configuration is modelled as a fluent API so the rest of the configuration methods are typically chained on to AddEnforcer.
Adding a Policy Store
Enforcer comes with three styles of policy store: File System, Embedded Resource, and Git. It is also an extensibility point if you have other requirements about where to store your authorization policies. For Git based policy stores, Enforcer supports both GitHub and Azure Devops.
File System Policy Store
The file system policy store uses a root directory under which the Alfa files can be placed directly or in subdirectories. Changes to any policy file causes the policies to be recompiled for the next policy evaluation. The EnforcerBuilder has an extension method AddFileSystemPolicyStore that takes the following parameters
| Name | Type | Description |
|---|---|---|
| storeRootDirectory | string | The location of the folder that is the root of the policy store |
| policyFileExtension | string | The extension of the files that contain Alfa policies. The parameter is optional and will default to alfa |
| configFileName | string | The file name for the alfa compiler configuration file. The parameter is optional and defaults to alfaconfig.json. See the Alfa Compiler Configuration page for more details |
AddFileSystemPolicyStore Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddFileSystemPolicyStore("~/policies", "alfa");
Embedded Policy Store
You can add your policy files as embedded resources within your application. This allows you to know either certainty what authorization policy was in effect in any version of the software. The policy files must be placed under a common root in the embedded resources. To use the embedded policy store call the AddEmbeddedPolicyStore method on the EnforcerBuilder. There are two overloads of this method
| Name | Type | Description |
|---|---|---|
| resourceAssembly | Assembly | An assembly reference for the assembly that contains the embedded resources |
| resourceRoot | string | The root of the resource names that define the policy files |
| policyFileExtension | string | The file extension of the embedded resource files. This parameter is optional and defaults to alfa |
| configFileName | string | The file name for the alfa compiler configuration file. The parameter is optional and defaults to alfaconfig.json. See the Alfa Compiler Configuration page for more details |
| Name | Type | Description |
|---|---|---|
| resourceRoot | string | The root of the resource names that define the policy files. These resources are assumed to be in the assembly that calls this method (equivalent to calling the first overload with a resourceAssembly parameter of Assembly.GetExecutingAssembly()) |
| policyFileExtension | string | The file extension of the embedded resource files. This parameter is optional and defaults to alfa |
AddEmbeddedPolicyStore Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddEmbeddedPolicyStore("policies.v1", "alfa");
Git Policy Store
Using Git for your policy store allows an authorization policy to evolve without redeploying the application but allows controls and an audit trail for changes. The Git policy store supports both GitHub and Azure Devops. To use the Git policy store you must first reference the Rsk.Enforcer.Store.Git Nuget package. Then use the AddGitPolicyStore extension method and then, on the GitPolicyStoreOptions options object specify which provider to use using either AddAzureDevops or AddGitHub. Both of these have options to set to specify exactly how to integrate with the provider. You also specify how often to check for changes in the policy via the GitPolicyStoreOptions using the PollingInterval property which defaults to 5 minutes.
Using Azure Devops
Reference the Rsk.Enforcer.Store.Git.AzureDevops Nuget package.
The Git Policy Store needs to be able to authenticate wth Azure Devops. To allow this you must create a Personal Access Token for the account under which the store will access the repository. Instructions on how to create a Personal Access Token are here. The only scope the token needs is full access to code.
When you call AddAzureDevops on the GitPolicyStoreOptions, you need to configure the AzureDevopsGitClientOptions. It has the following properties:
| Name | Type | Description |
|---|---|---|
| PersonalAccessToken | string | The personal access token that allows the policy store to talk to the policy repository in Azure Devops |
| TenancyName | string | The name of your tenancy in Azure Devops |
| Project Name | string | The name of the Azure Devops project that contains the policy repository |
| RepositoryName | string | The name of the repository that holds the policy files |
| BranchToWatch | string | The name of the branch that is the active authorization policy. The is the branch that the store will monitor for changes to reload the policy |
| PolicyRootFolder | string | The root folder of the policy files within the repository |
| PolicyFileExtension | string | The extension of the policy files. This defaults to alfa |
Azure Devops Git Policy Store Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddGitPolicyStore( o =>
{
o.PollingInterval = TimeSpan.FromMinutes(10);
o.AddAzureDevops(devopsOptions =>
{
devopsOptions.PersonalAccessToken = "rqsixv4k7nuacbzhddeegeiteigbcfwyz2imvuz34ocvtgmivefa";
devopsOptions.TenancyName = "acmecorp";
devopsOptions.ProjectName = "Nugen";
devopsOptions.RepositoryName = "NugenPolicy";
devopsOptions.BranchToWatch = "master";
devopsOptions.PolicyRootFolder = "policy";
});
});
Using GitHub
Reference the Rsk.Enforcer.Store.Git.GitHub Nuget package.
The Git Policy Store needs to be able to authenticate wth GitHub. To allow this you must create a Personal Access Token for the account under which the store will access the repository. Instructions on how to create a Personal Access Token are here. The scope that the personal access token needs is full access to repositories.
When you call AddGitHub on the GitPolicyStoreOptions, you need to configure the GitHubGitClientOptions. It has the following properties:
| Name | Type | Description |
|---|---|---|
| PersonalAccessToken | string | The personal access token that allows the policy store to talk to the policy repository in Azure Devops |
| RepositoryName | string | The name of the repository that holds the policy files |
| BranchToWatch | string | The name of the branch that is the active authorization policy. The is the branch that the store will monitor for changes to reload the policy |
| PolicyRootFolder | string | The root folder of the policy files within the repository |
| PolcyFileExtension | string | The extension of the policy files. This defaults to alfa |
GitHub Git Policy Store Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddGitPolicyStore( o =>
{
o.PollingInterval = TimeSpan.FromMinutes(10);
o.AddGitHub(githubOptions =>
{
githubOptions.PersonalAccessToken = "rqsixv4k7nuacbzhddeegeiteigbcfwyz2imvuz34ocvtgmivefa";
githubOptions.RepositoryName = "NugenPolicy";
githubOptions.BranchToWatch = "master";
githubOptions.PolicyRootFolder = "policy";
});
});
Using a Custom Policy Store
When you create a custom policy store you need to implement the Rsk.Enforcer.PAP.Store.IPolicyStore interface. You then use the AddPolicyStore extension method on the EnforcerBuilder.
Custom Policy Store Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddPolicyStore<MyCustomPolicyStore>();
Configuring the Policy Enforcement Point
The PEP must be configured using the AddPolicyEnforcementPoint extension method on EnforcerBuilder. This allows you to set the PolicyEnforcementPointOptions with the following properties:
| Name | Type | Description |
|---|---|---|
| Bias | PepBias | The PEP Bias is the outcome the PEP will return if the PDP cannot come to a dinfinitive conclusion (for example, if one or more attributes needed for evaluation were not available) or an obligation could not be satisfied. The application needs a definitive result to know whether it can proceed and so the PEP Bias is used to produce that result. The Bias has two possible values: Deny (default) and Permit. |
PEP Configuration Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddPolicyEnforcementPoint( o =>
{
o.Bias = PepBias.Permit;
});
Adding OutcomeActionHandlers
OutcomeActionHandlers are used to satisfy obligations and advice. If your policy issues obligations you must register outcome action handlers to process those obligations as the PEP enforces obligations before returning to the caller. Outcome Action Handlers may also be used to automatically resolve advice returned from a policy evaluation. Any advice that would not be automatically satisfied, using an outcome action handler, will be returned to the caller as unresolved advice.
How you add an outcome action handler depends on whether it is stateful during an evaluation. If the handler is stateless (does not change its shared state during execution), you can register thge handler directly. However, if it does change state then you need to create a factory that will create the handler on demand. Outcome action handlers must, ultimately, derive from OutcomeActionHandler and factories must ultimately derive from OutcomeActionHandlerFactory.
Enforcer ships with one outcome action handler, SmtpOutcomeActionHandler for sending email messages as a result of policy evaluation. Enforcer also has a base class OutcomeActionHandler<T> to simpify building your own outcome action handlers. Custom output action handlers are added via the AddOutcomeActionHandler extension method of EnforcerBuilder and factories are added using the AddOutcomeActionHandlerFactory extension method.
Adding an OutcomeActionHandler Example
services.AddEnforcer("global", o =>
{
o.Licensee = "International Space Station";
o.LicenseKey = "<license key>";
})
.AddOutcomeActionHandler<AuditOutcomeActionHandler>()
.AddOutsomeActionHandlerFactory<AirlockDoorOutcomeActionHandlerFactory>();
Using the SmtpOutcomeActionHandler
To use the SMTP outcome action handler you need to reference the Rsk.Enforcer.OutcomeActions.Smtp Nuget package. You can then use the AddSmtpOutcomeActionHandler extension method of EnforcerBuilder and configure the SmtpOutcomeActionHandlerOptions. The following properties are suported:
| Name | Type | Description |
|---|---|---|
| SmtpServer | string | The server name or IP address of the SMTP server |
| Port | int | The port the SMTP server is listening on |
| UseTls | bool | Whether or not the SMTP connection will use TLS to secure the connection |
| UserId | string | The user id for authenticating with the server |
| Password | string | The password for authenticating with the server |
| From | string | The email address emails will default to being from |
When referencing the outcome action handler as an obligation or advice in your Alfa policy documents the name of the handler is Rsk.Enforcer.ActionHandlers.Smtp. It uses the following attributes:
| Name | Category | Type | Mandatory | Description |
|---|---|---|---|---|
| to | Rsk.Enforcer.ActionOutcomes.Smtp | String | Yes | The email address(es) to send to |
| from | Rsk.Enforcer.ActionOutcomes.Smtp | String | No | The email address the email is sent from. If omitted the default set up in the SmtpOutcomeActionHandlerOptions is used |
| cc | Rsk.Enforcer.ActionOutcomes.Smtp | String | No | The email address(es) that are copied on the email |
| subject | Rsk.Enforcer.ActionOutcomes.Smtp | String | Yes | The subject of the email |
| body | Rsk.Enforcer.ActionOutcomes.Smtp | String | Yes | TThe body of the email |
Using the SMTP Outcome Action Handler Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddSmtpOutcomeActionHandler(o =>
{
o.SmtpServer = "192.168.4.45";
o.Port = 993;
o.UseTls = true;
o.UserId = "emailgateway";
o.Password = "iudghfiugsdu";
o.From = "alerts@rocksolidknowledge.com";
});
Adding Attribute Value Providers
Attribute value providers are used by the PIP to resolve attributes requested by the policy evaluation. Enforcer comes with two general use attribute value providers:
| Name | Description |
|---|---|
| EnvironmentAttributeValueProvider | This provides attributes for current date, time and day of week. It is added automatically so you do not have to take any action for these attributes to be available |
| DynamicAttributeValueProvider | This is a general purpose component allowing code to add attributes it wants dynamically enabling them to be resolved during policy evaluation. |
Custom attribute value providers must directly or indirectly implement Rsk.Enforcer.PIP.IAttributeValueProvider. They are added via the AddAttributeValueProvider extension method of EnforcerBuilder. Generally, to implement a custom attribute value provider, you will derive from RecordAttributeValueProvider or use DelegatingRecordAttributeValueProvider. There is also a low level base class that you can use called AttributeValueProvider but its usage is more complex. More information on creating custom attribute value providers can be found in the extensibility section.
Adding a Custom Attribute Value Provider Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
})
.AddAttributeValueProvider<LDAPAttributeValueProvider>();
Excluding built-in Attribute Value Providers
Enforcer automatically includes the EnvironmentAttributeValueProvider, which provides attribute values relating to the current date and time. In situations where this is undesirable, such as a unit test for policy code, the EnvironmentAttributeValueProvider can be excluded by setting the OmitStandardPIPs flag on the EnforcerOptions.
Excluding EnvironmentAttributeValueProvider Example
services.AddEnforcer("global", o =>
{
o.Licensee = "Rock Solid knowledge";
o.LicenseKey = "<license key>";
o.OmitStandardPIPs = true;
})