diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/SigningKeyValidationResult.cs b/src/Microsoft.IdentityModel.Tokens/Validation/SigningKeyValidationResult.cs new file mode 100644 index 0000000000..6c3905c1cf --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/SigningKeyValidationResult.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Contains the result of validating the used to sign a . + /// The contains a collection of for each step in the token validation. + /// + internal class SigningKeyValidationResult : ValidationResult + { + private Exception? _exception; + + /// + /// Creates an instance of + /// + /// is the security key that was validated successfully. + public SigningKeyValidationResult(SecurityKey? signingKey) + : base(ValidationFailureType.ValidationSucceeded) + { + SigningKey = signingKey; + IsValid = true; + } + + /// + /// Creates an instance of + /// + /// is the security key that was intended to be validated. + /// is the that occurred during validation. + /// is the that occurred during validation. + public SigningKeyValidationResult(SecurityKey? signingKey, ValidationFailureType validationFailure, ExceptionDetail exceptionDetail) + : base(validationFailure, exceptionDetail) + { + SigningKey = signingKey; + IsValid = false; + } + + /// + /// Gets the that occurred during validation. + /// + public override Exception? Exception + { + get + { + if (_exception != null || ExceptionDetail == null) + return _exception; + + HasValidOrExceptionWasRead = true; + _exception = ExceptionDetail.GetException(); + if (_exception is SecurityTokenInvalidSigningKeyException securityTokenInvalidSigningKeyException) + { + securityTokenInvalidSigningKeyException.SigningKey = SigningKey; + securityTokenInvalidSigningKeyException.ExceptionDetail = ExceptionDetail; + securityTokenInvalidSigningKeyException.Source = "Microsoft.IdentityModel.Tokens"; + } + + return _exception; + } + } + + /// + /// Gets the security key that was validated or intended to be validated. + /// + public SecurityKey? SigningKey { get; } + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs index 3c4a2ec3b8..11a9f7c482 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs @@ -39,6 +39,12 @@ private class IssuerValidationFailure : ValidationFailureType { internal IssuerV public static readonly ValidationFailureType AudienceValidationFailed = new AudienceValidationFailure("AudienceValidationFailed"); private class AudienceValidationFailure : ValidationFailureType { internal AudienceValidationFailure(string name) : base(name) { } } + /// + /// Defines a type that represents that signing key validation failed. + /// + public static readonly ValidationFailureType SigningKeyValidationFailed = new SigningKeyValidationFailure("SigningKeyValidationFailed"); + private class SigningKeyValidationFailure : ValidationFailureType { internal SigningKeyValidationFailure(string name) : base(name) { } } + /// /// Defines a type that represents that lifetime validation failed. /// diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSecurityKey.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSecurityKey.cs index 1a50cb9d45..e5595a178a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSecurityKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSecurityKey.cs @@ -2,12 +2,37 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; using Microsoft.IdentityModel.Abstractions; using Microsoft.IdentityModel.Logging; +#nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Definition for delegate that will validate the that signed a . + /// + /// The security key to validate. + /// The that is being validated. + /// required for validation. + /// + /// + /// A that contains the results of validating the issuer. + /// This delegate is not expected to throw. + internal delegate Task IssuerSecurityKeyValidationDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + TokenValidationParameters validationParameters, + CallContext callContext, + CancellationToken cancellationToken); + + /// + /// SigningKeyValidation + /// + public static partial class Validators { /// @@ -21,7 +46,7 @@ public static partial class Validators /// if 'validationParameters' is null. public static void ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters) { - ValidateIssuerSecurityKey(securityKey, securityToken, validationParameters, null); + ValidateIssuerSecurityKey(securityKey, securityToken, validationParameters, configuration: null); } /// @@ -34,7 +59,7 @@ public static void ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityTo /// if 'securityKey' is null and ValidateIssuerSigningKey is true. /// if 'securityToken' is null and ValidateIssuerSigningKey is true. /// if 'validationParameters' is null. - internal static void ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration configuration) + internal static void ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration? configuration) { if (validationParameters == null) throw LogHelper.LogArgumentNullException(nameof(validationParameters)); @@ -84,7 +109,7 @@ internal static void ValidateIssuerSecurityKey(SecurityKey securityKey, Security /// The that are used to validate the token. internal static void ValidateIssuerSigningKeyLifeTime(SecurityKey securityKey, TokenValidationParameters validationParameters) { - X509SecurityKey x509SecurityKey = securityKey as X509SecurityKey; + X509SecurityKey? x509SecurityKey = securityKey as X509SecurityKey; if (x509SecurityKey?.Certificate is X509Certificate2 cert) { DateTime utcNow = DateTime.UtcNow; @@ -104,5 +129,186 @@ internal static void ValidateIssuerSigningKeyLifeTime(SecurityKey securityKey, T LogHelper.LogInformation(LogMessages.IDX10251, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow)); } } + + /// + /// Validates the that signed a . + /// + /// The that signed the . + /// The being validated. + /// required for validation. + /// + /// if 'securityKey' is null and ValidateIssuerSigningKey is true. + /// if 'securityToken' is null and ValidateIssuerSigningKey is true. + /// if 'validationParameters' is null. + internal static SigningKeyValidationResult ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters, CallContext callContext) + { + return ValidateIssuerSecurityKey(securityKey, securityToken, validationParameters, null, callContext); + } + + /// + /// Validates the that signed a . + /// + /// The that signed the . + /// The being validated. + /// required for validation. + /// The required for issuer and signing key validation. + /// + /// if 'securityKey' is null and ValidateIssuerSigningKey is true. + /// if 'securityToken' is null and ValidateIssuerSigningKey is true. + /// if 'validationParameters' is null. + internal static SigningKeyValidationResult ValidateIssuerSecurityKey(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration? configuration, CallContext callContext) + { + if (validationParameters == null) + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10000, + LogHelper.MarkAsNonPII(nameof(validationParameters))), + typeof(ArgumentNullException), + new StackFrame(true))); + + if (validationParameters.IssuerSigningKeyValidatorUsingConfiguration != null) + { + return ValidateSigningKeyUsingDelegateAndConfiguration(securityKey, securityToken, validationParameters, configuration); + } + + if (validationParameters.IssuerSigningKeyValidator != null) + { + return ValidateSigningKeyUsingDelegateAndConfiguration(securityKey, securityToken, validationParameters, null); + } + + if (!validationParameters.ValidateIssuerSigningKey) + { + LogHelper.LogVerbose(LogMessages.IDX10237); + return new SigningKeyValidationResult(securityKey); + } + + if (!validationParameters.RequireSignedTokens && securityKey == null) + { + LogHelper.LogInformation(LogMessages.IDX10252); + return new SigningKeyValidationResult(securityKey); + } + else if (securityKey == null) + { + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10253, + LogHelper.MarkAsNonPII(nameof(securityKey))), + typeof(ArgumentNullException), + new StackFrame(true))); + } + + if (securityToken == null) + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10000, + LogHelper.MarkAsNonPII(nameof(securityToken))), + typeof(ArgumentNullException), + new StackFrame(true))); + + return ValidateIssuerSigningKeyLifeTime(securityKey, validationParameters, callContext); + } + + /// + /// Given a signing key, when it's derived from a certificate, validates that the certificate is already active and non-expired + /// + /// The that signed the . + /// The that are used to validate the token. + /// +#pragma warning disable CA1801 // Review unused parameters + internal static SigningKeyValidationResult ValidateIssuerSigningKeyLifeTime(SecurityKey securityKey, TokenValidationParameters validationParameters, CallContext callContext) +#pragma warning restore CA1801 // Review unused parameters + { + X509SecurityKey? x509SecurityKey = securityKey as X509SecurityKey; + if (x509SecurityKey?.Certificate is X509Certificate2 cert) + { + DateTime utcNow = DateTime.UtcNow; + var notBeforeUtc = cert.NotBefore.ToUniversalTime(); + var notAfterUtc = cert.NotAfter.ToUniversalTime(); + + if (notBeforeUtc > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)) + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogHelper.FormatInvariant( + LogMessages.IDX10248, + LogHelper.MarkAsNonPII(notBeforeUtc), + LogHelper.MarkAsNonPII(utcNow))), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))); + + if (LogHelper.IsEnabled(EventLogLevel.Informational)) + LogHelper.LogInformation(LogMessages.IDX10250, LogHelper.MarkAsNonPII(notBeforeUtc), LogHelper.MarkAsNonPII(utcNow)); + + if (notAfterUtc < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate())) + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogHelper.FormatInvariant( + LogMessages.IDX10249, + LogHelper.MarkAsNonPII(notAfterUtc), + LogHelper.MarkAsNonPII(utcNow))), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))); + + if (LogHelper.IsEnabled(EventLogLevel.Informational)) + LogHelper.LogInformation(LogMessages.IDX10251, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow)); + } + + return new SigningKeyValidationResult(securityKey); + } + + private static SigningKeyValidationResult ValidateSigningKeyUsingDelegateAndConfiguration(SecurityKey securityKey, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration? configuration) + { + try + { + bool success; + if (configuration != null) + success = validationParameters.IssuerSigningKeyValidatorUsingConfiguration(securityKey, securityToken, validationParameters, configuration); + else + success = validationParameters.IssuerSigningKeyValidator(securityKey, securityToken, validationParameters); + + if (!success) + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + securityKey), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))); + + return new SigningKeyValidationResult(securityKey); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception exception) +#pragma warning restore CA1031 // Do not catch general exception types + { + return new SigningKeyValidationResult( + securityKey, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + securityKey), + exception.GetType(), + new StackFrame(true), + exception)); + } + } } } +#nullable restore diff --git a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs index d6955070f7..1644fa856b 100644 --- a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs +++ b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs @@ -673,6 +673,71 @@ internal static bool AreAudienceValidationResultsEqual( return context.Merge(localContext); } + public static bool AreSigningKeyValidationResultsEqual(object object1, object object2, CompareContext context) + { + var localContext = new CompareContext(context); + if (!ContinueCheckingEquality(object1, object2, context)) + return context.Merge(localContext); + + return AreSigningKeyValidationResultsEqual( + object1 as SigningKeyValidationResult, + object2 as SigningKeyValidationResult, + "SigningKeyValidationResult1", + "SigningKeyValidationResult2", + null, + context); + } + + internal static bool AreSigningKeyValidationResultsEqual( + SigningKeyValidationResult signingKeyValidationResult1, + SigningKeyValidationResult signingKeyValidationResult2, + string name1, + string name2, + string stackPrefix, + CompareContext context) + { + var localContext = new CompareContext(context); + AreSecurityKeysEqual(signingKeyValidationResult1.SigningKey, signingKeyValidationResult2.SigningKey, localContext); + + if (!ContinueCheckingEquality(signingKeyValidationResult1, signingKeyValidationResult2, localContext)) + return context.Merge(localContext); + + if (signingKeyValidationResult1.IsValid != signingKeyValidationResult2.IsValid) + localContext.Diffs.Add($"SigningKeyValidationResult1.IsValid: {signingKeyValidationResult2.IsValid} != SigningKeyValidationResult2.IsValid: {signingKeyValidationResult2.IsValid}"); + + if (signingKeyValidationResult1.ValidationFailureType != signingKeyValidationResult2.ValidationFailureType) + localContext.Diffs.Add($"SigningKeyValidationResult1.ValidationFailureType: {signingKeyValidationResult1.ValidationFailureType} != SigningKeyValidationResult2.ValidationFailureType: {signingKeyValidationResult2.ValidationFailureType}"); + + // true => both are not null. + if (ContinueCheckingEquality(signingKeyValidationResult1.Exception, signingKeyValidationResult2.Exception, localContext)) + { + AreStringsEqual( + signingKeyValidationResult1.Exception.Message, + signingKeyValidationResult2.Exception.Message, + $"({name1})signingKeyValidationResult1.Exception.Message", + $"({name2})signingKeyValidationResult2.Exception.Message", + localContext); + + AreStringsEqual( + signingKeyValidationResult1.Exception.Source, + signingKeyValidationResult2.Exception.Source, + $"({name1})signingKeyValidationResult1.Exception.Source", + $"({name2})signingKeyValidationResult2.Exception.Source", + localContext); + + if (!string.IsNullOrEmpty(stackPrefix)) + AreStringPrefixesEqual( + signingKeyValidationResult1.Exception.StackTrace.Trim(), + signingKeyValidationResult2.Exception.StackTrace.Trim(), + $"({name1})signingKeyValidationResult1.Exception.StackTrace", + $"({name2})signingKeyValidationResult2.Exception.StackTrace", + stackPrefix.Trim(), + localContext); + } + + return context.Merge(localContext); + } + public static bool AreLifetimeValidationResultsEqual(object object1, object object2, CompareContext context) { var localContext = new CompareContext(context); diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/SigningKeyValidationResultTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/SigningKeyValidationResultTests.cs new file mode 100644 index 0000000000..43a6d3e313 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/SigningKeyValidationResultTests.cs @@ -0,0 +1,333 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using Microsoft.IdentityModel.TestUtils; +using Xunit; + +namespace Microsoft.IdentityModel.Tokens.Validation.Tests +{ + public class SigningKeyValidationResultTests + { + [Theory, MemberData(nameof(SigningKeyValidationTestCases), DisableDiscoveryEnumeration = true)] + public void SecurityKey(SigningKeyValidationTheoryData theoryData) + { + CompareContext context = TestUtilities.WriteHeader($"{this}.SigningKeyValidationResultTests", theoryData); + + SigningKeyValidationResult signingKeyValidationResult = Validators.ValidateIssuerSecurityKey( + theoryData.SecurityKey, + theoryData.SecurityToken, + theoryData.ValidationParameters, + theoryData.BaseConfiguration, + new CallContext()); + + if (signingKeyValidationResult.Exception != null) + theoryData.ExpectedException.ProcessException(signingKeyValidationResult.Exception); + else + theoryData.ExpectedException.ProcessNoException(); + + IdentityComparer.AreSigningKeyValidationResultsEqual( + signingKeyValidationResult, + theoryData.SigningKeyValidationResult, + context); + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData SigningKeyValidationTestCases + { + get + { + DateTime utcNow = DateTime.UtcNow; + DateTime utcExpired = KeyingMaterial.ExpiredX509SecurityKey_Public.Certificate.NotAfter.ToUniversalTime(); + DateTime utcNotYetValid = KeyingMaterial.NotYetValidX509SecurityKey_Public.Certificate.NotBefore.ToUniversalTime(); + + return new TheoryData + { + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityTokenIsPresent_ValidateIssuerSigningKeyIsTrue", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true }, + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityKeyIsNull_ValidateIssuerSigningKeyIsFalse", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = null, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = false }, + SigningKeyValidationResult = new SigningKeyValidationResult(null) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityTokenIsNull_ValidateIssuerSigningKeyIsFalse", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = null, + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = false }, + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityKeyIsNull_RequireSignedTokensIsFalse", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = null, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, RequireSignedTokens = false }, + SigningKeyValidationResult = new SigningKeyValidationResult(null) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityKeyIsPresent_RequireSignedTokensIsTrue", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, RequireSignedTokens = true }, + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_SecurityKeyIsPresent_RequireSignedTokensIsFalse", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, RequireSignedTokens = false }, + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_DelegateSet_ReturnsTrue", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidator = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters) => true + }, + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Valid_DelegateUsingConfigurationSet_ReturnsTrue", + ExpectedException = ExpectedException.NoExceptionExpected, + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidatorUsingConfiguration = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters, BaseConfiguration configuration) => true + }, + BaseConfiguration = new OpenIdConnectConfiguration(), + SigningKeyValidationResult = new SigningKeyValidationResult(KeyingMaterial.SymmetricSecurityKey2_256) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_SecurityKeyIsNull", + ExpectedException = ExpectedException.ArgumentNullException(substringExpected: "IDX10253:"), + SecurityKey = null, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true }, + SigningKeyValidationResult = new SigningKeyValidationResult( + null, // SecurityKey + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail(LogMessages.IDX10253), + typeof(ArgumentNullException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_SecurityTokenIsNullAndValidateIssuerSigningKeyTrue", + ExpectedException = ExpectedException.ArgumentNullException(), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = null, + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true }, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10000, + LogHelper.MarkAsNonPII("securityToken")), + typeof(ArgumentNullException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_ValidationParametersIsNull", + ExpectedException = ExpectedException.ArgumentNullException(), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = null, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10000, + LogHelper.MarkAsNonPII("validationParameters")), + typeof(ArgumentNullException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_SecurityKeyIsExpired", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10249:"), + SecurityKey = KeyingMaterial.ExpiredX509SecurityKey_Public, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true }, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.ExpiredX509SecurityKey_Public, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10249, + LogHelper.MarkAsNonPII(utcExpired), + LogHelper.MarkAsNonPII(utcNow)), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_SecurityKeyIsNotYetValid", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10248:"), + SecurityKey = KeyingMaterial.NotYetValidX509SecurityKey_Public, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true }, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.NotYetValidX509SecurityKey_Public, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10248, + LogHelper.MarkAsNonPII(utcNotYetValid), + LogHelper.MarkAsNonPII(utcNow)), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_SecurityKeyIsNull_RequireSignedTokensIsTrue", + ExpectedException = ExpectedException.ArgumentNullException(substringExpected: "IDX10253:"), + SecurityKey = null, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, RequireSignedTokens = true }, + SigningKeyValidationResult = new SigningKeyValidationResult( + null, + ValidationFailureType.NullArgument, + new ExceptionDetail( + new MessageDetail(LogMessages.IDX10253), + typeof(ArgumentNullException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_DelegateIsSet_ReturnsFalse", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10232:"), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidator = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters) => false + }, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + KeyingMaterial.SymmetricSecurityKey2_256), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_DelegateUsingConfigurationSet_ReturnsFalse", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10232:"), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidatorUsingConfiguration = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters, BaseConfiguration configuration) => false + }, + BaseConfiguration = new OpenIdConnectConfiguration(), + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + KeyingMaterial.SymmetricSecurityKey2_256), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true))) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_DelegateIsSet_Throws", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10232:", innerTypeExpected: typeof(SecurityTokenInvalidSigningKeyException)), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidator = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters) => throw new SecurityTokenInvalidSigningKeyException() + }, + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + KeyingMaterial.SymmetricSecurityKey2_256), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true), + new SecurityTokenInvalidSigningKeyException())) + }, + new SigningKeyValidationTheoryData + { + TestId = "Invalid_DelegateUsingConfigurationSet_Throws", + ExpectedException = ExpectedException.SecurityTokenInvalidSigningKeyException(substringExpected: "IDX10232:", innerTypeExpected: typeof(SecurityTokenInvalidSigningKeyException)), + SecurityKey = KeyingMaterial.SymmetricSecurityKey2_256, + SecurityToken = new JwtSecurityToken(), + ValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKeyValidatorUsingConfiguration = (SecurityKey securityKey, SecurityToken token, TokenValidationParameters validationParameters, BaseConfiguration configuration) => throw new SecurityTokenInvalidSigningKeyException() + }, + BaseConfiguration = new OpenIdConnectConfiguration(), + SigningKeyValidationResult = new SigningKeyValidationResult( + KeyingMaterial.SymmetricSecurityKey2_256, + ValidationFailureType.SigningKeyValidationFailed, + new ExceptionDetail( + new MessageDetail( + LogMessages.IDX10232, + KeyingMaterial.SymmetricSecurityKey2_256), + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame(true), + new SecurityTokenInvalidSigningKeyException())) + }, + }; + } + } + } + + public class SigningKeyValidationTheoryData: TheoryDataBase + { + public SecurityKey SecurityKey { get; set; } + public SecurityToken SecurityToken { get; set; } + public TokenValidationParameters ValidationParameters { get; set; } + public BaseConfiguration BaseConfiguration { get; set; } + internal SigningKeyValidationResult SigningKeyValidationResult { get; set; } + } + }