Search code examples
c#asp.net-coreasp.net-core-3.1claims

What does `ClaimsPrincipal.IsInRole` expect in the claim?


I have a claim called groups. When I setup my TokenValidationParameters I set RoleClaimType to be groups.

When the claims come through, the groups claim has a value like this:

"something,some other thing,more things,other other things"

But when I call:

User.IsInRole("some other thing");

The result is False.

What does IsInRole expect in that claim?

Meaning does it want semicolon separation, comma separation (that does not seem to be working), space delimited, or a single value (not sure how it could be an "in" check if it is a single value.)


Solution

  • IsInRole wants the claim to contain the value you are looking for. This is why it won't work in your case. What you can do is make a claims transformation like this:

    public class AzureAdGroupsSplitClaimTransformation : IClaimsTransformation
    {
        public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            var identities = principal.Identities;
            if (identities == null)
            {
                return Task.FromResult(principal);
            }
    
            var result = new List<ClaimsIdentity>();
            var groupsClaimSplit = false;
    
            // Iterate each identity the user may have, make sure to keep all of them
            foreach (var identity in identities)
            {
                var groupClaims = identity.FindAll("groups").ToList();
                if (groupClaims.Count != 1 || !groupClaims[0].Value.Contains(','))
                {
                    // groupClaims.Count == 0: Identity does not have groups
                    // groupClaims.Count > 1: Identity has more than one groups claim, already split
                    // The only groups claim does not contain a comma: Identity has one group, no need to split
                    result.Add(identity);
                    continue;
                }
    
                var claim = groupClaims[0];
                var groups = claim.Value.Split(',', StringSplitOptions.RemoveEmptyEntries);
                var claims = groups.Select(s => new Claim("groups", s));
                var updatedIdentity = new ClaimsIdentity(identity, claims);
                result.Add(updatedIdentity);
    
                groupsClaimSplit = true;
            }
    
            // Nothing was done to the original identities, may as well just return the original principal
            if (!groupsClaimSplit)
            {
                return Task.FromResult(principal);
            }
    
            return Task.FromResult(new ClaimsPrincipal(result));
        }
    }
    

    And then register it in the service collection:

    services.AddSingleton<IClaimsTransformation, AzureAdGroupsSplitClaimTransformation>();
    

    Now you should get additional group claims for the user with only a single value. Your role check should then work. Though it is a bit odd to use IsInRole for this purpose, you could also use User.HasClaim("groups", "your-group-id").