Search code examples
c#.netclaims-based-identityidentityserver3membershipreboot

How do I add UserClaims to ClaimsPrincipal


I've got a C# .NET project setup using Entity Framework, MembershipReboot and IdentityServer3.

I'm looking at the database and I see a UserClaims table. Inside this table I've added a few claims using the MembershipReboot AddClaim method.

The claims from the UserClaims table are somehow added to the ClaimsPrincipal. I can see this when I send a request to my Controller. In the controllers ActionResult method I have the following couple lines of code:

var claimsPrincipal = User as ClaimsPrincipal;
if (claimsPrincipal != null)
{
    var userClaims = claimsPrincipal.Claims;

In this example userClaims will contain the claims from MembershipReboots UserClaims table.

In a similar fashion I'd like to add some additional claims to the ClaimsPrincipal without using the UserClaims table. The idea is that if a user is a member of a group then they will inherit claims which are associated with that group. I've created a separate table that I'm storing these group claims in - but I'm having trouble actually adding these claims to the ClaimsPrincipal.

I've been looking at the SamAuthenticationService in MembershipReboot however I'm not sure if I'm looking in the right place.

Would someone more familiar with MembershipReboot and IdentityServer be able to point me in the right direction?


Solution

  • After doing some more digging I've discovered where the claims are gathered and added to the ClaimsPrincipal within MembershipReboot.

    The ClaimsPrincipal is set within the Sign In method in the AuthenticationService. The SignIn method does the following things before creating the ClaimsPrincipal.

    1. Gathers Claims that MembershipReboot manages (including the claims in the UserClaims table).
    2. Get's custom claims by calling UserAccountService.MapClaims

    The UserAccountService.MapClaims method executes a MapClaimsFromAccount<TAccount> command. It's at this point where you can actually register a handler with MembershipReboot to run a custom claims mapper. Your mapper will be executed and the claims you return will be added to the ClaimsPrincipal.

    It took me a while to find this - but this GitHub Issue helped a lot. I'll copy the code out below.

    Essentially what you do is create a CustomMapper which implements an ICommandHandler<MapClaimsFromAccount<CustomUserAccount>>. Where CustomUserAccount is your own class that extends RelationalUserAccount.

    Custom Claims Mapper

    public class CustomClaimsMapper : ICommandHandler<MapClaimsFromAccount<CustomUserAccount>>
    {
        public void Handle(MapClaimsFromAccount<CustomUserAccount> cmd)
        {
            cmd.MappedClaims = new System.Security.Claims.Claim[]
            {
                new System.Security.Claims.Claim(ClaimTypes.GivenName, cmd.Account.FirstName),
                new System.Security.Claims.Claim(ClaimTypes.Surname, cmd.Account.LastName),
            };
        }
    }
    

    This is the code you would use to map your own custom claims. The claims given above are just example. These claims can be whatever you need for your application.

    Registering the Mapper

    public static MembershipRebootConfiguration<CustomUserAccount> config;
    static MembershipRebootUserServiceFactory()
    {
        config = new MembershipRebootConfiguration<CustomUserAccount>();
    
        //Add a handler for the Custom User Account Type
        config.AddCommandHandler(new CustomClaimsMapper());
    }
    

    This is where you would add a command handler for your custom mapper.

    Now when the ClaimsPrincipal is created it will include any claims you return from your custom mapper.