Skip to content

Adding custom roles to windows roles in ASP.NET using claims

January 17, 2013

If you’ve been using WIF (Windows Identity Foundation) for any amount of time this shouldn’t be anything new, but for folks that haven’t had their eyes opened yet to using claims-based identity then I wanted to show how it’s very easy to add custom roles to windows roles (or any other claim type for that matter).

Here’s the requirement: I’m using windows authentication and I get all the groups back for the user as roles, but I want to also add additional application specific roles to the user for authorization purposes.

First thing to note here is that if you’re using windows authentication then you don’t need to use the WindowsTokenRoleProvider since the user’s groups are already loaded via windows authentication and most of the methods in this class throw an exception letting you know they’re not implemented (thus illustrating that role providers aren’t all that useful).

Second, if you’re using .NET 4.5 (since all the identity classes are claims-aware) then it’s dirt simple to augment them with custom claims (including roles). In ASP.NET you’d need to hook the same event in the HTTP pipeline that you’d hook for custom roles (as I already pointed out here). In short you need to load your custom roles (or claims) from your custom store/database and then augment the current principal with them in the Application_PostAuthenticateRequest in global.asax. Here’s the code:

void Application_PostAuthenticateRequest()
{
    if (Request.IsAuthenticated)
    {
        string[] roles = GetRolesForUser(User.Identity.Name);
        var id = ClaimsPrincipal.Current.Identities.First();
        foreach (var role in roles)
        {
            id.Claims.Add(new Claim(ClaimTypes.Role, role));
        }
    }
}

HTH

24 Comments leave one →
  1. January 23, 2013 10:16 am

    This is very interesting to me. So can I assume using this method it is more responsive when I want to use the Authorize Attribute on MVC Controllers or individual methods inside of a specific controller? I felt forced to hack create my own Authorize attribute because of the MVC limitations. I think a bit of a hack, but I really needed to define my application roles that would be assigned AD Groups of people. http://thomasgathings.com/?p=34

    If what you have above allows me to use the native Authorize Attribute with a string of roles that are application defined I may dance a jig.

    • January 23, 2013 10:28 pm

      These are doing different things — the PostAuthRequest allows for a place to load additional info about user. Prior to claims this was done as roles, but now with claims you can load any data.

      The [Authorize] attribute is doing authorization checks. If you built custom attributes to do DB checks, they could instead do checks against the claims that were loaded from the PostAuthRequest.

  2. RonyK permalink
    April 17, 2013 10:57 am

    What would be the best way to add a custom role (or other custom claim) to a security token, in a way that this claim would exist in the session cookie for subsequent requests, and even make the bootstrap token to contain the custom claim, to allow delegating the token to a web API service?

  3. omardelgado2014 permalink
    April 16, 2014 5:25 pm

    Brock,

    I have recently tried to implement this, with just a slight change necessary due to language updates I assume.

    I Changed
    id.Claims.Add(new Claim(ClaimTypes.Role, role));
    To
    id.AddClaim(new Claim(ClaimTypes.Role, role));
    The code seems to work up until that part. The problem is Whenever I run ClaimsPrincipal.Current.IsInRole(role) it always returns false. I have iterated through the claims collection for the roles and they appear :
    {http://schemas.microsoft.com/ws/2008/06/identity/claims/role: Author}
    Issuer: “LOCAL AUTHORITY”
    OriginalIssuer: “LOCAL AUTHORITY”
    Properties: Count = 0
    Subject: {System.Security.Principal.WindowsIdentity}
    Type: “http://schemas.microsoft.com/ws/2008/06/identity/claims/role”
    Value: “Author”
    ValueType: “http://www.w3.org/2001/XMLSchema#string”

    But the IsInRole method never returns true.

    I don’t know if this is an old deprecated method, a new issue caused by a newer version of the development environment (VS2013 premium update 1) or an isolated incident. If bad comes to worse I guess I’m going to have to override the IsInRole method.

    • April 16, 2014 6:21 pm

      You shouldn’t have to override IsInRole. I’ll have to check this when I get a chance.

      • May 1, 2014 6:13 pm

        Brock,

        Right now I am getting things to work by using a new generic principal and using the windows principal identity in the constructor as well as the roles obtained from the db. I then assign the principal to the thread and my methods can verify based on those custom roles.

  4. Michael permalink
    April 25, 2014 8:34 am

    This is due to the claims principal and how the IsInRole method varies between a “ClaimsPrincipal” and the “WindowsPrincipal”. What is means is using windows authentication the “IsInRole” method is checking against windows user groups, the domain not the role claims in the token.

    Therefore when you do something like this.User.IsInRole(“Admin”) it will never find it and return false. In order to return true you need to have a windows user group set on the local computer or domain and the user who is logged in needs to be part of it and call it like this.User.IsInRole(“DOMAIN\Admin”)

    See http://msdn.microsoft.com/en-us/library/system.security.principal.windowsprincipal.isinrole(v=vs.110).aspx for some more information.

  5. macnac permalink
    August 14, 2014 5:27 pm

    ClaimsPrincipal.Current.IsInRole(role) is always returning false. Using ClaimsPrincipal.Current.HasClaim(ClaimTypes.Role, role) instead.

    • August 16, 2014 11:58 am

      The behavior of IsInRole depends on the RoleClaimType passed to the ClaimsPrincipal ctor.

  6. Ehren permalink
    December 15, 2014 2:07 pm

    This is a pretty valuable post to me. It seems quite straightforward, but I am having trouble getting things working properly.

    I modified your code slightly in the Application_PostAuthenticateRequest() to:

    var id = ClaimsPrincipal.Current.Identities.First();
    foreach (var role in roles)
    {
    id.AddClaim(new Claim(ClaimTypes.Role, role));
    }

    My goal, if I have a role “Admin” in roles, I could just decorate a controller class with this: [Authorize(Roles = “Admin”)].

    Am I perhaps misunderstanding the point of this article?

    Thanks for your help!

  7. Mithun Balan permalink
    March 30, 2015 12:54 am

    Do we have to load the roles for the user on each request. I understand Session doesn’t work in this event. Also on next request the roles has to be reloaded. What if we are fetching roles from DB? Each Ajax calls will hav a DB call for Role.

    • April 11, 2015 9:51 am

      Cache the roles in-memory then if you think there are too many look ups in the DB.

  8. June 24, 2015 11:55 am

    Went down this road for a new MVC 5 application, but the MSDN documentation states that “Starting with the .NET Framework 4.5, Windows Identity Foundation (WIF) has been fully integrated into the .NET Framework. The version of WIF addressed by this topic, WIF 3.5, is deprecated and should only be used when developing against the .NET Framework 3.5 SP1 or the .NET Framework 4…”. Is there another way I should be looking at doing this now?

    • June 24, 2015 11:57 am

      never mind, I think I was just looking at Microsoft.IdentityModel.Claims and not System.Security.Claims documentation. Thanks and sorry.

  9. June 25, 2015 2:26 pm

    Hi Brock – Thanks for all your articles on this rather confusing subject, I’ve read several of them. If you have a moment, I hope you can answer my question. I have a situation where my project (intranet app) wants to use Windows authentication, but all the role-based stuff is already in a database and there are about 6,000+ employees. I went ahead and implemented and cached (as the last question suggests) the role information. Problem is User.IsInRole and Authorize were not working. So then I went ahead and created my own Custom AuthorizeAttribute and my own “IsInRole”. I didn’t like that solution because if I want to protect a static resource, I can’t do it just by a web.config entry. So now I have implemented my own RoleProvider instead which seems like it is the “old” way of doing things. I still use and cache claims, but once I added the RoleManager node to web.config this line stopped working:
    var id = ClaimsPrincipal.Current.Identities.First();

    So now I just query the cached data (which is a list of Claims) inside the RoleProvider. It all works just fine, but is this the wrong path and is there a better way to integrate Windows Authentication with custom Roles from the database and still have the Authorize and IsInRole stuff work automatically?

    Thanks for your time!!
    Brian Edwards

  10. June 27, 2015 9:27 am

    You might need to replace the entire ClaimsIdentity and set the name claim type and role claim type on the ctor.

  11. August 27, 2015 10:11 am

    You saved my life with this post; I should spend more time getting to know System.Web.HttpApplication… Thanks!

  12. Paddy McAllister permalink
    September 23, 2015 12:23 pm

    Great Post Brockallen, however like some others here the User.IsInRole(“”) and Authorize Attributes on MVC Controllers e.g. [Authorize(Roles = “Admin”)] don’t appear to be working.

    Is it possible to use Windows Authenication and “Claims Roles” for this?

    • October 1, 2015 5:13 pm

      You’d have to check what the claims are in the user’s claims collection. Also, when the ClaimsIdentity is created that indicates which claim type is consulted for IsInRole checks — you can change this, of course.

    • SomeRandomGuy permalink
      August 26, 2016 8:06 am

      For IsInRole() to work, you can add your custom roles like this:

      identity.AddClaim(new Claim(ClaimTypes.GroupSid, “SomeRoleName”));

      The key here is choosing the correct ClaimType type (i.e. GroupSid)

      • Rob permalink
        September 22, 2016 1:44 pm

        Amazing – thanks. I’ve spent hours trying to find the answer to this. ClaimTypes.GroupSid did the trick for me.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: