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; }
+ }
+ }