How do I remove an existing claim from a ClaimsPrinciple?

32,354

Solution 1

You should use identity to add or remove a claim. Try this to add a claim.

var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
identity.AddClaim(new Claim(ClaimTypes.Role, "somenewrole"));

To remove a claim,

var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
var claim = (from c in user.Claims
                         where c.Value == "somenewrole"
                         select c).Single();
identity.RemoveClaim(claim);

BTW, it is better to use User from your controller instead of HttpContext.Current.User.

Solution 2

Something else that is important to add is to make sure you do not try to iterate over the collection of claims and remove items. I just stumbled upon buggy code written by someone else, and at first I didn't see the problem until I stepped through it.

The buggy code was:

        foreach (var claim in identity.Claims)
        {
            var name = claim.Type;
            if (!name.Equals("UserAccountId") && !name.Equals("Email") && !name.Equals("TenantIds"))
            {
                identity.RemoveClaim(claim);
            }
        }

The result was that claims were inconsistently removed from the list. The simple solution to the problem is to iterate over a list of claims and not the claims themselves, and remove them that way:

        var claimNameList = identity.Claims.Select(x => x.Type).ToList();

        foreach (var name in claimNameList)
        {
            if (!name.Equals("UserAccountId") && !name.Equals("Email") && !name.Equals("TenantIds"))
            {
                var claim = identity.Claims.FirstOrDefault(x => x.Type == name);
                if (claim != null)
                    identity.RemoveClaim(claim);
            }
        }

It's never a good idea to iterate over a collection and add or remove items. You will see sporadic errors and different results depending on the situation, and in some circumstances, such as iterating over items in HttpContext.Current.Items, you will see sporadic errors about the collection being modified.

Share:
32,354
Greg Mason
Author by

Greg Mason

Software validation engineering background with lots of experience with windows networking, storage area networks (SAN), iSCSI, and automation of testing environments. Recent experience is trending towards software development using C#, Powershell, WMI, network performance, and Windows domain security. Offline I enjoy a heading a medium sized home-brewing club that produces beer, mead, wine, and cider and puts on tastings and contests for learning purposes with our members. Also conspiring with a few other small clubs in the area for brewing learning.

Updated on November 09, 2020

Comments

  • Greg Mason
    Greg Mason over 3 years

    I am making a developer tool for impersonating Roles for an intranet site to allow developers to quickly act as any Role as needed. Roles defined are Developer, Team Lead, Team Member, Engineering, Marketing, Guest and a tool on the web page makes a call to a Web Api to add or remove the Claim... well I can add but can't seem to find out where the .RemoveClaim(claim) or .TryRemoveClaim(claim) can be accessed to get this working. Do I have to create a custom claims manager to get this functionality or am I missing something?

    I have been looking at System.Security.Claims and almost everything else seems to work very straightforward and there is no reference as to needing extensive work to do what I need.

    I am using VS 2013/Web Api2 with .NET 4.5.1.

    The website side just uses a simple ajax call to PUT and DELETE functionality till I get this to work the way I want. From the Controller, my cs code is as:

        public void Put(int id, [FromBody]string role)
        {
            if (FindClaim(role) != null) return;
    
            var user = HttpContext.Current.User as ClaimsPrincipal;
            if (user == null) return;
    
            var claimId = new ClaimsIdentity();
            claimId.AddClaim(new Claim(ClaimTypes.Role, role));
            user.AddIdentity(claimId);
        }
    
        // DELETE api/devroleadjuster/5
        public void Delete(int id, [FromBody]string role)
        {
            var claim = FindClaim(role);
            if (claim == null) return;
    
            var user = HttpContext.Current.User as ClaimsPrincipal;
            if (user == null)  return;
    
            // Why can't I do this????
            user.RemoveClaim(claim);
        }
    
        private Claim FindClaim(string role)
        {
            try
            {
                var user = HttpContext.Current.User as ClaimsPrincipal;
                var claim = (from c in user.Claims
                             where c.Value == role
                             select c).Single();
                return claim;
            }
            catch (InvalidOperationException)
            {
                return null;
            }
        }
    

    The Put works just fine, the problem is with the Delete portion of my code... I want to use the user.RemoveClaim(claim); code or something like it... I can't see why I can't according to MSDN, and I can't find any example code for removing a claim.