Custom Claims Principals in .NET 4.5

Recently I got a number of questions on what’s the best approach to implement a “custom claims principal”. What people typically mean by this is a ClaimsPrincipal derived class that provides some extra API surface like properties (think .EmailAddress). The reasons for that are mostly “type safety” and for streamlining the code.

The basic approach
The right way to associate identity data in .NET 4.5 with a security context is to use the claims collection – and nothing else. The reason I say this is, that other parts of the .NET Framework use that collection to give you additional services – like session management. So don’t even try to invent your own system unless you explicitly want something “separate”.

Given that all claims are in the collection you can write a very thin ClaimsPrincipal derived class to achieve the “strong typing”:

public class CustomClaimsPrincipal : ClaimsPrincipal

{

    public CustomClaimsPrincipal(ClaimsPrincipal principal)

        : base(principal)

    { }

 

    public bool IsOperator

    {

        get

        {

            return HasClaim(ClaimTypes.Role, “Operator”);

        }

    }

}

 

You would then simply wrap a standard ClaimsPrincipal (with its ClaimsIdentity and claims) with your derived class and use the standard operators (HasClaim, FindAll, FindFirst) to provide your more domain specific API.

An obvious place to set your custom claims principal in the pipeline would be e.g. a ClaimsAuthenticationManager.

Session management and type identity
Now when you use the above approach in conjunction with the session authentication module, you will notice that after the principal has once made the round-trip through session de/serialization, you will get a standard ClaimsPrincipal back in your application code.

This is because that during session token creation and re-hydration the type identity is lost. As I said, from a .NET Framework point of view, all that counts is the claims collection and not the type holding it (there is some special casing for Windows based principals, but that’s an internal implementation detail).

This means you need some extra plumbing to re-wrap that ClaimsPrincipal in your derived type for every request. Either automatically (e.g. in the PostAuthenticateRequest event in ASP.NET) – or simply while accessing it in application code, you could e.g. add a static method to your custom principal:

public static new CustomClaimsPrincipal Current

{

    get

    {

        return new CustomClaimsPrincipal(ClaimsPrincipal.Current);

    }

}

 

So your application code could look like this:

var p = CustomClaimsPrincipal.Current;

var op = p.IsOperator;

 

Extension methods
I actually prefer to stay away from derivation and rather use extension methods when I need to access certain information frequently and want to keep my code “clean”. Imagine this:

public static class ClaimsPrincipalExtensions

{

    public static bool IsOperator(this ClaimsPrincipal principal)

    {

        return principal.HasClaim(ClaimTypes.Role, “Operator”);

    }

}

 

Which basically gives you a programming model like this:

var op = ClaimsPrincipal.Current.IsOperator();

 

So in conclusion I think the only important thing to remember is, that if you want to play nice with “the system”, you should use the claims collection to associate identity information with a user. The way you access that information is totally up to. Derivation, helper methods or extension methods are just syntactic sugar.

This entry was posted in .NET Security, IdentityModel. Bookmark the permalink.

11 Responses to Custom Claims Principals in .NET 4.5

  1. Tim says:

    What happens when one has dozens of claims. What can we do to lessen the bloated tokens? Thanks in advance. We are SPA based app and looking at some suggestions.

      • Chris says:

        So how much is too much? I know you hit a hard limit when it comes to token size, and can have issues with performance, but is dozens of claims a bad idea architecturally speaking? I have a situation where we are moving to a new access setup where we certainly could have dozens of permissions because we need really fine grained access over lots of screens in the application. I was trying to see if there was some smart way of reducing the claims, but I couldn’t see any way, so I’m trying to figure out if this is a real or perceived problem.

  2. I have tried to add my custom claims in the PostAuthenticateRequest in an ASP.NET MVC 4 application, but the custom claims get lost somewhere in the process. I am using forms authentication and I suspect that it is the cookie that is stepping on my custom claims. Is there somewhere else I should be adding my custom claims? I am using a custom AuthenticationManager to add my claims but it appears that in .NET 4.5 it is not automatically called anywhere in the process and you have to invoke it manually.

  3. Daniel Hilgarth says:

    In a ASP.NET Web API where would you actually add this “Operator” Role to the Claims collection?
    I am currently using Basic Authentication with AuthenticationConfiguration.AddBasicAuthentication. However, in the validation delegate I can’t add the role, because the infrastructure creates a new principal after the delegate, so the roles I added to the old one are lost.
    Currently I registered a class derived from ClaimsAuthenticationManager as the ClaimsAuthenticationManager of the AuthenticationConfig.
    I cann add my roles there and it works, but it feels not really right, because I would have two database hits in this scenario:
    One in my validation delegate to actually check the username and password and one in my AuthenticationManager to fetch the roles of the user.
    This seems unnecessary.

    It would be nice if the validation delegate could return custom claims that are used by the infrastructure for the new principal.
    What do you think?

  4. Either use the session token feature, or do caching in the ClaimsAuthMgr.,

  5. That said – I am considering this as a new feature.

  6. nevermind about my comment on other blog post – this is a case, thanks :)

Leave a comment