IsInRole return false even if there is role in claims
Asked Answered
D

5

13

I am working on claim base authentication and it is working fine. Now I want to add role autorization. I have role claim for user (eg. "Admin")

When the IsInRole() method is called, there is a check made to see if the current user has that role. In claims-aware applications, the role is expressed by a role claim type that should be available in the token. The role claim type is expressed using the following URI: http://schemas.microsoft.com/ws/2008/06/identity/claims/role

//Include all claims
//claims is List<Claim> with all claims
 var id = new ClaimsIdentity(claims, "Cookies");
 Request.GetOwinContext().Authentication.SignIn(id);

If i check if user is in role I will get false. Although I have Role claim with "Admin" value

User.IsInRole("Admin");

Also authorize attrubute on my api will not work

[Authorize (Roles = "Admin")]

I probably misih logic how to make roles visible to User. Probably is not enough to just have Roles in list of claims?

Drona answered 29/1, 2016 at 9:31 Comment(0)
P
22

If your service is using Windows authentication, then the IPrincipal.Identity you receive will be of type WindowsPrincipal. It's a little misleading, but the ClaimType that WindowsPrincipal.IsInRole() looks for is not ClaimTypes.Role as you might reasonably expect, but ClaimTypes.GroupSid.

However, you should not assume the actual ClaimType that the current Identity uses for specifying roles because different types of identity use different values. Instead you should reference the ClaimsIdentity.RoleClaimType property.

We have implemented a IAuthenticationFilter along the following lines:

public Task AuthenticateAsync(HttpAuthenticationContext context, cancellationToken)
{
    var principal = context.Principal;

    if(principal.Identity is ClaimsIdentity && principal.Identity.IsAuthenticated)
    {
        var ci = (ClaimsIdentity)principal.Identity;
        // get the user's additional roles from somewhere and add Claims
        ci.AddClaim(new Claim(ci.RoleClaimType, "MyRole"));
    }
}

This allows us to use the standard AuthorizeAttribute mechanism in our ASP.Net Controllers. e.g.

[Authorize(Roles="MyRole")]
public IHttpActionResult Get()
{
    //authenticated and authorised code here
}

See ClaimsIdentity.RoleClaimType on MSDN for further clarification.

Please note: adding user-defined roles to the WindowsPrincipal can cause problems. It seems that the current implementation of .Net Framework 4.5 (as of April 2017) will sometimes throw an exception when checking roles, expecting the details of the role to be available from Active Directory. See this question for an alternative approach.

Plight answered 22/9, 2016 at 17:59 Comment(0)
P
4

Probably, the ClaimType of the claim is just "role".

You should create the claim using Microsoft Schema:

manager.AddClaim(dn1.Id, claim: new Claim(ClaimTypes.Role.ToString(), "ADMINISTRATOR"));

Then User.IsInRole("Admin"); and [Authorize (Roles = "Admin")]will work properly.

This because Microsoft Identity uses the schema:

http://schemas.microsoft.com/ws/2008/06/identity/claims/role

When for role checking. I suggest you to check ASPNETIdentity database to have a complete view of how che claim are inserted. I'm pretty sure that the ClaimType of AspNetUserClaims is not like the Microsoft Schema.

Regards

Phiz answered 20/4, 2016 at 14:24 Comment(3)
Is the user Id @PhilipStratfordPhiz
Thank you a million @DarioN1, I would like to believe this is in fact the correct answer.Tract
In fact, I needed this: identity.AddClaim(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Role, userRole));Tract
A
2

TL;DR Case Sensitivity, Perhaps?

I found that the check used by default in...

  [Authorize(Roles = "RoleA,RoleB")] 

...was case sensitive.

I created roles in mixed case, and used AspNetCore's Identity manager, with an non-EF memory implementation for testing.
UserManager.IsInRole("RoleA") returned true, but when checked via the ClaimsPrincipal, HttpContext.User.IsInRole("RoleA") returned false. I dumped the claims out to text and could see that there were role claims for the correct MS schema...

    ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEA], Issuer:[TokenServer]
    ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEB], Issuer:[TokenServer]

...but the claim value (the role) was upper case.
To fix the problem, I just had to change the attribute to...

[Authorize(Roles = "ROLEA,ROLEB")]

... and it worked.

So, if you are having a problem getting roles authorization to work in AspNetCore, try to read the claims, and match the claims exactly. You can read the claims by accessing the HttpContext.User.Claims object...

        foreach (var claim in HttpContext.User.Claims)            
            Console.WriteLine($"ClaimType:[{claim.Type}], ClaimValue:[{claim.Value}], Issuer:[{claim.Issuer}]");

It could of course be that I somehow donkey-coded the roles to upper case, or somewhere used the NormalisedRole, but you might have done the same thing...

Altamirano answered 21/7, 2017 at 14:14 Comment(0)
G
2

Note that HttpContext.User.Identity.RoleClaimType: "role"

may be different to ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"

So when generating the claims identity you may need to add claims using "role" as the key instead of the ClaimTypes constants. ClaimsIdentity.IsInRole(String) uses the claim key as defined by ClaimsIdentity.RoleClaimType.

My factory code looks like this ...

            var identity = await base.GenerateClaimsAsync(user);
            var roles = await UserManager.GetRolesAsync(user);
            foreach (var role in roles)
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, role));
                identity.AddClaim(new Claim("role", role));
            }

            return identity;

The first add is really superfluous, but makes me feel like I am actually adding the right claim.

Galangal answered 15/7, 2020 at 9:55 Comment(1)
I'm using Identityserver and .net core. Using the string "Role" instead of ClaimTypes.Role worked for me +1Almund
N
0

You did not mention which Authentication approach you are using, but if you are using JWT Authentication, then you need to add the roles to the ClaimsIdentity when generating the token, as detailed in this post: ASP.NET Core JWT mapping role claims to ClaimsIdentity

Neese answered 20/12, 2019 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.