Skip to content

Commit 55ad3e3

Browse files
committed
Add tests.
1 parent e5bbdca commit 55ad3e3

File tree

5 files changed

+119
-70
lines changed

5 files changed

+119
-70
lines changed

src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.CreateToken.cs

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,60 +1335,62 @@ internal IEnumerable<SecurityKey> GetContentEncryptionKeys(JsonWebToken jwtToken
13351335
// keep track of exceptions thrown, keys that were tried
13361336
StringBuilder exceptionStrings = null;
13371337
StringBuilder keysAttempted = null;
1338-
foreach (var key in keys)
1338+
if (keys != null)
13391339
{
1340-
try
1340+
foreach (var key in keys)
13411341
{
1342-
#if NET472 || NET6_0_OR_GREATER
1343-
if (SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(jwtToken.Alg))
1342+
try
13441343
{
1345-
ECDsaSecurityKey publicKey;
1346-
1347-
// Since developers may have already worked around this issue, implicitly taking a dependency on the
1348-
// old behavior, we guard the new behavior behind an AppContext switch. The new/RFC-conforming behavior
1349-
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
1350-
// (such as the next major version update) we should consider whether or not this app-compat switch
1351-
// needs to be maintained.
1352-
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
1344+
#if NET472 || NET6_0_OR_GREATER
1345+
if (SupportedAlgorithms.EcdsaWrapAlgorithms.Contains(jwtToken.Alg))
13531346
{
1354-
// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C
1355-
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Epk, out string epk);
1356-
publicKey = new ECDsaSecurityKey(new JsonWebKey(epk), false);
1347+
ECDsaSecurityKey publicKey;
1348+
1349+
// Since developers may have already worked around this issue, implicitly taking a dependency on the
1350+
// old behavior, we guard the new behavior behind an AppContext switch. The new/RFC-conforming behavior
1351+
// is treated as opt-in. When the library is at the point where it is able to make breaking changes
1352+
// (such as the next major version update) we should consider whether or not this app-compat switch
1353+
// needs to be maintained.
1354+
if (AppContextSwitches.UseRfcDefinitionOfEpkAndKid)
1355+
{
1356+
// on decryption we get the public key from the EPK value see: https://datatracker.ietf.org/doc/html/rfc7518#appendix-C
1357+
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Epk, out string epk);
1358+
publicKey = new ECDsaSecurityKey(new JsonWebKey(epk), false);
1359+
}
1360+
else
1361+
{
1362+
publicKey = validationParameters.TokenDecryptionKey as ECDsaSecurityKey;
1363+
}
1364+
1365+
var ecdhKeyExchangeProvider = new EcdhKeyExchangeProvider(
1366+
key as ECDsaSecurityKey,
1367+
publicKey,
1368+
jwtToken.Alg,
1369+
jwtToken.Enc);
1370+
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apu, out string apu);
1371+
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apv, out string apv);
1372+
SecurityKey kdf = ecdhKeyExchangeProvider.GenerateKdf(apu, apv);
1373+
var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(kdf, ecdhKeyExchangeProvider.GetEncryptionAlgorithm());
1374+
var unwrappedKey = kwp.UnwrapKey(Base64UrlEncoder.DecodeBytes(jwtToken.EncryptedKey));
1375+
unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey));
13571376
}
13581377
else
1378+
#endif
1379+
if (key.CryptoProviderFactory.IsSupportedAlgorithm(jwtToken.Alg, key))
13591380
{
1360-
publicKey = validationParameters.TokenDecryptionKey as ECDsaSecurityKey;
1381+
var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(key, jwtToken.Alg);
1382+
var unwrappedKey = kwp.UnwrapKey(jwtToken.EncryptedKeyBytes);
1383+
unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey));
13611384
}
1362-
1363-
var ecdhKeyExchangeProvider = new EcdhKeyExchangeProvider(
1364-
key as ECDsaSecurityKey,
1365-
publicKey,
1366-
jwtToken.Alg,
1367-
jwtToken.Enc);
1368-
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apu, out string apu);
1369-
jwtToken.TryGetHeaderValue(JwtHeaderParameterNames.Apv, out string apv);
1370-
SecurityKey kdf = ecdhKeyExchangeProvider.GenerateKdf(apu, apv);
1371-
var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(kdf, ecdhKeyExchangeProvider.GetEncryptionAlgorithm());
1372-
var unwrappedKey = kwp.UnwrapKey(Base64UrlEncoder.DecodeBytes(jwtToken.EncryptedKey));
1373-
unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey));
13741385
}
1375-
else
1376-
#endif
1377-
if (key.CryptoProviderFactory.IsSupportedAlgorithm(jwtToken.Alg, key))
1386+
catch (Exception ex)
13781387
{
1379-
var kwp = key.CryptoProviderFactory.CreateKeyWrapProviderForUnwrap(key, jwtToken.Alg);
1380-
var unwrappedKey = kwp.UnwrapKey(jwtToken.EncryptedKeyBytes);
1381-
unwrappedKeys.Add(new SymmetricSecurityKey(unwrappedKey));
1388+
(exceptionStrings ??= new StringBuilder()).AppendLine(ex.ToString());
13821389
}
1383-
}
1384-
catch (Exception ex)
1385-
{
1386-
(exceptionStrings ??= new StringBuilder()).AppendLine(ex.ToString());
1387-
}
13881390

1389-
(keysAttempted ??= new StringBuilder()).AppendLine(key.KeyId);
1391+
(keysAttempted ??= new StringBuilder()).AppendLine(key.KeyId);
1392+
}
13901393
}
1391-
13921394
if (unwrappedKeys.Count > 0 || exceptionStrings is null)
13931395
return unwrappedKeys;
13941396
else

src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ protected TokenValidationParameters(TokenValidationParameters other)
8989
TokenReplayCache = other.TokenReplayCache;
9090
TokenReplayValidator = other.TokenReplayValidator;
9191
TransformBeforeSignatureValidation = other.TransformBeforeSignatureValidation;
92+
TryAllDecryptionKeys = other.TryAllDecryptionKeys;
9293
TryAllIssuerSigningKeys = other.TryAllIssuerSigningKeys;
9394
TypeValidator = other.TypeValidator;
9495
ValidateActor = other.ValidateActor;
@@ -118,6 +119,7 @@ public TokenValidationParameters()
118119
RequireSignedTokens = true;
119120
RequireAudience = true;
120121
SaveSigninToken = false;
122+
TryAllDecryptionKeys = true;
121123
TryAllIssuerSigningKeys = true;
122124
ValidateActor = false;
123125
ValidateAudience = true;

src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ protected ValidationParameters(ValidationParameters other)
9292
SaveSigninToken = other.SaveSigninToken;
9393
_signatureValidator = other.SignatureValidator;
9494
TimeProvider = other.TimeProvider;
95+
TryAllDecryptionKeys = other.TryAllDecryptionKeys;
9596
TokenDecryptionKeyResolver = other.TokenDecryptionKeyResolver;
9697
_tokenDecryptionKeys = other.TokenDecryptionKeys;
9798
TokenReplayCache = other.TokenReplayCache;
@@ -112,6 +113,7 @@ public ValidationParameters()
112113
{
113114
LogTokenId = true;
114115
SaveSigninToken = false;
116+
TryAllDecryptionKeys = true;
115117
ValidateActor = false;
116118
}
117119

test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ public void GetEncryptionKeys(CreateTokenTheoryData theoryData)
672672
var jwtTokenFromJsonHandlerWithKid = new JsonWebToken(jweFromJsonHandlerWithKid);
673673
var encryptionKeysFromJsonHandlerWithKid = theoryData.JsonWebTokenHandler.GetContentEncryptionKeys(jwtTokenFromJsonHandlerWithKid, theoryData.ValidationParameters, theoryData.Configuration);
674674

675-
IdentityComparer.AreEqual(encryptionKeysFromJsonHandlerWithKid, theoryData.ExpectedDecryptionKeys);
675+
Assert.True(IdentityComparer.AreEqual(encryptionKeysFromJsonHandlerWithKid, theoryData.ExpectedDecryptionKeys));
676676
theoryData.ExpectedException.ProcessNoException(context);
677677
}
678678
catch (Exception ex)
@@ -696,15 +696,19 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
696696
configurationWithDecryptionKeys.TokenDecryptionKeys.Add(KeyingMaterial.DefaultSymmetricSecurityKey_256);
697697
configurationWithDecryptionKeys.TokenDecryptionKeys.Add(KeyingMaterial.DefaultSymmetricSecurityKey_512);
698698

699-
var configurationThatThrows = CreateCustomConfigurationThatThrows();
699+
var rsaKey = new RsaSecurityKey(KeyingMaterial.RsaParameters_2048) { KeyId = "CustomRsaSecurityKey_2048" };
700+
var configurationThatThrows = CreateCustomConfigurationThatThrows(rsaKey);
701+
702+
var configurationWithMismatchedKeys = new OpenIdConnectConfiguration();
703+
configurationWithMismatchedKeys.TokenDecryptionKeys.Add(rsaKey);
700704

701705
tokenHandler.InboundClaimTypeMap.Clear();
702706
return new TheoryData<CreateTokenTheoryData>
703707
{
704-
new CreateTokenTheoryData
705-
{
708+
new CreateTokenTheoryData
709+
{
706710
First = true,
707-
TestId = "EncryptionKeyInConfig",
711+
TestId = "ValidKeyInConfig_KeysSetInConfig",
708712
Payload = Default.PayloadString,
709713
TokenDescriptor = new SecurityTokenDescriptor
710714
{
@@ -720,10 +724,10 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
720724
},
721725
Configuration = configurationWithDecryptionKeys,
722726
ExpectedDecryptionKeys = new List<SecurityKey>(){ KeyingMaterial.DefaultSymmetricSecurityKey_256 },
723-
},
724-
new CreateTokenTheoryData
725-
{
726-
TestId = "ValidEncryptionKeyInConfig",
727+
},
728+
new CreateTokenTheoryData
729+
{
730+
TestId = "ValidKeyInConfig_KeysSetInConfigAndTvp",
727731
Payload = Default.PayloadString,
728732
TokenDescriptor = new SecurityTokenDescriptor
729733
{
@@ -740,10 +744,10 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
740744
},
741745
Configuration = configurationWithDecryptionKeys,
742746
ExpectedDecryptionKeys = new List<SecurityKey>(){ KeyingMaterial.DefaultSymmetricSecurityKey_256 },
743-
},
744-
new CreateTokenTheoryData
745-
{
746-
TestId = "Valid",
747+
},
748+
new CreateTokenTheoryData
749+
{
750+
TestId = "ValidKeyInTvp_KeysSetInTvp",
747751
Payload = Default.PayloadString,
748752
TokenDescriptor = new SecurityTokenDescriptor
749753
{
@@ -759,10 +763,10 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
759763
ValidIssuer = Default.Issuer
760764
},
761765
ExpectedDecryptionKeys = new List<SecurityKey>(){ KeyingMaterial.DefaultSymmetricSecurityKey_256 },
762-
},
763-
new CreateTokenTheoryData
764-
{
765-
TestId = "AlgorithmMismatch",
766+
},
767+
new CreateTokenTheoryData
768+
{
769+
TestId = "AlgorithmMismatch_ReturnsNoKeys",
766770
Payload = Default.PayloadString,
767771
// There is no error, just no decryption keys are returned.
768772
ExpectedException = ExpectedException.NoExceptionExpected,
@@ -780,10 +784,10 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
780784
ValidAudience = Default.Audience,
781785
ValidIssuer = Default.Issuer
782786
},
783-
},
784-
new CreateTokenTheoryData
785-
{
786-
TestId = "EncryptionKeyInConfig_OneKeysThrows_SuccessfulKeyReturned",
787+
},
788+
new CreateTokenTheoryData
789+
{
790+
TestId = "ValidKeyInConfig_OneKeyThrows_SuccessfulKeyReturned",
787791
Payload = Default.PayloadString,
788792
TokenDescriptor = new SecurityTokenDescriptor
789793
{
@@ -798,13 +802,53 @@ public static TheoryData<CreateTokenTheoryData> SecurityTokenDecryptionTheoryDat
798802
ValidIssuer = Default.Issuer
799803
},
800804
Configuration = configurationThatThrows,
801-
ExpectedDecryptionKeys = new List<SecurityKey>(){ KeyingMaterial.DefaultSymmetricSecurityKey_256 },
802-
}
805+
ExpectedDecryptionKeys = new List<SecurityKey>(){ rsaKey },
806+
},
807+
new CreateTokenTheoryData
808+
{
809+
TestId = "KeyIdMismatch_TryAllDecryptionKeysTrue_ReturnsKey",
810+
Payload = Default.PayloadString,
811+
TokenDescriptor = new SecurityTokenDescriptor
812+
{
813+
SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
814+
EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256),
815+
Claims = Default.PayloadDictionary
816+
},
817+
ValidationParameters = new TokenValidationParameters
818+
{
819+
IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
820+
TryAllDecryptionKeys = true,
821+
ValidAudience = Default.Audience,
822+
ValidIssuer = Default.Issuer
823+
},
824+
Configuration = configurationWithMismatchedKeys,
825+
ExpectedDecryptionKeys = new List<SecurityKey>(){ rsaKey },
826+
},
827+
new CreateTokenTheoryData
828+
{
829+
TestId = "KeyIdMismatch_TryAllDecryptionKeysFalse_ReturnsNoKeys",
830+
Payload = Default.PayloadString,
831+
TokenDescriptor = new SecurityTokenDescriptor
832+
{
833+
SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
834+
EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256),
835+
Claims = Default.PayloadDictionary
836+
},
837+
ValidationParameters = new TokenValidationParameters
838+
{
839+
IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
840+
TryAllDecryptionKeys = false,
841+
ValidAudience = Default.Audience,
842+
ValidIssuer = Default.Issuer
843+
},
844+
Configuration = configurationWithMismatchedKeys,
845+
ExpectedDecryptionKeys = new List<SecurityKey>(),
846+
}
803847
};
804848
}
805849
}
806850

807-
private static OpenIdConnectConfiguration CreateCustomConfigurationThatThrows()
851+
private static OpenIdConnectConfiguration CreateCustomConfigurationThatThrows(SecurityKey rsaKey)
808852
{
809853
var customCryptoProviderFactory = new DerivedCryptoProviderFactory
810854
{
@@ -815,8 +859,6 @@ private static OpenIdConnectConfiguration CreateCustomConfigurationThatThrows()
815859
var sym512Hey = new SymmetricSecurityKey(KeyingMaterial.DefaultSymmetricKeyBytes_512) { KeyId = "CustomSymmetricSecurityKey_512" };
816860
sym512Hey.CryptoProviderFactory = customCryptoProviderFactory;
817861

818-
var rsaKey = new RsaSecurityKey(KeyingMaterial.RsaParameters_2048) { KeyId = "CustomRsaSecurityKey_2048" };
819-
820862
var configurationWithCustomCryptoProviderFactory = new OpenIdConnectConfiguration();
821863
configurationWithCustomCryptoProviderFactory.TokenDecryptionKeys.Add(rsaKey);
822864
configurationWithCustomCryptoProviderFactory.TokenDecryptionKeys.Add(sym512Hey);

0 commit comments

Comments
 (0)