Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find the content of a claim from inside an ASP.NET Web API method?

In my code (ASP.NET Identity 2.1) I set claims as follows:

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
        ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }
        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);
        ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
            CookieAuthenticationDefaults.AuthenticationType);
        AuthenticationProperties properties = CreateProperties(
            user.UserName,
            oAuthIdentity,
            user.FirstName,
            user.LastName,
            user.Organization);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(cookiesIdentity);
    }

Here is the CreateProperites method where then claims for roles are added:

    public static AuthenticationProperties CreateProperties(
        string userName,
        ClaimsIdentity oAuthIdentity,
        string firstName,
        string lastName,
        int organization)
    {

        IDictionary<string, string> data = new Dictionary<string, string>
            {
                { "userName", userName},
                { "firstName", firstName},
                { "lastName", lastName},
                { "organization", organization.ToString()},
                { "roles",string.Join(":",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())}

            };
        return new AuthenticationProperties(data);
    }

On my client I issue a request for a token and receive it back like this:

    this.$http({
        method: 'POST',
        url: '/Token',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password),
    })
        .success((data: any, status, headers, cfg) => {
            self.data.roles = data.roles;

I can see that self.data.roles is correctly populated with the roles. Now back on the server I would like to check the contents of the roles claim. Can someone help by telling me how to do this? I know I can do the following in a method:

    [HttpGet]
    [Route("Retrieve")]
    public async Task<IHttpActionResult> Retrieve()
    {

        var x = User;

x gets the value of the

System.Security.Claims.ClaimsPrinciple and 
System.Security.Claims.ClaimsIdentity

but within x I cannot find the information on the claims themselves.

Note that I did try a suggestion posted before on SO:

        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;

        // The following line returns null
        var roles = identity.Claims.Where(r => r.Type == "roles").FirstOrDefault();

But I still cannot inside of claims find the information that I have related to the roles claim. I know it must be there as it gets to the client.

Please note I am looking for the "roles" claim specifically. Not any system generated claim. But the one I tried to add myself that contains an concatenated list of the roles.

like image 686
Samantha J T Star Avatar asked Nov 12 '14 06:11

Samantha J T Star


2 Answers

Did you try this?

var roleClaims = identity.Claims.Where(c => c.Type == ClaimTypes.Role);

UPDATE

First of all, you are not adding a claim. You are adding some data into the properties dictionary of the AuthenticationTicket. This data happens to be comma separated roles and the key you have chosen to name is "roles". So, this is not a claim.

When you say it does not work for me, I believe you want to find the comma separated value you put in the dictionary. If that is the case, you cannot retrieve it from User in controller. When you send a bearer token, the bearer token authentication middleware reads the token, gets the ClaimsIdentity from the token and sets that in the context so that you can read that off User.

Anything you put in the AuthenticationTicket is for the middleware (actually handler) to use. So, if you want to get any data from AuthenticationTicket, you need to call AuthenticateAsync on the bearer middleware yourself. By doing var result = await AuthenticationManager.AuthenticateAsync(OAuthDefaults.AuthenticationType);, you now are getting the entire ticket and not just the ClaimsIdentity. By looking at the result, you should be able to get your comma separated roles but then understand, the bearer middleware has already done that for you once and you are calling it again.

BTW, if you want to add a custom claim, then you need to add it to the oAuthIdentity in GrantResourceOwnerCredentials.

public override async Task GrantResourceOwnerCredentials(
                            OAuthGrantResourceOwnerCredentialsContext context)
{
    // snip
    ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);
    oAuthIdentity.AddClaim(new Claim("urn:roles", "a,b,c");
}

If you do it like this, you can read from User.

var myRoleClaims = identity.Claims.Where(c => c.Type == "urn:roles");

like image 85
Badri Avatar answered Oct 31 '22 15:10

Badri


I think the issue is that you are looking at the wrong authenticationType, User.Identity maps to the cookie and the 'active' authenticationType which is: CookieAuthenticationDefaults.AuthenticationType

To look at the claimsIdentity with your roles, you probably need to call IAuthenticationManager.Authenticate(OAuthDefaults.AuthenticationType) and then I think you will see the roleClaims that you expect.

Edit: added an example

    var result = await AuthenticationManager.AuthenticateAsync(OAuthDefaults.AuthenticationType);
    // do something with result.Identity
like image 25
Hao Kung Avatar answered Oct 31 '22 17:10

Hao Kung