10

From brockallen's article, He says that the "AuthenticateAsync() might be invoked multiple times" which could be the reason why the TransformAsync() is being called more than once (twice on my app).

What I don't get is:

  1. When I construct ClaimsIdentity WITH parameters, the duplication only happens on added claims ('now' and 'boom'). [See Code 1, Image 1-A and Image 1-B below]
  2. When I construct ClaimsIdentity WITHOUT parameters, the added claims ('now' and 'boom') does not duplicate. [See Code 2, Image 2-A and Image 2-B below]
  3. How come the added claims (now and boom) are duplicated WHILE the other/pre-defined claims (nbf, exp, iss, aud, etc...) are not? [Compare Image 1-A and Image 1-B below]

Does anybody know why the ClaimsIdentity behaves this way?


UPDATED QUESTION:

What I don't get is:

  1. When I construct ClaimsIdentity WITH parameters, the duplication only happens on added claims ('now' and 'boom'). [See Code 1, Image 1-A and Image 1-B below]
    (Answered)
  2. When I construct ClaimsIdentity WITHOUT parameters, the added claims ('now' and 'boom') does not duplicate. [See Code 2, Image 2-A and Image 2-B below]
    (Answered)
  3. How come the added claims (now and boom) are duplicated WHILE the other/pre-defined claims (nbf, exp, iss, aud, etc...) are not? [Compare Image 1-A and Image 1-B below]
    (Not Answered, but alternative code is posted below)

Code 1

class ClaimsTransformer : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var id = ((ClaimsIdentity)principal.Identity);
        var ci = new ClaimsIdentity(id.Claims, id.AuthenticationType, id.NameClaimType, id.RoleClaimType);

        ci.AddClaim(new Claim("now", DateTime.Now.ToString()));
        ci.AddClaim(new Claim("boom", "hehehe"));

        var cp = new ClaimsPrincipal(ci);

        return Task.FromResult(cp);
    }
}

Image 1-A

enter image description here

Image 1-B

enter image description here


Code 2

class ClaimsTransformer : IClaimsTransformation
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var ci = new ClaimsIdentity();

        ci.AddClaim(new Claim("now", DateTime.Now.ToString()));
        ci.AddClaim(new Claim("boom", "hehehe"));

        var cp = new ClaimsPrincipal(ci);

        return Task.FromResult(cp);
    }
}

Image 2-A

enter image description here

Image 2-B

enter image description here

gulp
  • 421
  • 3
  • 12
  • Check the pricinpal parameter and the register services of DI. The claims was register as the in scope with DI will be some object in current http request. – ocrenaka Aug 08 '18 at 06:16

2 Answers2

3

Answering Question 1:
I realized that duplication happens because i am copying the values from the principal and returns back with the added custom claims.

Answering Question 2:
I realized that duplication NEVER happens because i am always creating a new ClaimsIdentity and never copies the values from the principal.

gulp
  • 421
  • 3
  • 12
  • Answering Question 3: when creating a new identity all claims are copied automatically from the source. Only the claims 'now' and 'boom' are added again. Those will occur twice, because they were already in it when copied from the source identity. – Chaim Zonnenberg Aug 09 '18 at 19:14
  • What about the other claims (nbf, exp, iss...)? they were already in it but they were not duplicated. – gulp Aug 10 '18 at 04:51
  • 1
    The second time it passes your code (Code 1), the claims 'now' and 'boom' are already in id.Claims. Then you add them again, so they are duplicated. The other ones are not duplicated because you don't explicitly add them. Try adding the line ci.AddClaim(new Claim("nbf", "1234")); Then nbf will be duplicated as well :-) – Chaim Zonnenberg Aug 10 '18 at 07:35
  • 1
    Thanks for the example @ChaimZonnenberg. =) May be this is a bug (or not) for Claims Transformation. I believe this is related to the question from brockallen's issue posted in https://github.com/aspnet/Security/issues/1399. – gulp Aug 11 '18 at 01:38
2

I resolved the duplicate custom claims issue by adding a transformation checking in the ClaimsTransformer class and registering it in the DI as AddScoped() instead of AddSingleton().

ClaimsTransformer.cs

class ClaimsTransformer : IClaimsTransformation
{
    private bool isTransformed = false;

    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        if (!isTransformed)
        {
            var id = ((ClaimsIdentity)principal.Identity).Clone();
            var ci = new ClaimsIdentity(id);

            // add custom claims here
            // e.g. ci.AddClaim(new Claim("boom", "hehehe"));

            isTransformed = true;

            var cp = new ClaimsPrincipal(ci);
            return Task.FromResult(cp);
        }

        return Task.FromResult(principal);
    }
}

Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // other ConfigureServices() codes here

        services.AddScoped<IClaimsTransformation, ClaimsTransformer>();

        // other ConfigureServices() codes here
    }

    // Other Startup codes here
}
gulp
  • 421
  • 3
  • 12