.NET Runtime Client
The runtime client library communicates with the runtime API to turn a user’s identity into application roles and permissions.
The library is provided as a NuGet package with the name PolicyServer.Runtime.Client.
Creating and configuring the Runtime Client
In the easiest case, you configure the name of the base policy, URL of the token server, and credentials in code:
var options = new PolicyServerRuntimeClientOptions
{
BasePolicy = "EmergencyRoom",
TokenClient =
{
Authority = "<insert here>",
ClientId = "runtime.client",
ClientSecret = "<insert here>"
}
};
You can then either create the client via a DI container, e.g.:
var services = new ServiceCollection();
services.AddPolicyServerRuntimeClientCore(options =>
{
options.BasePolicy = "EmergencyRoom";
options.TokenClient.Authority = "<insert here>";
options.TokenClient.ClientId = "runtime.client";
options.TokenClient.ClientSecret = "<insert here>";
});
var provider = services.BuildServiceProvider();
var client = provider.GetService<IPolicyServerRuntimeClient>();
…or by calling the Create
method (if no DI is available):
var client = PolicyServerRuntimeClient.Create(options);
A third option is to use the .NET Core configuration API, e.g. with the following configuration file:
{
"PolicyServerRuntimeClient": {
"BasePolicy": "EmergencyRoom",
"TokenClient": {
"Authority": "<insert authority here>",
"ClientId": "runtime.client",
"ClientSecret": "<insert runtime API client secret here>"
}
}
}
…and then initialize the client like this:
services.AddPolicyServerRuntimeClientCore(Configuration.GetSection("PolicyServerRuntimeClient"));
Using an external Token Service
By default, PolicyServer contains an embedded token service to issue tokens for the runtime API. If you already have an OAuth 2.0 authorization server, you can use your server to issue tokens instead. In this case, you specify different addresses for PolicyServer and your token service in configuration, e.g.:
{
"PolicyServerRuntimeClient": {
"PolicyServerUrl": "<insert address of policyserver>",
"BasePolicy": "EmergencyRoom",
"TokenClient": {
"Authority": "<insert authority here>",
"ClientId": "runtime.client",
"ClientSecret": "<insert runtime API client secret here>"
}
}
}
Creating Claims for Policy Evaluation
Either you create claims to represent the current user, or you forward the claims of the currently logged on user (e.g. via the User
property in ASP.NET).
An easy way to create a principal is using the Principal
helper class:
var user = Principal.Create("ps",
new Claim("sub", "1"),
new Claim("role", "Surgeon"),
new Claim("tenant", "5"));
The claims sub
, role
and tenant
have special meanings in PolicyServer. sub
specifies the unique identifier for the user,
role
an identity role and tenant
is a tenant identifier (see Claims Transformation).
Calling the Runtime API
You can then use the client library to send the claims to the configured policy to retrieve application roles and permissions:
var result = await client.EvaluateAsync(user);
if (result.IsError) throw new Exception(result.Error);
result.Roles.ToList().ForEach(i => Console.WriteLine(i));
result.Permissions.ToList().ForEach(i => Console.WriteLine(i));
EvaluateSync
will return all application roles and permissions based on the incoming claims. You can also call IsInRoleAsync
or HasPermissionAsync
as
shortcuts if you want to check for a specific role or permission.
Caching
By default, every call will result in a network round trip to the runtime API. You can also specify CacheDuration
on the PolicyServerRuntimeClientOptions
(in seconds),
which means that the result will be cached locally for the specified amount of time:
var options = new PolicyServerRuntimeClientOptions
{
BasePolicy = "EmergencyRoom",
CacheDuration = 300,
TokenClient =
{
Authority = "<insert here>",
ClientId = "runtime.client",
ClientSecret = "<insert here>"
}
};
Claims Transformation
The PolicyServer runtime API expects some claims to have certain claim types:
sub
- a unique user identifierrole
- an identity roletenant
- a tenant identifier
You might use different claim types in your system to express the same data.
If you create the ClaimsPrincipal
yourself - you need to transform your claim types to the expected claim types.
If you want to forward an existing identity (maybe created by some application plumbing or coming from your identity system),
the client library can also do automatic claims transformation for you.
You can configure that on the PolicyServerRuntimeClientOptions
, e.g.:
var options = new PolicyServerRuntimeClientOptions
{
BasePolicy = "EmergencyRoom",
TokenClient =
{
Authority = "<insert here>",
ClientId = "runtime.client",
ClientSecret = "<insert here>"
},
ClaimTypes =
{
Subject = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
Tenant = "http://myorg/claims/tenantid"
}
};
This would automatically translate a claim of type http://myorg/claims/tenantid
to our expected tenant
.
Runtime Client Flags
The PolicyServer runtime API support some flags that helps extract more data the claims evaluations. These flags are:
IncludePolicyDiagnostics
EvaluateChildPolicies
IncludeChildrenWithDescendantAssignments
IncludeTenantRoles
IncludePolicyDiagnostics
When evaluating a policy that resides within a hierarchy, roles and permissions can be assigned at any level in the hierarchy. If you wish to debug which policy in the hierarchy has made specific assignments, the IncludePolicyDiagnostics
flag can be used:
e.g.:
var client = PolicyServerRuntimeClient.Create(options);
var user = Principal.Create("test", new Claim("sub", "1111"));
var result = client.EvaluateAsync(new PolicyEvaluationRequest {
User = user,
IncludePolicyDiagnostics = true
}).Result;
EvaluateChildPolicies
When evaluating a policy, you can also request that the child policies are also evaluated and returned in the response (which includes the child policies’ roles and permissions) with the EvaluateChildPolicies
parameter.
This only evaluates the immediate child policies, not the entire descendant hierarchy. If no roles or permissions are matched in the child policy, then the child policy is not included in the response. This indicates that the user has no access to the policy. e.g.:
var client = PolicyServerRuntimeClient.Create(options);
var user = Principal.Create("test", new Claim("sub", "1111"));
var result = client.EvaluateAsync(new PolicyEvaluationRequest {
User = user,
EvaluateChildPolicies = true
}).Result;
IncludeChildrenWithDescendantAssignments
When evaluating child policies (as described above), children where no role or permission is issued is not emitted in the response. There might be descendant policies beneath the child that do have role or permission assignments, but when simply evaluating child policies those are not taken into consideration.
If, when evaluating child policies, you do want the policies where some assignment is granted somewhere in the descendant policy hierarchy, then include the IncludeChildrenWithDescendantAssignments
in the request.
e.g.:
var client = PolicyServerRuntimeClient.Create(options);
var user = Principal.Create("test", new Claim("sub", "1111"));
var result = client.EvaluateAsync(new PolicyEvaluationRequest {
User = user,
IncludeChildrenWithDescendantAssignments = true
}).Result;
IncludeTenantRoles
Normally the runtime API evaluation return the subject roles in all policies, but does not include the tenant roles even if the tenant claim was sent in the evaluation request.
The IncludeTenantRoles
parameter in a policy evaluation request allows the runtime API to include the roles for the tenant claim sent in the request.
e.g.:
var client = PolicyServerRuntimeClient.Create(options);
var user = Principal.Create("test", new Claim("sub", "1111"));
var result = client.EvaluateAsync(new PolicyEvaluationRequest {
User = user,
IncludeTenantRoles = true
}).Result;