Dependency Injection of Custom Claim Authorisation Manager

Claims

Authorisation is one of the most intertwined aspect in an application. We find it the most difficult part to isolate its implementations from rest of the logic. We can overcome partly syntactically through declarative sugar, but for more complex evaluations we might have to go inline. But the application still needs to continue checking the validity of the user.

The best thing that happened in security since .NET version 4.5 is that Claims became the base for all identity based security and with it we also saw ways through which we could externalise the authorisation logic (and also building of claims). A claim is statement or declaration made about oneself or others. When a user tries to claim access to any resource, the authorisation process assess if they trust the issuer of the claim and evaluates the claim.

In claim based authorisation the applications need not authenticate individuals and find out about the user. It is presented with claims by the user and the application just uses it to determine if they indeed have the right claim to continue. Now the application is undisturbed (decoupled) by the ever changing roles of a user or whether it has to accommodate any changed roles. As long as the user presents it with the right claims they get access.

Using claims not just simplifies authorisation, but you can use it to add other important facts about the user. During authentication, we could query multiple systems or specific sources which the application is more interested in and build the claim for the user. These could be email addresses, roles, position, mode of transport, dietary preferences anything which makes sense and need to share that information with applications. You can already see if used correctly how it would make authorisation and personalisation mush more easier in applications.

Enough with the introductions already! Windows Identity Foundation has now been merged with .NET Framework and we have access to default implementations of ClaimsAuthorizationManager. We can override this programmatically by using IdentityConfiguration or through application configuration file.

Through configuration:

1
2
3
4
5
<system.identityModel>
<identityConfiguration>
<claimsAuthorizationManager type="CustomAuthorisationManager"/>
</identityConfiguration>
</system.identityModel>

One limitation which it presents is that the custom type reference which we provide through configuration must have a 0 argument constructor. Which means we cannot specify any dependencies through the constructor.

This can however be overcome through code. We can register for the event FederationConfigurationCreated and when the FederationConfiguration is initialised, this event is raised where we can then modify the configuration to assign our own ClaimsAuthorizationManager.

Through code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
namespace ClaimsAwareApp
{
class App
{
static void Main(string[] args)
{
FederatedAuthentication.FederationConfigurationCreated +=
FederatedAuthentication_FederationConfigurationCreated;

//declarative
DoAction();

// inline
var cuthmgr = FederatedAuthentication.FederationConfiguration
.IdentityConfiguration.ClaimsAuthorizationManager;
var authContext =
new AuthorizationContext(ClaimsPrincipal.Current, "SomeResource", "Execute");
if (cuthmgr.CheckAccess(authContext))
Console.WriteLine("DoAction");
}

[ClaimsPrincipalPermission(
SecurityAction.Demand,
Operation = "Execute",
Resource = "SomeResource")]
static void DoAction()
{

}

private static void FederatedAuthentication_FederationConfigurationCreated(object sender,
FederationConfigurationCreatedEventArgs e)
{
DependencyFactory factory = new DependencyFactory();
e.FederationConfiguration.IdentityConfiguration.ClaimsAuthorizationManager =
new CustomClaimAuthorisation(factory);
//e.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager
// = new ClaimsAuthenticationManager();
}
}

class CustomClaimAuthorisation : ClaimsAuthorizationManager
{
private readonly DependencyFactory factory;
public CustomClaimAuthorisation(DependencyFactory factory)
{
this.factory = factory;
}

public override bool CheckAccess(AuthorizationContext context)
{
// Get instance from factory
using (var store = factory.GetStore())
{
// Do your authorisation
return base.CheckAccess(context);
}
}
}
class DependencyFactory
{
public MyStore GetStore()
{
return new MyStore();
}
}

class MyStore : IDisposable
{
public void Dispose()
{
// clean up
}
}
}

Few points to note!

You need to have system.identityModel in your configSections of your configuration file.

1
2
3
4
5
6
7
8
<configuration>
<configSections>
<section name="system.identityModel"
type="System.IdentityModel.Configuration.SystemIdentityModelSection,
System.IdentityModel, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
</configuration>

Without the above entry you would run into the below exception.

Message=ID7027: Could not load the identity configuration because no <system.identityModel> configuration section was found.

I think this config section is mandatory to get access to instance of FederationConfiguration. I anyway have not found a work around for this.

Also note that FederationConfiguration is created as a singleton and you would always get the same instance of ClaimsAuthorizationManager or ClaimsAuthenticationManager. So take care how you manage the lifetime of the objects which you inject inside of these instances. If you need to dispose them after each call, I recommend inject Factory instance instead of the actual concrete instance. This way you can dispose of the concretes and have the factory provide you with a new instance on each call to CheckAccess in the case of authorisation.

Of course for a web application, one should register the FederationConfigurationCreated event under global.asax App start.