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 |
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 |
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 alling 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 |
PolcyFileExtension | 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;
})