Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update User Claim not Taking Effect. Why?

Tags:

I am using ASP.NET MVC 5.1 with Owin and Claims authentication.

After the user changes its email I need to update the users claims, so I tried in the controller:

  ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
  Claim claim = identity.FindFirst(ClaimTypes.Email);
  identity.RemoveClaim(claim);
  identity.AddClaim(new Claim(ClaimTypes.Email, newEmail));

  IOwinContext context = new OwinContext();

  context.Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
  context.Authentication.SignIn(identity);

The Claim is changed but when I refresh the page the email claims is the original again ...

It seems the cookie is not being updated. Any idea what I am doing wrong?

And is it possible to get the value of "IsPersistent" from the identity so when I sign it again I will have the same value?

Thank You,

Miguel

like image 632
Miguel Moura Avatar asked Feb 22 '14 21:02

Miguel Moura


2 Answers

I had this same problem, so just wanted to summarise my findings here. As Chris says, the basis of the answer is indeed here: How to change authentication cookies after changing UserName of current user with asp.net identity but I found that thread a bit hard to follow, and that question isn't really a direct duplicate.

To begin, get the AuthenticationManager from the current OWIN context. Once you have that, you can get the value of "isPersistent" (and other properties from the original SignIn call), by calling the AuthenticateAsync method. Then to update the claims of the current user identity you just need to replace the value of the AuthenticationResponseGrant property like this:

var identity = (ClaimsIdentity)User.Identity;

// Call AddClaim, AddClaims or RemoveClaim on the user identity.

IOwinContext context = Request.GetOwinContext();

var authenticationContext = 
    await context.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);

if (authenticationContext != null)
{
    authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
        identity,
        authenticationContext.Properties);
}

It is the final setting of the AuthenticationResponseGrant property that actually updates the cookie.

Hope this helps other readers.

like image 152
Adrian Edwards Avatar answered Sep 21 '22 13:09

Adrian Edwards


SORRY, this is an ASP.NET CORE solution I also challenged the problem with claims, but the answer was easy to find.

To refresh your cookie, you can rely on the RefreshSignInAsync() function of the SignInManager;

private readonly UserManager<ApplicationUser> _userManager;
    private readonly ApplicationDbContext _context;
    private readonly SignInManager<ApplicationUser> _signInManager;

    public ApiClubController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, ApplicationDbContext context)
    {
        _userManager = userManager;
        _context = context;
        _signInManager = signInManager;
    }

Inside your function:

//GET CURRENT USER
        var usr = await GetCurrentUserAsync();
        //OLD CLAIM
        var myClaims = await _userManager.GetClaimsAsync(usr);
        var oldClaim = myClaims.Where(o => o.Type.Equals("Club")).FirstOrDefault();
        if (oldClaim != null)
        {
            await _userManager.RemoveClaimAsync(usr, oldClaim);
        }

        //CREATE CLUB CLAIM
        var clubClaim = new Claim("Club", "" + id);
        await _userManager.AddClaimAsync(usr, clubClaim);

        //RESET USER COOKIE
        await _signInManager.RefreshSignInAsync(usr);

        //RETURN
        return Ok(company);;

NOTE: I'm using an API here, because I'm mixing up a lot with angular. If you update your identity with your API, you need to refresh your page in order to view things based on your claim

like image 20
Officer Jonez Avatar answered Sep 20 '22 13:09

Officer Jonez