Skip to content

Commit

Permalink
Correctly handle claims of same type with multiple values (#2248)
Browse files Browse the repository at this point in the history
* Handle claims with multiple values

* refactor

---------

Co-authored-by: Keegan Caruso <[email protected]>
  • Loading branch information
2 people authored and brentschmaltz committed Sep 7, 2023
1 parent 17469d7 commit 0e80d29
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/Microsoft.IdentityModel.Tokens/TokenUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,17 @@ internal static IDictionary<string, object> CreateDictionaryFromClaims(
// When the creating the JWT and a list is found, a JsonArray will be created.
if (payload.TryGetValue(claim.Type, out object existingValue))
{
if (existingValue is not IList<object>)
if (existingValue is IList<object> existingList)
{
existingList.Add(jsonClaimValue);
}
else
{
payload[claim.Type] = new List<object>
{
existingValue,
jsonClaimValue
};
};
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,40 @@ namespace Microsoft.IdentityModel.JsonWebTokens.Tests
{
public class JsonWebTokenHandlerTests
{
[Fact]
public void JsonWebTokenHandler_CreateToken_SameTypeMultipleValues()
{
var identity = new ClaimsIdentity("Test");

var claimValues = new List<string> { "value1", "value2", "value3", "value4" };

foreach (var value in claimValues)
identity.AddClaim(new Claim("a", value));

var descriptor = new SecurityTokenDescriptor
{
SigningCredentials = new SigningCredentials(Default.AsymmetricSigningKey, SecurityAlgorithms.RsaSsaPssSha256),
Subject = identity
};

var handler = new JsonWebTokenHandler();

var token = handler.CreateToken(descriptor);

var jwt = new JsonWebToken(token);
var claims = jwt.Claims.ToList();

int defaultClaimsCount = 3;

Assert.Equal(defaultClaimsCount + claimValues.Count, claims.Count);

var aTypeClaims = claims.Where(c => c.Type == "a").ToList();

Assert.Equal(4, aTypeClaims.Count);

foreach (var value in claimValues)
Assert.NotNull(aTypeClaims.SingleOrDefault(c => c.Value == value));
}

// This test checks to make sure that the value of JsonWebTokenHandler.Base64UrlEncodedUnsignedJWSHeader has remained unchanged.
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,40 @@ namespace System.IdentityModel.Tokens.Jwt.Tests
public class JwtSecurityTokenHandlerTests
{

[Fact]
public void JwtSecurityTokenHandler_CreateToken_SameTypeMultipleValues()
{
var identity = new ClaimsIdentity("Test");

var claimValues = new List<string> { "value1", "value2", "value3", "value4" };

foreach (var value in claimValues)
identity.AddClaim(new Claim("a", value));

var descriptor = new SecurityTokenDescriptor
{
SigningCredentials = new SigningCredentials(Default.AsymmetricSigningKey, SecurityAlgorithms.RsaSsaPssSha256),
Subject = identity
};

var handler = new JwtSecurityTokenHandler();

var jwt = (JwtSecurityToken)handler.CreateToken(descriptor);

var claims = jwt.Claims.ToList();

int defaultClaimsCount = 3;

Assert.Equal(defaultClaimsCount + claimValues.Count, claims.Count);

var aTypeClaims = claims.Where(c => c.Type == "a").ToList();

Assert.Equal(4, aTypeClaims.Count);

foreach (var value in claimValues)
Assert.NotNull(aTypeClaims.SingleOrDefault(c => c.Value == value));
}

[Theory, MemberData(nameof(CreateJWEWithPayloadStringTheoryData))]
public void CreateJWEWithAdditionalHeaderClaims(CreateTokenTheoryData theoryData)
{
Expand Down

0 comments on commit 0e80d29

Please sign in to comment.