diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs index e0b9eccdd4..d25425c1e2 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs @@ -212,7 +212,7 @@ private ClaimsIdentity CreateClaimsIdentityWithMapping(JsonWebToken jwtToken, To { _ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters)); - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, issuer); foreach (Claim jwtClaim in jwtToken.Claims) { bool wasMapped = _inboundClaimTypeMap.TryGetValue(jwtClaim.Type, out string claimType); @@ -281,7 +281,7 @@ private ClaimsIdentity CreateClaimsIdentityPrivate(JsonWebToken jwtToken, TokenV { _ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters)); - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, issuer); foreach (Claim jwtClaim in jwtToken.Claims) { string claimType = jwtClaim.Type; diff --git a/src/Microsoft.IdentityModel.TestExtensions/TestTokenCreator.cs b/src/Microsoft.IdentityModel.TestExtensions/TestTokenCreator.cs index ace57502c4..5b0db81a15 100644 --- a/src/Microsoft.IdentityModel.TestExtensions/TestTokenCreator.cs +++ b/src/Microsoft.IdentityModel.TestExtensions/TestTokenCreator.cs @@ -357,7 +357,7 @@ public SecurityTokenDescriptor CreateTokenDescriptorWithInstanceOverrides() { var securityTokenDescriptor = new SecurityTokenDescriptor() { - Subject = new ClaimsIdentity(_payloadClaims), + Subject = ClaimsIdentityFactory.Create(_payloadClaims), }; if (!string.IsNullOrEmpty(Issuer)) diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.cs index d75cbdbd59..bda9d53b0f 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.cs @@ -677,7 +677,7 @@ protected virtual IEnumerable ProcessStatements(SamlSecurityToke if (!identityDict.TryGetValue(statement.Subject, out ClaimsIdentity identity)) { - identity = validationParameters.CreateClaimsIdentity(samlToken, issuer); + identity = ClaimsIdentityFactory.Create(samlToken, validationParameters, issuer); ProcessSubject(statement.Subject, identity, issuer); identityDict.Add(statement.Subject, identity); } @@ -898,7 +898,7 @@ protected virtual void SetDelegateFromAttribute(SamlAttribute attribute, ClaimsI } } - subject.Actor = new ClaimsIdentity(claims, "Federation"); + subject.Actor = ClaimsIdentityFactory.Create(claims, "Federation"); SetDelegateFromAttribute(actingAsAttribute, subject.Actor, issuer); } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.cs index 90773b37c1..ec1206f198 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.cs @@ -1129,7 +1129,7 @@ protected virtual void SetClaimsIdentityActorFromAttribute(Saml2Attribute attrib } } - identity.Actor = new ClaimsIdentity(claims); + identity.Actor = ClaimsIdentityFactory.Create(claims); SetClaimsIdentityActorFromAttribute(actorAttribute, identity.Actor, issuer); } @@ -1314,7 +1314,8 @@ protected virtual ClaimsIdentity CreateClaimsIdentity(Saml2SecurityToken samlTok actualIssuer = ClaimsIdentity.DefaultIssuer; } - var identity = validationParameters.CreateClaimsIdentity(samlToken, actualIssuer); + var identity = ClaimsIdentityFactory.Create(samlToken, validationParameters, issuer); + ProcessSubject(samlToken.Assertion.Subject, identity, actualIssuer); ProcessStatements(samlToken.Assertion.Statements, identity, actualIssuer); diff --git a/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs new file mode 100644 index 0000000000..9c0dd1deb7 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Security.Claims; + +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// AppContext switches for Microsoft.IdentityModel.Tokens and referencing packages. + /// + internal static class AppContextSwitches + { + /// + /// Enables a fallback to the previous behavior of using instead of globally. + /// + internal const string UseClaimsIdentityTypeSwitch = "Microsoft.IdentityModel.Tokens.UseClaimsIdentityType"; + + internal static bool UseClaimsIdentityType() => (AppContext.TryGetSwitch(UseClaimsIdentityTypeSwitch, out bool useClaimsIdentityType) && useClaimsIdentityType); + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/CaseSensitiveClaimsIdentity.cs b/src/Microsoft.IdentityModel.Tokens/CaseSensitiveClaimsIdentity.cs new file mode 100644 index 0000000000..1c48b36a2c --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/CaseSensitiveClaimsIdentity.cs @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Security.Claims; + +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// A derived where claim retrieval is case-sensitive. The current retrieves claims in a case-insensitive manner which is different than querying the underlying . The provides consistent retrieval logic between the and . + /// + public class CaseSensitiveClaimsIdentity : ClaimsIdentity + { + /// + /// Gets the associated with this claims identity. + /// + public SecurityToken SecurityToken { get; internal set; } + + /// + /// Initializes an instance of . + /// + public CaseSensitiveClaimsIdentity() : base() + { + } + + /// + /// Initializes an instance of . + /// + /// The authentication method used to establish this identity. + public CaseSensitiveClaimsIdentity(string authenticationType) : base(authenticationType) + { + } + + /// + /// Initializes an instance of . + /// + /// to copy. + public CaseSensitiveClaimsIdentity(ClaimsIdentity claimsIdentity) : base(claimsIdentity) + { + } + + /// + /// Initializes an instance of . + /// + /// associated with this instance. + public CaseSensitiveClaimsIdentity(IEnumerable claims) : base(claims) + { + } + + /// + /// Initializes an instance of . + /// + /// associated with this instance. + /// The authentication method used to establish this identity. + public CaseSensitiveClaimsIdentity(IEnumerable claims, string authenticationType) : base(claims, authenticationType) + { + } + + /// + /// Initializes an instance of . + /// + /// associated with this instance. + /// The authentication method used to establish this identity. + /// The used when obtaining the value of . + /// The used when performing logic for . + public CaseSensitiveClaimsIdentity(IEnumerable claims, string authenticationType, string nameType, string roleType) : + base(claims, authenticationType, nameType, roleType) + { + } + + /// + /// Initializes an instance of . + /// + /// The authentication method used to establish this identity. + /// The used when obtaining the value of . + /// The used when performing logic for . + public CaseSensitiveClaimsIdentity(string authenticationType, string nameType, string roleType) : + base(authenticationType, nameType, roleType) + { + } + + /// + /// Retrieves a where each equals . + /// + /// The type of the claim to match. + /// A of matched claims. + /// Comparison is . + /// if is null. + public override IEnumerable FindAll(string type) + { + return base.FindAll(claim => claim?.Type.Equals(type, StringComparison.Ordinal) == true); + } + + /// + /// Retrieves the first where equals . + /// + /// The type of the claim to match. + /// A , if nothing matches. + /// Comparison is . + /// if is null. + public override Claim FindFirst(string type) + { + return base.FindFirst(claim => claim?.Type.Equals(type, StringComparison.Ordinal) == true); + } + + /// + /// Determines if a claim with type AND value is contained within this claims identity. + /// + /// The type of the claim to match. + /// The value of the claim to match. + /// true if a claim is matched, false otherwise. + /// Comparison is for and . + /// if is null. + /// if is null. + public override bool HasClaim(string type, string value) + { + return base.HasClaim(claim => claim?.Type.Equals(type, StringComparison.Ordinal) == true + && claim?.Value.Equals(value, StringComparison.Ordinal) == true); + } + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/ClaimsIdentityFactory.cs b/src/Microsoft.IdentityModel.Tokens/ClaimsIdentityFactory.cs new file mode 100644 index 0000000000..e4ded9889b --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/ClaimsIdentityFactory.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Security.Claims; + +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Facilitates the creation of and instances based on the . + /// + internal static class ClaimsIdentityFactory + { + internal static ClaimsIdentity Create(IEnumerable claims) + { + if (AppContextSwitches.UseClaimsIdentityType()) + return new ClaimsIdentity(claims); + + return new CaseSensitiveClaimsIdentity(claims); + } + + internal static ClaimsIdentity Create(IEnumerable claims, string authenticationType) + { + if (AppContextSwitches.UseClaimsIdentityType()) + return new ClaimsIdentity(claims, authenticationType); + + return new CaseSensitiveClaimsIdentity(claims, authenticationType); + } + + internal static ClaimsIdentity Create(string authenticationType, string nameType, string roleType, SecurityToken securityToken) + { + if (AppContextSwitches.UseClaimsIdentityType()) + return new ClaimsIdentity(authenticationType: authenticationType, nameType: nameType, roleType: roleType); + + return new CaseSensitiveClaimsIdentity(authenticationType: authenticationType, nameType: nameType, roleType: roleType) + { + SecurityToken = securityToken, + }; + } + + internal static ClaimsIdentity Create(SecurityToken securityToken, TokenValidationParameters validationParameters, string issuer) + { + ClaimsIdentity claimsIdentity = validationParameters.CreateClaimsIdentity(securityToken, issuer); + + // Set the SecurityToken in cases where derived TokenValidationParameters created a CaseSensitiveClaimsIdentity. + if (claimsIdentity is CaseSensitiveClaimsIdentity caseSensitiveClaimsIdentity && caseSensitiveClaimsIdentity.SecurityToken == null) + { + caseSensitiveClaimsIdentity.SecurityToken = securityToken; + } + else if (claimsIdentity is not CaseSensitiveClaimsIdentity && !AppContextSwitches.UseClaimsIdentityType()) + { + claimsIdentity = new CaseSensitiveClaimsIdentity(claimsIdentity) + { + SecurityToken = securityToken, + }; + } + + return claimsIdentity; + } + + internal static ClaimsIdentity Create(TokenHandler tokenHandler, SecurityToken securityToken, TokenValidationParameters validationParameters, string issuer) + { + ClaimsIdentity claimsIdentity = tokenHandler.CreateClaimsIdentityInternal(securityToken, validationParameters, issuer); + + // Set the SecurityToken in cases where derived TokenHandler created a CaseSensitiveClaimsIdentity. + if (claimsIdentity is CaseSensitiveClaimsIdentity caseSensitiveClaimsIdentity && caseSensitiveClaimsIdentity.SecurityToken == null) + { + caseSensitiveClaimsIdentity.SecurityToken = securityToken; + } + else if (claimsIdentity is not CaseSensitiveClaimsIdentity && !AppContextSwitches.UseClaimsIdentityType()) + { + claimsIdentity = new CaseSensitiveClaimsIdentity(claimsIdentity) + { + SecurityToken = securityToken, + }; + } + + return claimsIdentity; + } + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs b/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs index 6bfadcd465..c9fc108317 100644 --- a/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs +++ b/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs @@ -30,8 +30,8 @@ public abstract class TokenHandler /// 'value' less than 1. public virtual int MaximumTokenSizeInBytes { - get => _maximumTokenSizeInBytes; - set => _maximumTokenSizeInBytes = (value < 1) ? throw LogExceptionMessage(new ArgumentOutOfRangeException(nameof(value), FormatInvariant(LogMessages.IDX10101, MarkAsNonPII(value)))) : value; + get => _maximumTokenSizeInBytes; + set => _maximumTokenSizeInBytes = (value < 1) ? throw LogExceptionMessage(new ArgumentOutOfRangeException(nameof(value), FormatInvariant(LogMessages.IDX10101, MarkAsNonPII(value)))) : value; } /// @@ -53,7 +53,6 @@ public int TokenLifetimeInMinutes } #region methods - /// /// Validates a token. /// On a validation failure, no exception will be thrown; instead, the exception will be set in the returned TokenValidationResult.Exception property. diff --git a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs index 2112772699..e0a9232b91 100644 --- a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs +++ b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs @@ -240,7 +240,7 @@ public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken, if (LogHelper.IsEnabled(EventLogLevel.Informational)) LogHelper.LogInformation(LogMessages.IDX10245, securityToken); - return new ClaimsIdentity(authenticationType: AuthenticationType ?? DefaultAuthenticationType, nameType: nameClaimType ?? ClaimsIdentity.DefaultNameClaimType, roleType: roleClaimType ?? ClaimsIdentity.DefaultRoleClaimType); + return ClaimsIdentityFactory.Create(authenticationType: AuthenticationType ?? DefaultAuthenticationType, nameType: nameClaimType ?? ClaimsIdentity.DefaultNameClaimType, roleType: roleClaimType ?? ClaimsIdentity.DefaultRoleClaimType, securityToken); } /// diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/TokenValidationResult.cs b/src/Microsoft.IdentityModel.Tokens/Validation/TokenValidationResult.cs index 46c90738e0..505c750f63 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/TokenValidationResult.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/TokenValidationResult.cs @@ -135,7 +135,7 @@ internal ClaimsIdentity ClaimsIdentityNoLocking if (_validationParameters != null && SecurityToken != null && _tokenHandler != null && Issuer != null) { - _claimsIdentity = _tokenHandler.CreateClaimsIdentityInternal(SecurityToken, _validationParameters, Issuer); + _claimsIdentity = ClaimsIdentityFactory.Create(_tokenHandler, SecurityToken, _validationParameters, Issuer); } _claimsIdentityInitialized = true; diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs index 302ee7c460..34fec6ced4 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs @@ -1527,7 +1527,7 @@ protected virtual ClaimsIdentity CreateClaimsIdentity(JwtSecurityToken jwtToken, private ClaimsIdentity CreateClaimsIdentityWithMapping(JwtSecurityToken jwtToken, string actualIssuer, TokenValidationParameters validationParameters) { - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, actualIssuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, actualIssuer); foreach (Claim jwtClaim in jwtToken.Claims) { if (_inboundClaimFilter.Contains(jwtClaim.Type)) @@ -1573,7 +1573,7 @@ private ClaimsIdentity CreateClaimsIdentityWithMapping(JwtSecurityToken jwtToken private ClaimsIdentity CreateClaimsIdentityWithoutMapping(JwtSecurityToken jwtToken, string actualIssuer, TokenValidationParameters validationParameters) { - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, actualIssuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, actualIssuer); foreach (Claim jwtClaim in jwtToken.Claims) { if (_inboundClaimFilter.Contains(jwtClaim.Type)) diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerClaimsIdentityTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerClaimsIdentityTests.cs new file mode 100644 index 0000000000..43cd4e5f91 --- /dev/null +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerClaimsIdentityTests.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Security.Claims; +using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; +using Xunit; + +namespace Microsoft.IdentityModel.JsonWebTokens.Tests +{ + [Collection(nameof(JsonWebTokenHandlerClaimsIdentityTests))] + public class JsonWebTokenHandlerClaimsIdentityTests + { + [Fact] + public void CreateClaimsIdentity_ReturnsCaseSensitveClaimsIdentity_ByDefault() + { + var handler = new DerivedJsonWebTokenHandler(); + var jsonWebToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())); + var tokenValidationParameters = new TokenValidationParameters(); + + var actualClaimsIdentity = handler.CreateClaimsIdentity(jsonWebToken, tokenValidationParameters); + Assert.IsType(actualClaimsIdentity); + Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + + actualClaimsIdentity = handler.CreateClaimsIdentity(jsonWebToken, tokenValidationParameters, Default.Issuer); + Assert.IsType(actualClaimsIdentity); + Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + + actualClaimsIdentity = handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer); + Assert.IsType(actualClaimsIdentity); + Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + + // This will also test mapped claims flow. + handler.MapInboundClaims = true; + actualClaimsIdentity = handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer); + Assert.IsType(actualClaimsIdentity); + Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + } + + [Fact] + public void CreateClaimsIdentity_ReturnsClaimsIdentity_WithAppContextSwitch() + { + AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, true); + + var handler = new DerivedJsonWebTokenHandler(); + var jsonWebToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())); + var tokenValidationParameters = new TokenValidationParameters(); + + Assert.IsType(handler.CreateClaimsIdentity(jsonWebToken, tokenValidationParameters)); + Assert.IsType(handler.CreateClaimsIdentity(jsonWebToken, tokenValidationParameters, Default.Issuer)); + Assert.IsType(handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer)); + // This will also test mapped claims flow. + handler.MapInboundClaims = true; + Assert.IsType(handler.CreateClaimsIdentityInternal(jsonWebToken, tokenValidationParameters, Default.Issuer)); + + AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, false); + } + + private class DerivedJsonWebTokenHandler : JsonWebTokenHandler + { + public new ClaimsIdentity CreateClaimsIdentity(JsonWebToken jwtToken, TokenValidationParameters validationParameters) => base.CreateClaimsIdentity(jwtToken, validationParameters); + public new ClaimsIdentity CreateClaimsIdentity(JsonWebToken jwtToken, TokenValidationParameters validationParameters, string issuer) => base.CreateClaimsIdentity(jwtToken, validationParameters, issuer); + public new ClaimsIdentity CreateClaimsIdentityInternal(SecurityToken securityToken, TokenValidationParameters tokenValidationParameters, string issuer) => base.CreateClaimsIdentityInternal(securityToken, tokenValidationParameters, issuer); + } + } +} diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs index 7e88894509..b443838c35 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs @@ -30,7 +30,7 @@ public class JsonWebTokenHandlerTests [Fact] public void JsonWebTokenHandler_CreateToken_SameTypeMultipleValues() { - var identity = new ClaimsIdentity("Test"); + var identity = new CaseSensitiveClaimsIdentity("Test"); var claimValues = new List { "value1", "value2", "value3", "value4" }; @@ -118,7 +118,7 @@ public static TheoryData TokenValidationClaimsTheoryData var tokenHandler = new JsonWebTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, }; @@ -142,7 +142,7 @@ public static TheoryData TokenValidationClaimsTheoryData tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadAllShortClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadAllShortClaims), SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, }; accessToken = tokenHandler.CreateToken(tokenDescriptor); @@ -223,7 +223,7 @@ public static TheoryData TokenValidationTheoryData() var tokenHandler = new JsonWebTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, }; var accessToken = tokenHandler.CreateToken(tokenDescriptor); @@ -486,7 +486,7 @@ public static TheoryData CreateJWEWithAesGcmTheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = encryptionCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType" }, JsonWebTokenHandler = new JsonWebTokenHandler(), @@ -506,7 +506,7 @@ public static TheoryData CreateJWEWithAesGcmTheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm256, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType" }, JsonWebTokenHandler = new JsonWebTokenHandler(), @@ -520,7 +520,7 @@ public static TheoryData CreateJWEWithAesGcmTheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = encryptionCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType" }, JsonWebTokenHandler = new JsonWebTokenHandler(), @@ -606,7 +606,7 @@ public static TheoryData CreateJWETheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_Aes256_Sha512_512, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType", }, JsonWebTokenHandler = new JsonWebTokenHandler(), @@ -626,7 +626,7 @@ public static TheoryData CreateJWETheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_Aes256_Sha512_512, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -645,7 +645,7 @@ public static TheoryData CreateJWETheoryData { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_Aes256_Sha512_512, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -1245,7 +1245,7 @@ public static TheoryData CreateJWSTheoryData TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType" }, JsonWebTokenHandler = new JsonWebTokenHandler(), @@ -1264,7 +1264,7 @@ public static TheoryData CreateJWSTheoryData TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims) }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -1282,7 +1282,7 @@ public static TheoryData CreateJWSTheoryData TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims) }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -1301,7 +1301,7 @@ public static TheoryData CreateJWSTheoryData TokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = signingCredentialsNoKeyId, - Subject = new ClaimsIdentity(Default.PayloadClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims) }, JsonWebTokenHandler = new JsonWebTokenHandler(), JwtSecurityTokenHandler = tokenHandler, @@ -2076,7 +2076,7 @@ public static TheoryData CreateJWSUsingSecurityTokenDescr { JwtRegisteredClaimNames.Nbf, EpochTime.GetIntDate(Default.NotBefore).ToString()}, { JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(Default.Expires).ToString() }, }, - Subject = new ClaimsIdentity(new List() + Subject = new CaseSensitiveClaimsIdentity(new List() { new Claim(JwtRegisteredClaimNames.Email, "Bob@contoso.com", ClaimValueTypes.String, Default.Issuer, Default.Issuer), new Claim(JwtRegisteredClaimNames.GivenName, "Bob", ClaimValueTypes.String, Default.Issuer, Default.Issuer), @@ -2101,7 +2101,7 @@ public static TheoryData CreateJWSUsingSecurityTokenDescr { JwtRegisteredClaimNames.Nbf, EpochTime.GetIntDate(Default.NotBefore).ToString()}, { JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(Default.Expires).ToString() }, }, - Subject = new ClaimsIdentity(new List() + Subject = new CaseSensitiveClaimsIdentity(new List() { new Claim(JwtRegisteredClaimNames.Email, "Bob@contoso.com", ClaimValueTypes.String, Default.Issuer, Default.Issuer), new Claim(JwtRegisteredClaimNames.GivenName, "Bob", ClaimValueTypes.String, Default.Issuer, Default.Issuer), @@ -2440,7 +2440,7 @@ public void CreateJWSWithDuplicateClaimsRoundTrip() }; // This ClaimsIdentity has two duplicate claims (with different case): "aud"/"AUD" and "iat"/"IAT". - var payloadClaimsIdentity = new ClaimsIdentity(new List() + var payloadClaimsIdentity = new CaseSensitiveClaimsIdentity(new List() { new Claim(JwtRegisteredClaimNames.Email, "Bob@contoso.com", ClaimValueTypes.String, Default.Issuer, Default.Issuer), new Claim(JwtRegisteredClaimNames.GivenName, "Bob", ClaimValueTypes.String, Default.Issuer, Default.Issuer), @@ -2931,7 +2931,7 @@ public void ValidateTokenClaims() var tokenHandler = new JsonWebTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, }; @@ -3005,7 +3005,7 @@ public async Task ValidateJsonWebTokenClaimMapping() var jsonWebTokenHandler = new JsonWebTokenHandler() { MapInboundClaims = false }; var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadAllShortClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadAllShortClaims), SigningCredentials = KeyingMaterial.DefaultSymmetricSigningCreds_256_Sha2, EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.DefaultX509Key_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256), }; @@ -3069,7 +3069,7 @@ public async Task ValidateDifferentClaimsBetweenHandlers() var jsonWebTokenHandler = new JsonWebTokenHandler() { MapInboundClaims = true }; var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadAllShortClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadAllShortClaims), SigningCredentials = KeyingMaterial.DefaultSymmetricSigningCreds_256_Sha2, EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.DefaultX509Key_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256), }; @@ -4112,7 +4112,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "TokenExpired", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -4130,7 +4130,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "InvalidIssuer", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = Default.AsymmetricSigningCredentials, }, ValidationParameters = new TokenValidationParameters @@ -4144,7 +4144,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "InvalidIssuerAndExpired", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -4161,7 +4161,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "KeysDontMatch-ValidLifeTimeAndIssuer", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = Default.AsymmetricSigningCredentials, }, ValidationParameters = new TokenValidationParameters @@ -4212,7 +4212,7 @@ public static TheoryData IncludeSecurityTokenOnFailureTes TestId = "TokenExpiredIncludeTokenOnFailedValidation", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -4231,7 +4231,7 @@ public static TheoryData IncludeSecurityTokenOnFailureTes TestId = "TokenExpiredNotIncludeTokenOnFailedValidation", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs index bfe32925d7..c0a18f9f7e 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs @@ -80,7 +80,7 @@ public void BoolClaimsEncodedAsExpected() SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = creds, - Subject = new ClaimsIdentity(claims), + Subject = new CaseSensitiveClaimsIdentity(claims), Expires = (new DateTime(2038, 1, 20)).ToUniversalTime(), }; @@ -108,7 +108,7 @@ public void DateTime2038Issue() SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = creds, - Subject = new ClaimsIdentity(claims), + Subject = new CaseSensitiveClaimsIdentity(claims), Expires = (new DateTime(2038, 1, 20)).ToUniversalTime(), }; @@ -130,7 +130,7 @@ public void JWETouchAllProperties() { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_Aes256_Sha512_512, - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), TokenType = "TokenType" }; diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JwtTokenUtilitiesTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JwtTokenUtilitiesTests.cs index e33b7d78d5..e7c649539b 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JwtTokenUtilitiesTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JwtTokenUtilitiesTests.cs @@ -38,7 +38,7 @@ public void LogSecurityArtifactTest() var jwsTokenDescriptor = new SecurityTokenDescriptor { SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials, - Subject = new ClaimsIdentity(Default.PayloadClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims) }; string stringJwe = new JsonWebTokenHandler().CreateToken(jweTokenDescriptor); diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/json/JsonWebTokenHandler.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/json/JsonWebTokenHandler.cs index 22b37229a6..2b3cc8da4a 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/json/JsonWebTokenHandler.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/json/JsonWebTokenHandler.cs @@ -806,7 +806,7 @@ private ClaimsIdentity CreateClaimsIdentityWithMapping(JsonWebToken jwtToken, To { _ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters)); - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, issuer); foreach (Claim jwtClaim in jwtToken.Claims) { bool wasMapped = _inboundClaimTypeMap.TryGetValue(jwtClaim.Type, out string claimType); @@ -875,7 +875,7 @@ private ClaimsIdentity CreateClaimsIdentityPrivate(JsonWebToken jwtToken, TokenV { _ = validationParameters ?? throw LogHelper.LogArgumentNullException(nameof(validationParameters)); - ClaimsIdentity identity = validationParameters.CreateClaimsIdentity(jwtToken, issuer); + ClaimsIdentity identity = ClaimsIdentityFactory.Create(jwtToken, validationParameters, issuer); foreach (Claim jwtClaim in jwtToken.Claims) { string claimType = jwtClaim.Type; diff --git a/test/Microsoft.IdentityModel.Protocols.WsFederation.Tests/WsFederationMessageTests.cs b/test/Microsoft.IdentityModel.Protocols.WsFederation.Tests/WsFederationMessageTests.cs index 56e528849f..fcfe5f7ee5 100644 --- a/test/Microsoft.IdentityModel.Protocols.WsFederation.Tests/WsFederationMessageTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.WsFederation.Tests/WsFederationMessageTests.cs @@ -248,7 +248,7 @@ private static SamlSecurityToken CreateSamlToken(IList claims) IssuedAt = Default.IssueInstant, Issuer = Default.Issuer, SigningCredentials = Default.AsymmetricSigningCredentials, - Subject = new ClaimsIdentity(claims) + Subject = new CaseSensitiveClaimsIdentity(claims) }; var token = samlTokenHandler.CreateToken(tokenDescriptor) as SamlSecurityToken; @@ -267,7 +267,7 @@ private static Saml2SecurityToken CreateSaml2Token(IList claims) IssuedAt = Default.IssueInstant, Issuer = Default.Issuer, SigningCredentials = Default.AsymmetricSigningCredentials, - Subject = new ClaimsIdentity(claims) + Subject = new CaseSensitiveClaimsIdentity(claims) }; var token = saml2TokenHandler.CreateToken(tokenDescriptor) as Saml2SecurityToken; diff --git a/test/Microsoft.IdentityModel.TestUtils/ClaimSets.cs b/test/Microsoft.IdentityModel.TestUtils/ClaimSets.cs index 703e9eabd7..968cb20396 100644 --- a/test/Microsoft.IdentityModel.TestUtils/ClaimSets.cs +++ b/test/Microsoft.IdentityModel.TestUtils/ClaimSets.cs @@ -122,13 +122,13 @@ static ClaimSets() claims.AddRange(DefaultClaims); DefaultDuplicatedClaims = claims; - DefaultClaimsIdentity = new ClaimsIdentity(DefaultClaims, Default.AuthenticationType); + DefaultClaimsIdentity = new CaseSensitiveClaimsIdentity(DefaultClaims, Default.AuthenticationType); DefaultClaimsIdentity.Label = Default.ClaimsIdentityLabel; - DefaultClaimsIdentityClaimsDuplicated = new ClaimsIdentity(DefaultDuplicatedClaims, Default.AuthenticationType); + DefaultClaimsIdentityClaimsDuplicated = new CaseSensitiveClaimsIdentity(DefaultDuplicatedClaims, Default.AuthenticationType); DefaultClaimsIdentityClaimsDuplicated.Label = Default.ClaimsIdentityLabelDup; - ClaimsIdentityDerivedClaims = new ClaimsIdentity(DerivedClaims, Default.AuthenticationType); - DerivedClaimsIdentityDefaultClaims = new ClaimsIdentity(DefaultClaims); - DerivedClaimsIdentityDerivedClaims = new ClaimsIdentity(DerivedClaims); + ClaimsIdentityDerivedClaims = new CaseSensitiveClaimsIdentity(DerivedClaims, Default.AuthenticationType); + DerivedClaimsIdentityDefaultClaims = new CaseSensitiveClaimsIdentity(DefaultClaims); + DerivedClaimsIdentityDerivedClaims = new CaseSensitiveClaimsIdentity(DerivedClaims); DefaultClaimsPrincipal = new ClaimsPrincipal(DefaultClaimsIdentity); } diff --git a/test/Microsoft.IdentityModel.TestUtils/Default.cs b/test/Microsoft.IdentityModel.TestUtils/Default.cs index 79c14f3c44..9f96762c47 100644 --- a/test/Microsoft.IdentityModel.TestUtils/Default.cs +++ b/test/Microsoft.IdentityModel.TestUtils/Default.cs @@ -209,7 +209,7 @@ public static List Claims public static ClaimsIdentity ClaimsIdentity { - get => new ClaimsIdentity(Claims, AuthenticationType); + get => new CaseSensitiveClaimsIdentity(Claims, AuthenticationType); } public static string ClaimsIdentityLabel @@ -497,7 +497,7 @@ public static Dictionary PayloadJsonDictionary public static ClaimsIdentity PayloadClaimsIdentity { - get => new ClaimsIdentity(PayloadClaims, "AuthenticationTypes.Federation"); + get => new CaseSensitiveClaimsIdentity(PayloadClaims, "AuthenticationTypes.Federation"); } public static Dictionary PayloadDictionary @@ -906,7 +906,7 @@ public static List SamlClaimsIssuerEqOriginalIssuer public static ClaimsIdentity SamlClaimsIdentity { - get => new ClaimsIdentity(SamlClaims, AuthenticationType); + get => new CaseSensitiveClaimsIdentity(SamlClaims, AuthenticationType); } public static SamlConditions SamlConditionsSingleCondition @@ -958,7 +958,7 @@ public static SecurityTokenDescriptor SecurityTokenDescriptor( IssuedAt = DateTime.UtcNow, NotBefore = DateTime.UtcNow, SigningCredentials = signingCredentials, - Subject = claims == null ? ClaimsIdentity : new ClaimsIdentity(claims) + Subject = claims == null ? ClaimsIdentity : new CaseSensitiveClaimsIdentity(claims) }; } @@ -973,7 +973,7 @@ public static SecurityTokenDescriptor SecurityTokenDescriptor(SigningCredentials IssuedAt = DateTime.UtcNow, NotBefore = DateTime.UtcNow, SigningCredentials = signingCredentials, - Subject = claims == null ? ClaimsIdentity : new ClaimsIdentity(claims), + Subject = claims == null ? ClaimsIdentity : new CaseSensitiveClaimsIdentity(claims), }; if (securityTokenDescriptor.Claims == null) @@ -998,7 +998,7 @@ public static SecurityTokenDescriptor X509SecurityTokenDescriptor( IssuedAt = DateTime.UtcNow, NotBefore = DateTime.UtcNow, SigningCredentials = signingCredentials, - Subject = claims == null ? ClaimsIdentity : new ClaimsIdentity(claims) + Subject = claims == null ? ClaimsIdentity : new CaseSensitiveClaimsIdentity(claims) }; } diff --git a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs index 593e79b12f..84c882cdf2 100644 --- a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs +++ b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs @@ -45,6 +45,7 @@ public class IdentityComparer { typeof(CanonicalizingTransfrom).ToString(), CompareAllPublicProperties }, { typeof(Claim).ToString(), CompareAllPublicProperties }, { typeof(ClaimsIdentity).ToString(), CompareAllPublicProperties }, + { typeof(CaseSensitiveClaimsIdentity).ToString(), CompareAllPublicProperties }, { typeof(ClaimsPrincipal).ToString(), CompareAllPublicProperties }, { typeof(Collection).ToString(), ContinueCheckingEquality }, { typeof(DateTime).ToString(), AreDateTimesEqual }, @@ -55,6 +56,7 @@ public class IdentityComparer { typeof(IDictionary).ToString(), AreStringDictionariesEqual}, { typeof(IEnumerable).ToString(), AreClaimsEnumsEqual }, { typeof(IEnumerable).ToString(), AreClaimsIdentitiesEnumsEqual }, + { typeof(IEnumerable).ToString(), AreClaimsIdentitiesEnumsEqual }, { typeof(IEnumerable).ToString(), AreObjectEnumsEqual }, { typeof(IEnumerable).ToString(), AreSecurityKeyEnumsEqual }, { typeof(IEnumerable).ToString(), AreStringEnumsEqual }, @@ -1705,6 +1707,12 @@ public static bool CompareAllPublicProperties(object obj1, object obj2, CompareC continue; } + if (type == typeof(CaseSensitiveClaimsIdentity)) + { + if (propertyInfo.Name == "SecurityToken") + continue; + } + if (propertyInfo.GetMethod != null) { object val1 = propertyInfo.GetValue(obj1, null); diff --git a/test/Microsoft.IdentityModel.TestUtils/NotDefault.cs b/test/Microsoft.IdentityModel.TestUtils/NotDefault.cs index a80002b9fb..75077cf113 100644 --- a/test/Microsoft.IdentityModel.TestUtils/NotDefault.cs +++ b/test/Microsoft.IdentityModel.TestUtils/NotDefault.cs @@ -64,7 +64,7 @@ public static ClaimsIdentity CaimsIdentity { get { - return new ClaimsIdentity(Claims, AuthenticationType, NameClaimType, RoleClaimType) + return new CaseSensitiveClaimsIdentity(Claims, AuthenticationType, NameClaimType, RoleClaimType) { Label = ClaimsIdentityLabel }; diff --git a/test/Microsoft.IdentityModel.TestUtils/ReferenceSaml.cs b/test/Microsoft.IdentityModel.TestUtils/ReferenceSaml.cs index 8d90a9a7d0..c027d08231 100644 --- a/test/Microsoft.IdentityModel.TestUtils/ReferenceSaml.cs +++ b/test/Microsoft.IdentityModel.TestUtils/ReferenceSaml.cs @@ -1291,7 +1291,7 @@ public static SamlTokenTestSet TokenClaimsIdentitiesSameSubject string name = ClaimTypes.Country.Substring(index + 1); var statement = new SamlAttributeStatement(ReferenceSaml.SamlSubject, new SamlAttribute(ns, name, Default.Country)); - var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); + var identity = new CaseSensitiveClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); identity.AddClaim(claim); identity.AddClaim(claim); return new SamlTokenTestSet @@ -1312,12 +1312,12 @@ public static SamlTokenTestSet TokenClaimsIdentitiesDifferentSubjects string name = ClaimTypes.Country.Substring(index + 1); var attrStatement1 = new SamlAttribute(ns, name, Default.Country); var statement1 = new SamlAttributeStatement(ReferenceSaml.SamlSubject, attrStatement1); - var identity1 = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); + var identity1 = new CaseSensitiveClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); identity1.AddClaim(claim1); // statement2 has different subject with statement1 var statement2 = new SamlAttributeStatement(new SamlSubject(Default.NameIdentifierFormat, Default.NameQualifier, Default.AttributeName), attrStatement1); - var identity2 = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); + var identity2 = new CaseSensitiveClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); identity2.AddClaim(claim1); var claim2 = new Claim(ClaimTypes.NameIdentifier, Default.AttributeName, ClaimValueTypes.String, Default.Issuer); diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.cs index d9bb11a79b..9b6303dc04 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.cs @@ -342,7 +342,7 @@ public static TheoryData WriteTokenTheoryData Expires = Default.Expires, Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), }; var validationParameters = new TokenValidationParameters @@ -487,7 +487,7 @@ public void SetDefaultTimesOnTokenCreation() Issuer = Default.Issuer, Audience = Default.Audience, SigningCredentials = Default.AsymmetricSigningCredentials, - Subject = new ClaimsIdentity() + Subject = new CaseSensitiveClaimsIdentity() }; var token = tokenHandler.CreateToken(descriptorNoTimeValues); @@ -1153,7 +1153,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParametersWithAudiences, @@ -1170,7 +1170,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParametersWithAudiences, @@ -1187,7 +1187,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParametersWithAudiences, @@ -1204,7 +1204,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParametersWithAudiences, @@ -1241,7 +1241,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParameters @@ -1258,7 +1258,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, Claims = Default.SamlClaimsDictionary, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParameters @@ -1275,7 +1275,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, Claims = Default.SamlClaimsDictionary, - Subject = new ClaimsIdentity + Subject = new CaseSensitiveClaimsIdentity ( new List { @@ -1305,7 +1305,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri { ClaimTypes.GivenName, "Bob" }, { ClaimTypes.Role, "HR" } }, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, Saml2SecurityTokenHandler = new Saml2SecurityTokenHandler(), ValidationParameters = validationParameters @@ -1327,7 +1327,7 @@ public static TheoryData CreateSaml2TokenUsingTokenDescri { ClaimTypes.GivenName, "Alice" }, { ClaimTypes.Role, "HR" } }, - Subject = new ClaimsIdentity + Subject = new CaseSensitiveClaimsIdentity ( new List { diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.cs index 4ec30af29c..51e0da011b 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.cs @@ -120,7 +120,8 @@ public static TheoryData CanReadTokenTheoryData public void CreateClaimsIdentities(SamlTheoryData theoryData) { TestUtilities.WriteHeader($"{this}.CreateClaimsIdentities", theoryData); - var context = new CompareContext($"{this}.CreateClaimsIdentities, {theoryData.TestId}") { IgnoreType = true }; + var context = new CompareContext($"{this}.CreateClaimsIdentities, {theoryData.TestId}"); + try { var identities = ((theoryData.Handler) as SamlSecurityTokenHandlerPublic).CreateClaimsIdentitiesPublic(theoryData.TokenTestSet.SecurityToken as SamlSecurityToken, theoryData.Issuer, theoryData.ValidationParameters); @@ -881,7 +882,7 @@ public static TheoryData WriteTokenTheoryData Expires = Default.Expires, Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), }; var validationParameters = new TokenValidationParameters @@ -1241,7 +1242,7 @@ public static TheoryData CreateSamlTokenUsingTokenDescrip Issuer = Default.Issuer, SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, SamlSecurityTokenHandler = new SamlSecurityTokenHandler(), ValidationParameters = validationParameters @@ -1258,7 +1259,7 @@ public static TheoryData CreateSamlTokenUsingTokenDescrip SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, Claims = Default.SamlClaimsDictionary, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, SamlSecurityTokenHandler = new SamlSecurityTokenHandler(), ValidationParameters = validationParameters @@ -1275,7 +1276,7 @@ public static TheoryData CreateSamlTokenUsingTokenDescrip SigningCredentials = new SigningCredentials(KeyingMaterial.X509SecurityKeySelfSigned2048_SHA256, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest), EncryptingCredentials = null, Claims = Default.SamlClaimsDictionary, - Subject = new ClaimsIdentity + Subject = new CaseSensitiveClaimsIdentity ( new List { @@ -1305,7 +1306,7 @@ public static TheoryData CreateSamlTokenUsingTokenDescrip { ClaimTypes.GivenName, "Bob" }, { ClaimTypes.Role, "HR" } }, - Subject = new ClaimsIdentity(Default.SamlClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims) }, SamlSecurityTokenHandler = new SamlSecurityTokenHandler(), ValidationParameters = validationParameters @@ -1327,7 +1328,7 @@ public static TheoryData CreateSamlTokenUsingTokenDescrip { ClaimTypes.GivenName, "Alice" }, { ClaimTypes.Role, "HR" } }, - Subject = new ClaimsIdentity + Subject = new CaseSensitiveClaimsIdentity ( new List { diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlTestData.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlTestData.cs index 889b954610..6479051ddd 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlTestData.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlTestData.cs @@ -21,7 +21,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TokenDescriptor = new SecurityTokenDescriptor { Audience = Default.Audience, - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -41,7 +41,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TokenDescriptor = new SecurityTokenDescriptor { Audience = Default.Audience, - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), SigningCredentials = Default.AsymmetricSigningCredentials, Issuer = Default.Issuer, }, @@ -57,7 +57,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TokenDescriptor = new SecurityTokenDescriptor { Audience = Default.Audience, - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -78,7 +78,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TokenDescriptor = new SecurityTokenDescriptor { Audience = Default.Audience, - Subject = new ClaimsIdentity(Default.SamlClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.SamlClaims), SigningCredentials = Default.AsymmetricSigningCredentials, Issuer = Default.Issuer, }, diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/CaseSensitiveClaimsIdentityTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/CaseSensitiveClaimsIdentityTests.cs new file mode 100644 index 0000000000..8cd3b1e84d --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/CaseSensitiveClaimsIdentityTests.cs @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.TestUtils; +using Newtonsoft.Json.Linq; +using Xunit; +using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames; + +namespace Microsoft.IdentityModel.Tokens.Tests +{ + public class CaseSensitiveClaimsIdentityTests + { + private static readonly string LowerCaseClaimName = "tid"; + private static readonly string LowerCaseClaimValue = "tenant"; + private static readonly string UpperCaseClaimName = "TID"; + private static readonly string UpperCaseClaimValue = "TENANT"; + private static readonly JObject _defaultPayload = new() + { + [JwtRegisteredClaimNames.Iss] = Default.Issuer, + [JwtRegisteredClaimNames.Aud] = Default.Audience, + }; + + [Theory, MemberData(nameof(GetCaseSensitiveClaimsIdentityTheoryData))] + public void FindAll_DoesCaseSensitiveSearch(CaseSensitiveClaimsIdentityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.FindAll_DoesCaseSensitiveSearch", theoryData); + + try + { + var actualClaims = theoryData.ClaimsIdentity.FindAll(theoryData.ClaimNameSearch).Select(claim => claim.Type); + + IdentityComparer.AreEqual(theoryData.ExpectedClaims, actualClaims, context); + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + [Theory, MemberData(nameof(GetCaseSensitiveClaimsIdentityTheoryData))] + public void FindFirst_DoesCaseSensitiveSearch(CaseSensitiveClaimsIdentityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.FindFirst_DoesCaseSensitiveSearch", theoryData); + + try + { + var actualClaim = theoryData.ClaimsIdentity.FindFirst(theoryData.ClaimNameSearch)?.Type; + + IdentityComparer.AreEqual(theoryData.ExpectedClaim, actualClaim, context); + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + [Theory, MemberData(nameof(GetCaseSensitiveClaimsIdentityTheoryData))] + public void HasClaim_DoesCaseSensitiveSearch(CaseSensitiveClaimsIdentityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.HasClaim_DoesCaseSensitiveSearch", theoryData); + + try + { + var actualHasClaim = theoryData.ClaimsIdentity.HasClaim(theoryData.ClaimNameSearch, theoryData.ClaimValueSearch); + + IdentityComparer.AreEqual(theoryData.ExpectedHasClaim, actualHasClaim, context); + theoryData.ExpectedException.ProcessNoException(context); + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + [Fact] + public void AddClaim_AddsClaim() + { + var claimsIdentity = new CaseSensitiveClaimsIdentity(); + + Assert.Empty(claimsIdentity.Claims); + + var claim = new Claim("claimType", "claimValue"); + claimsIdentity.AddClaim(claim); + + Assert.NotEmpty(claimsIdentity.Claims); + } + + [Fact] + public void AddClaim_AddNull_ThrowsException() + { + var claimsIdentity = new CaseSensitiveClaimsIdentity(); + + Assert.Throws(() => claimsIdentity.AddClaim(null)); + } + + [Fact] + public void RemoveClaim_RemovesClaim() + { + var claimsIdentity = new CaseSensitiveClaimsIdentity(); + var claim = new Claim("claimType", "claimValue"); + claimsIdentity.AddClaim(claim); + + Assert.NotEmpty(claimsIdentity.Claims); + + var claimToRemove = claimsIdentity.Claims.First(); + + claimsIdentity.RemoveClaim(claimToRemove); + + Assert.Empty(claimsIdentity.Claims); + } + + [Fact] + public void DefaultProperties_CorrectlySet() + { + var validationParameters = new TokenValidationParameters() + { + NameClaimType = "tvp_name", + RoleClaimType = "tvp_role", + }; + var claimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject(), validationParameters); + + Assert.Equal(validationParameters.NameClaimType, claimsIdentity.NameClaimType); + Assert.Equal(validationParameters.RoleClaimType, claimsIdentity.RoleClaimType); + } + + public static TheoryData GetCaseSensitiveClaimsIdentityTheoryData + { + get + { + return new TheoryData + { + new CaseSensitiveClaimsIdentityTheoryData("UppercaseSearch_ClaimsExist") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [LowerCaseClaimName] = LowerCaseClaimValue, + [UpperCaseClaimName] = UpperCaseClaimValue, + }), + ClaimNameSearch = UpperCaseClaimName, + ClaimValueSearch = UpperCaseClaimValue, + ExpectedHasClaim = true, + ExpectedClaim = UpperCaseClaimName, + ExpectedClaims = [UpperCaseClaimName], + }, + new CaseSensitiveClaimsIdentityTheoryData("LowercaseSearch_ClaimsExist") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [UpperCaseClaimName] = UpperCaseClaimValue, + [LowerCaseClaimName] = LowerCaseClaimValue, + }), + ClaimNameSearch = LowerCaseClaimName, + ClaimValueSearch = LowerCaseClaimValue, + ExpectedHasClaim = true, + ExpectedClaim = LowerCaseClaimName, + ExpectedClaims = [LowerCaseClaimName], + }, + new CaseSensitiveClaimsIdentityTheoryData("UppercaseSearch_ClaimsMissing") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [LowerCaseClaimName] = LowerCaseClaimValue, + }), + ClaimNameSearch = UpperCaseClaimName, + ClaimValueSearch = UpperCaseClaimValue, + ExpectedHasClaim = false, + ExpectedClaim = null, + ExpectedClaims = [], + }, + new CaseSensitiveClaimsIdentityTheoryData("LowercaseSearch_ClaimsMissing") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [UpperCaseClaimName] = UpperCaseClaimValue, + }), + ClaimNameSearch = LowerCaseClaimName, + ClaimValueSearch = LowerCaseClaimValue, + ExpectedHasClaim = false, + ExpectedClaim = null, + ExpectedClaims = [], + }, + new CaseSensitiveClaimsIdentityTheoryData("UppercaseMixedSearch_ClaimsMissing") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [LowerCaseClaimName] = UpperCaseClaimValue, + }), + ClaimNameSearch = UpperCaseClaimName, + ClaimValueSearch = UpperCaseClaimValue, + ExpectedHasClaim = false, + ExpectedClaim = null, + ExpectedClaims = [], + }, + new CaseSensitiveClaimsIdentityTheoryData("LowercaseMixedSearch_ClaimsMissing") + { + ClaimsIdentity = CreateCaseSensitiveClaimsIdentity(new JObject { + [UpperCaseClaimName] = LowerCaseClaimValue, + }), + ClaimNameSearch = LowerCaseClaimName, + ClaimValueSearch = LowerCaseClaimValue, + ExpectedHasClaim = false, + ExpectedClaim = null, + ExpectedClaims = [], + }, + }; + } + } + + public class CaseSensitiveClaimsIdentityTheoryData(string testId) : TheoryDataBase(testId) + { + internal ClaimsIdentity ClaimsIdentity { get; set; } + internal string ClaimNameSearch { get; set; } + internal string ClaimValueSearch { get; set; } + internal bool ExpectedHasClaim { get; set; } + internal string ExpectedClaim { get; set; } + internal List ExpectedClaims { get; set; } + } + + private static ClaimsIdentity CreateCaseSensitiveClaimsIdentity(JObject claims, TokenValidationParameters validationParameters = null) + { + var handler = new JsonWebTokenHandler(); + return handler.CreateClaimsIdentityInternal(new JsonWebToken(CreateUnsignedToken(claims)), validationParameters ?? new TokenValidationParameters(), Default.Issuer); + } + + private static string CreateUnsignedToken(JObject payload) + { + // Add default claims to the beginning of the payload + var jObject = new JObject(_defaultPayload); + jObject.Merge(payload); + return string.Concat(Base64UrlEncoder.Encode("{}"), ".", Base64UrlEncoder.Encode(jObject.ToString()), "."); + } + } +} diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs new file mode 100644 index 0000000000..5cb38bb83a --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/ClaimsIdentityFactoryTests.cs @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Security.Claims; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.TestUtils; +using Xunit; + +namespace Microsoft.IdentityModel.Tokens.Tests +{ + [Collection(nameof(ClaimsIdentityFactoryTests))] + public class ClaimsIdentityFactoryTests + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Create_FromTokenValidationParameters_ReturnsCorrectClaimsIdentity(bool useClaimsIdentity) + { + AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, useClaimsIdentity); + + var jsonWebToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())); + var tokenValidationParameters = new TokenValidationParameters(); + tokenValidationParameters.AuthenticationType = "custom-authentication-type"; + tokenValidationParameters.NameClaimType = "custom-name"; + tokenValidationParameters.RoleClaimType = "custom-role"; + + var actualClaimsIdentity = ClaimsIdentityFactory.Create(jsonWebToken, tokenValidationParameters, Default.Issuer); + + Assert.Equal(tokenValidationParameters.AuthenticationType, actualClaimsIdentity.AuthenticationType); + Assert.Equal(tokenValidationParameters.NameClaimType, actualClaimsIdentity.NameClaimType); + Assert.Equal(tokenValidationParameters.RoleClaimType, actualClaimsIdentity.RoleClaimType); + + if (useClaimsIdentity) + { + Assert.IsType(actualClaimsIdentity); + } + else + { + Assert.IsType(actualClaimsIdentity); + Assert.NotNull(((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + Assert.Equal(jsonWebToken, ((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken); + } + + AppContext.SetSwitch(AppContextSwitches.UseClaimsIdentityTypeSwitch, false); + } + + [Fact] + public void Create_FromDerivedTokenValidationParameters_HonorsSetSecurityToken() + { + var jsonWebToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())); + var tokenValidationParameters = new DerivedTokenValidationParameters(returnCaseSensitiveClaimsIdentityWithToken: true); + tokenValidationParameters.AuthenticationType = "custom-authentication-type"; + tokenValidationParameters.NameClaimType = "custom-name"; + tokenValidationParameters.RoleClaimType = "custom-role"; + + var actualClaimsIdentity = ClaimsIdentityFactory.Create(jsonWebToken, tokenValidationParameters, Default.Issuer); + + // The SecurityToken set in derived TokenValidationParameters is honored. + Assert.IsType(actualClaimsIdentity); + + var securityToken = ((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken; + Assert.NotNull(securityToken); + Assert.IsType(securityToken); + Assert.NotEqual(jsonWebToken, securityToken); + + Assert.Equal(tokenValidationParameters.AuthenticationType, actualClaimsIdentity.AuthenticationType); + Assert.Equal(tokenValidationParameters.NameClaimType, actualClaimsIdentity.NameClaimType); + Assert.Equal(tokenValidationParameters.RoleClaimType, actualClaimsIdentity.RoleClaimType); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Create_FromDerivedTokenValidationParameters_ReturnsCorrectClaimsIdentity(bool tvpReturnsCaseSensitiveClaimsIdentityWithoutToken) + { + var jsonWebToken = new JsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())); + var tokenValidationParameters = new DerivedTokenValidationParameters(returnCaseSensitiveClaimsIdentityWithoutToken: tvpReturnsCaseSensitiveClaimsIdentityWithoutToken); + tokenValidationParameters.AuthenticationType = "custom-authentication-type"; + tokenValidationParameters.NameClaimType = "custom-name"; + tokenValidationParameters.RoleClaimType = "custom-role"; + + var actualClaimsIdentity = ClaimsIdentityFactory.Create(jsonWebToken, tokenValidationParameters, Default.Issuer); + + Assert.IsType(actualClaimsIdentity); + + var securityToken = ((CaseSensitiveClaimsIdentity)actualClaimsIdentity).SecurityToken; + Assert.NotNull(securityToken); + Assert.Equal(jsonWebToken, securityToken); + + Assert.Equal(tokenValidationParameters.AuthenticationType, actualClaimsIdentity.AuthenticationType); + Assert.Equal(tokenValidationParameters.NameClaimType, actualClaimsIdentity.NameClaimType); + Assert.Equal(tokenValidationParameters.RoleClaimType, actualClaimsIdentity.RoleClaimType); + } + + + + private class DerivedTokenValidationParameters : TokenValidationParameters + { + private bool _returnCaseSensitiveClaimsIdentityWithToken; + private bool _returnCaseSensitiveClaimsIdentityWithoutToken; + + public DerivedTokenValidationParameters(bool returnCaseSensitiveClaimsIdentityWithToken = false, bool returnCaseSensitiveClaimsIdentityWithoutToken = false) + { + _returnCaseSensitiveClaimsIdentityWithToken = returnCaseSensitiveClaimsIdentityWithToken; + _returnCaseSensitiveClaimsIdentityWithoutToken = returnCaseSensitiveClaimsIdentityWithoutToken; + } + + public override ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken, string issuer) + { + if (_returnCaseSensitiveClaimsIdentityWithToken) + { + return new CaseSensitiveClaimsIdentity(AuthenticationType, NameClaimType, RoleClaimType) + { + SecurityToken = new TvpJsonWebToken(Default.Jwt(Default.SecurityTokenDescriptor())), + }; + } + + if (_returnCaseSensitiveClaimsIdentityWithoutToken) + { + return new CaseSensitiveClaimsIdentity(AuthenticationType, NameClaimType, RoleClaimType); + } + + return new ClaimsIdentity(AuthenticationType, NameClaimType, RoleClaimType); + } + } + + private class TvpJsonWebToken : JsonWebToken + { + public TvpJsonWebToken(string jwtEncodedString) : base(jwtEncodedString) + { + } + + public TvpJsonWebToken(ReadOnlyMemory encodedTokenMemory) : base(encodedTokenMemory) + { + } + + public TvpJsonWebToken(string header, string payload) : base(header, payload) + { + } + } + } +} diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/CrossTokenTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/CrossTokenTests.cs index be26ab7654..82e4cd9efb 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/CrossTokenTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/CrossTokenTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.TestUtils; @@ -23,6 +24,7 @@ public class CrossTokenTests public void CrossTokenValidateToken(CrossTokenTheoryData theoryData) { var context = TestUtilities.WriteHeader($"{this}.CrossTokenValidateToken", theoryData); + try { var samlToken = IdentityUtilities.CreateEncodedSaml(theoryData.SecurityTokenDescriptor, theoryData.SamlTokenHandler); diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/IdentityComparerTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/IdentityComparerTests.cs index f293582ed3..ce17447c1c 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/IdentityComparerTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/IdentityComparerTests.cs @@ -127,7 +127,7 @@ public void CompareClaimsIdentities() var originalRoleType = Guid.NewGuid().ToString(); var originalBootstrapContext = Guid.NewGuid().ToString(); var originalLabel = Guid.NewGuid().ToString(); - var originalActor = new ClaimsIdentity(Guid.NewGuid().ToString()); + var originalActor = new CaseSensitiveClaimsIdentity(Guid.NewGuid().ToString()); // Base ClaimsIdentity to use for all future comparisons. var originalClaimsIdentity = CreateClaimsIdentity(originalClaims, originalAuthenticationType, @@ -189,7 +189,7 @@ private ClaimsIdentity CreateClaimsIdentity(IEnumerable claims, string au string nameType, string roleType, string label, object bootstrapContext, ClaimsIdentity actor) { - ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, authenticationType, nameType, roleType); + ClaimsIdentity claimsIdentity = new CaseSensitiveClaimsIdentity(claims, authenticationType, nameType, roleType); claimsIdentity.Label = label; claimsIdentity.BootstrapContext = bootstrapContext; claimsIdentity.Actor = actor; @@ -202,7 +202,7 @@ public void CompareClaimsPrinciples() { TestUtilities.WriteHeader($"{this}.CompareClaimsPrincipals", true); var context = new CompareContext($"{this}.CompareClaimsPrincipals"); - var claimsPrincipal1 = new ClaimsPrincipal(new List { new ClaimsIdentity(Guid.NewGuid().ToString()) }); + var claimsPrincipal1 = new ClaimsPrincipal(new List { new CaseSensitiveClaimsIdentity(Guid.NewGuid().ToString()) }); var claimsPrincipal2 = new ClaimsPrincipal(); IdentityComparer.AreEqual(claimsPrincipal1, claimsPrincipal2, context); diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationResultTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationResultTests.cs index 2fa76c11af..50f081924e 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationResultTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/TokenValidationResultTests.cs @@ -29,7 +29,7 @@ public void GetSets() { PropertyNamesAndSetGetValue = new List>> { - new KeyValuePair>("ClaimsIdentity", new List{(ClaimsIdentity)null, new ClaimsIdentity(), new ClaimsIdentity()}), + new KeyValuePair>("ClaimsIdentity", new List{(CaseSensitiveClaimsIdentity)null, new CaseSensitiveClaimsIdentity(), new CaseSensitiveClaimsIdentity()}), new KeyValuePair>("Exception", new List{(Exception)null, new Exception(), new Exception()}), new KeyValuePair>("Issuer", new List{(string)null, "issuer", "issuer2"}), new KeyValuePair>("IsValid", new List{false, false, true}), diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs index 243bc2da24..5e0bcb21b8 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs @@ -1090,14 +1090,14 @@ public void RoleClaims() DateTime utcNow = DateTime.UtcNow; DateTime expire = utcNow + TimeSpan.FromHours(1); - ClaimsIdentity subject = new ClaimsIdentity(claims: ClaimSets.GetDefaultRoleClaims(null)); + ClaimsIdentity subject = new CaseSensitiveClaimsIdentity(claims: ClaimSets.GetDefaultRoleClaims(null)); JwtSecurityToken jwtToken = handler.CreateJwtSecurityToken(Default.Issuer, Default.Audience, subject, utcNow, expire, utcNow); SecurityToken securityToken; ClaimsPrincipal principal = handler.ValidateToken(jwtToken.RawData, validationParameters, out securityToken); CheckForRoles(ClaimSets.GetDefaultRoles(), new string[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }, principal); ClaimsIdentity expectedIdentity = - new ClaimsIdentity( + new CaseSensitiveClaimsIdentity( authenticationType: "Federation", claims: ClaimSets.GetDefaultRoleClaims(handler) ); @@ -1179,7 +1179,7 @@ public void NameAndRoleClaimDelegates() }; ClaimsIdentity subject = - new ClaimsIdentity( + new CaseSensitiveClaimsIdentity( new List { new Claim(_nameClaimTypeForDelegate, delegateName), new Claim(validationParametersNameClaimType, validationParameterName), diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs index 00bf5e5c5e..a67334bb45 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs @@ -25,7 +25,7 @@ public class JwtSecurityTokenHandlerTests [Fact] public void JwtSecurityTokenHandler_CreateToken_SameTypeMultipleValues() { - var identity = new ClaimsIdentity("Test"); + var identity = new CaseSensitiveClaimsIdentity("Test"); var claimValues = new List { "value1", "value2", "value3", "value4" }; @@ -556,7 +556,7 @@ public static TheoryData CreateJWEUsingSecurityTokenDescr SigningCredentials = Default.X509AsymmetricSigningCredentials, EncryptingCredentials = null, Claims = Default.PayloadJsonDictionary, - Subject = new ClaimsIdentity(Default.PayloadJsonClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadJsonClaims) }, JwtSecurityTokenHandler = tokenHandler, JsonWebTokenHandler = jsonTokenHandler, @@ -581,7 +581,7 @@ public static TheoryData CreateJWEUsingSecurityTokenDescr { "ClaimValueTypes.JsonClaimValueTypes.JsonArray1", JArray.Parse(@"[1,2,3,4]") }, {"ClaimValueTypes.JsonClaimValueTypes.Integer1", 1 }, }, - Subject = new ClaimsIdentity(Default.PayloadJsonClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadJsonClaims) }, JwtSecurityTokenHandler = tokenHandler, JsonWebTokenHandler = jsonTokenHandler, @@ -607,7 +607,7 @@ public static TheoryData CreateJWEUsingSecurityTokenDescr { SigningCredentials = Default.X509AsymmetricSigningCredentials, EncryptingCredentials = null, - Subject = new ClaimsIdentity(Default.PayloadJsonClaims) + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadJsonClaims) }, JwtSecurityTokenHandler = tokenHandler, JsonWebTokenHandler = jsonTokenHandler, @@ -621,7 +621,7 @@ public static TheoryData CreateJWEUsingSecurityTokenDescr SigningCredentials = Default.AsymmetricSigningCredentials, Claims = Default.PayloadJsonDictionary, EncryptingCredentials = null, - Subject = new ClaimsIdentity + Subject = new CaseSensitiveClaimsIdentity ( new List { @@ -666,7 +666,7 @@ public static TheoryData ActorTheoryData // Actor validation is true // Actor will be validated using validationParameters since validationsParameters.ActorValidationParameters is null - ClaimsIdentity claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + ClaimsIdentity claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.AsymmetricJwt)); var validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = true; @@ -683,7 +683,7 @@ public static TheoryData ActorTheoryData // Actor validation is true // Actor will be validated using validationParameters since validationsParameters.ActorValidationParameters is null - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.AsymmetricJwt)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = true; @@ -701,7 +701,7 @@ public static TheoryData ActorTheoryData // Actor validation is true // Actor is signed with symmetric key // TokenValidationParameters.ActorValidationParameters will not find signing key because an assymetric signing key is provided - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.SymmetricJws)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = true; @@ -721,7 +721,7 @@ public static TheoryData ActorTheoryData // Actor is signed with symmetric key // TokenValidationParameters.ActorValidationParameters is null // TokenValidationParameters will be used, but will not find signing key because an assymetric signing key is provided - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.SymmetricJws)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = true; @@ -741,7 +741,7 @@ public static TheoryData ActorTheoryData // TokenValidationParameters.ActorValidationParameters is null // TokenValidationParameters will be used, but will not find signing key because an assymetric signing key is provided // All Signing keys will not be tried to verify signature because validationParameters.TryAllIssuerSigningKeys is set to false - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.SymmetricJws)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = true; @@ -760,7 +760,7 @@ public static TheoryData ActorTheoryData // Actor validation is false // Actor is signed with symmetric key // TokenValidationParameters.ActorValidationParameters will not find signing key, but Actor should not be validated - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.SymmetricJws)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ValidateActor = false; @@ -778,7 +778,7 @@ public static TheoryData ActorTheoryData // Actor validation is true // Actor will be validated using validationsParameters.ActorValidationParameters - claimsIdentity = new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity); + claimsIdentity = new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity); claimsIdentity.AddClaim(new Claim(ClaimTypes.Actor, Default.SymmetricJws)); validationParameters = Default.AsymmetricSignTokenValidationParameters; validationParameters.ActorValidationParameters = Default.SymmetricSignTokenValidationParameters; @@ -1046,7 +1046,7 @@ public void InboundOutboundClaimTypeMapping() var jwt = handler.CreateJwtSecurityToken( issuer: Default.Issuer, audience: Default.Audience, - subject: new ClaimsIdentity( + subject: new CaseSensitiveClaimsIdentity( ClaimSets.AllInboundShortClaimTypes( Default.Issuer, Default.Issuer))); @@ -1099,7 +1099,7 @@ public void InboundOutboundClaimTypeMapping() { JwtRegisteredClaimNames.Sub, "Mapped_" + JwtRegisteredClaimNames.Sub }, }; - jwt = handler.CreateJwtSecurityToken(issuer: Default.Issuer, audience: Default.Audience, subject: new ClaimsIdentity(claims)); + jwt = handler.CreateJwtSecurityToken(issuer: Default.Issuer, audience: Default.Audience, subject: new CaseSensitiveClaimsIdentity(claims)); List expectedClaims = new List() { @@ -1144,7 +1144,7 @@ public void MapInboundClaims() new Claim(JwtRegisteredClaimNames.GivenName, "Bob", ClaimValueTypes.String, Default.Issuer) }; - var jwt = handler.CreateJwtSecurityToken(issuer: Default.Issuer, audience: Default.Audience, subject: new ClaimsIdentity(claims)); + var jwt = handler.CreateJwtSecurityToken(issuer: Default.Issuer, audience: Default.Audience, subject: new CaseSensitiveClaimsIdentity(claims)); // Check to make sure none of the short claim types have been mapped to longer ones. foreach (var claim in claims) @@ -1303,12 +1303,12 @@ public void InstanceClaimMappingAndFiltering() handler.OutboundClaimTypeMap.Add("internalClaim", "jwtClaim"); // Test outgoing - var outgoingToken = handler.CreateJwtSecurityToken(subject: new ClaimsIdentity(new Claim[] { internalClaim })); + var outgoingToken = handler.CreateJwtSecurityToken(subject: new CaseSensitiveClaimsIdentity(new Claim[] { internalClaim })); var wasClaimMapped = System.Linq.Enumerable.Contains(outgoingToken.Claims, jwtClaim, new ClaimComparer()); Assert.True(wasClaimMapped); // Test incoming - var incomingToken = handler.CreateJwtSecurityToken(issuer: "Test Issuer", subject: new ClaimsIdentity(new Claim[] { jwtClaim, unwantedClaim })); + var incomingToken = handler.CreateJwtSecurityToken(issuer: "Test Issuer", subject: new CaseSensitiveClaimsIdentity(new Claim[] { jwtClaim, unwantedClaim })); var validationParameters = new TokenValidationParameters { RequireSignedTokens = false, @@ -2554,7 +2554,7 @@ public static TheoryData ValidateTokenTheoryData { TestId = "NullToken_PayloadValidationFailure", ExpectedException = ExpectedException.SecurityTokenInvalidIssuerException(TokenLogMessages.IDX10211), - Token = handler.CreateEncodedJwt("", Default.Audience, new ClaimsIdentity(ClaimSets.DefaultClaimsIdentity), null, null, null, Default.AsymmetricSigningCredentials), + Token = handler.CreateEncodedJwt("", Default.Audience, new CaseSensitiveClaimsIdentity(ClaimSets.DefaultClaimsIdentity), null, null, null, Default.AsymmetricSigningCredentials), TokenHandler = handler, ValidationParameters = Default.AsymmetricSignTokenValidationParameters }, @@ -3182,7 +3182,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "TokenExpired", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -3200,7 +3200,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "InvalidIssuer", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = Default.AsymmetricSigningCredentials, }, ValidationParameters = new TokenValidationParameters @@ -3214,7 +3214,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "InvalidIssuerAndExpiredToken", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaimsExpired), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaimsExpired), Expires = DateTime.UtcNow.Subtract(new TimeSpan(0, 10, 0)), IssuedAt = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), NotBefore = DateTime.UtcNow.Subtract(new TimeSpan(1, 0, 0)), @@ -3231,7 +3231,7 @@ public static TheoryData SecurityKeyNotFoundExceptionTest TestId = "KeysDontMatch-ValidLifeTimeAndIssuer", TokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(Default.PayloadClaims), + Subject = new CaseSensitiveClaimsIdentity(Default.PayloadClaims), SigningCredentials = Default.AsymmetricSigningCredentials, }, ValidationParameters = new TokenValidationParameters diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/References.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/References.cs index ae1099b0e7..9249bb11ad 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/References.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/References.cs @@ -578,7 +578,7 @@ public static Dictionary ClaimNamesAsDictionary public static ClaimsIdentity ClaimsIdentityDistributedClaims(string issuer, string authType, Dictionary claimSources, Dictionary claimNames) { - var identity = new ClaimsIdentity(authType); + var identity = new CaseSensitiveClaimsIdentity(authType); var claimValue = BuildClaimValue(claimSources); identity.AddClaim(new Claim("_claim_sources", claimValue, JsonClaimValueTypes.Json, issuer, issuer, identity)); claimValue = BuildClaimValue(claimNames);