Get short claim type name
Asked Answered
B

8

12

I am using Asp.Net Core and ASP.NET Identity and when I get a Claim type I get something like

"type":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"value":"123"

How to get only the simple type name, e.g.:

"type":"nameidentifier",
"value":"123"

I know this is possible I just can't find the solution.

Briefing answered 30/3, 2016 at 17:18 Comment(2)
Define "simple type name", please. The one that you receive is a well-known claim type and is supposed to go by that name.Gymnasiarch
Do you know what is solution for this problem for asp.net core?Anonymous
J
20

I was looking for this answer when I came across this documentation:

When you inspect the claims on the about page, you will notice two things: some claims have odd long type names and there are more claims than you probably need in your application.

The long claim names come from Microsoft’s JWT handler trying to map some claim types to .NET’s ClaimTypes class types. You can turn off this behavior with the following line of code (in Startup).

This also means that you need to adjust the configuration for anti-CSRF protection to the new unique sub claim type:

AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

I added this code to the Startup.cs of my client and it shortened the claimtypes.

Update:

For newer versions of IdentityModel, the property is called DefaultInboundClaimTypeMap:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Make sure you run this line before you set up your Identity configuration.

Joappa answered 4/12, 2017 at 10:6 Comment(0)
S
5

If you want to get nameidentifier value, code:

User.FindFirst(ClaimTypes.NameIdentifier).Value
Stooge answered 30/3, 2016 at 19:17 Comment(2)
I think you miss understand me ... What I am looking for is to get the short name of the claim type, so instead of having schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" I would have simply nameindentifier. Not sure if there is a standard way to do this.Briefing
Above solution does what you need.Syncarpous
W
2

Try this

public static class ClaimsPrincipalExtentions
{

    private const string ShortNameProperty = "http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/ShortTypeName";

    public static IEnumerable<Claim> GetClaimsByShortTypeName(this ClaimsPrincipal cp, string name)
    {
        return cp.Claims.Where(x => x.GetShortTypeName() == name);
    }

    public static string GetShortTypeName(this Claim claim)
    {
        string shortName;
        return claim.Properties.TryGetValue(ShortNameProperty, out shortName) ? shortName : claim.Type;
    }

}
Wizen answered 14/6, 2016 at 12:3 Comment(3)
Unsure if i miss understood the question. I was under the impression you where after the "ShortName" correct? ie, "schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" would return "emailaddress" ? Any reason you need the soap namespace? If you are creating your own claim types and not using soap, (ie jwts) you shouldn't use the namespace with out setting the short name as it will bloat your tokens. It was for this reason Microsoft introduced the short name property value.Wizen
1: If you want to find the short name of a in build Microsoft claim, use the code i posted above 2: If you are making your own claims, and don't have a reason for the soap namespace, don't add namespace, your claim will still be valid 3: If you require the soap namespace, you will have to set the "short name" property on the property bag of the the claim. If you are using jwts the tokens should be created using the short name rather then the type stringWizen
Thanks. This solutions helps when you create claims mappingBoutin
S
2

After some research it looks like for security and maybe other reasons Microsoft's libraries incapsulate for as a lot of details that potential user (who is not always a security expert) wouldn't cause himself/herself a harm.

With that said, take this as an example the following straight forward code snippets of

1. issuing an access token
2. reading the claims from it

1. Issuing an access token.

Note that I use here Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames class with it's constants. Eventually it will be converted to "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" standard, doesn't matter if you hardcode "email" or use JwtRegisteredClaimNames.Email as a claim type.

string GenerateJWTAccessToken()
{       
    var claims = new[]
            {
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Sub, userName),
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Email, userEmail),
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Exp, DateTime.UtcNow.AddMinutes(_jwt.AccessTokenLifeTime_Minutes).ToString())                
            };
                
            var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("YOUR_KEY"));
            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: "YOUR_ISSUER",
                audience: "YOUR_AUDIENCE",
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(15),
                signingCredentials: cred
    );
    return new JwtSecurityTokenHandler().WriteToken(token);
}

Shortcut to get what you need. Consider following example with JwtRegisteredClaimNames.Email claim.

2. Reading the claims

Reading previously issued JWT token and getting info from the Payload (the claims).

var principals = new JwtSecurityTokenHandler()
    .ValidateToken
    (
        accessToken, // paste here JWT token
        new TokenValidationParameters
        {
            ValidIssuer = "YOUR_ISSUER",
            ValidAudience = "YOUR_AUDIENCE",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_KEY")),
            ValidateLifetime = false
        }, out _
    );
    
// Here straight forward way to get the value form the claim
var emailClaimValue = principals.Claims.FirstOrDefault(x => x.Properties.FirstOrDefault().Value == "email").Value; // please handle probable exceptions

Done. So we got the value needed.
Please fill free to alter and handle potential exceptions, here I just quickly briefly share my research results, not going to much into details.
If something new I will come up with updates.
Thanks.

Schumer answered 28/6 at 10:24 Comment(0)
P
1

Update with dotnet 8, the JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); is no longer sufficient as (from the statement in the aspnet github repo):

From ASP.NET Core 8, by default the class derived from SecurityToken implenting these properties is JSonWebToken which are produced by more optimized TokenHandlers.

This means that you have to set the JsonWebTokenHandler.DefaultInboundClaimTypeMap.Clear(); to keep the short hand claim names instead of the XML soap scheme URLs.

For further documentation on the issue see: https://github.com/aspnet/Announcements/issues/508

Primalia answered 1/8 at 9:31 Comment(0)
A
0
using System.IdentityModel.Tokens.Jwt;

var claim = new Claim(ClaimTypes.NameIdentifier, "1");
if (JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.TryGetValue(claim.Type, out string type))
{
    var shotrClame = new Claim(type, claim.Value, claim.ValueType, claim.Issuer, claim.OriginalIssuer, claim.Subject);
}

var claim = new Claim("nameid", "1");
if (JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.TryGetValue(claim.Type, out string type))
{
    var longClameType = new Claim(type, claim.Value, claim.ValueType, claim.Issuer, claim.OriginalIssuer, claim.Subject);
}

sourcs: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/d2361e5dcd1abbf6d0ea441cdb2e7404166b122c/src/System.IdentityModel.Tokens.Jwt/ClaimTypeMapping.cs#L61

Aciculate answered 4/1, 2021 at 1:43 Comment(0)
U
0

I wanted to use the short name for logging, so I used this:

var name = JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.FirstOrDefault(x => x.Value == myclaim.Type).Key ?? c.Type;

It might not be exactly what was originally sent in the JWT (ex, "sub" might become "nameid"), but it does provide something more readable than "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier".

Uriah answered 12/5, 2021 at 23:32 Comment(0)
A
-2

System.IO.Path.GetFileName(claim.Type)

Anorak answered 26/4, 2016 at 14:3 Comment(1)
Hi there. While your code snippet might work, it would make your answer much more useful if you were able to explain why and/or how it solves the problem in the question.Azotize

© 2022 - 2024 — McMap. All rights reserved.