diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index 39b501df24..2deb10bafd 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -383,13 +383,27 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext, return signatureValidationResult.UnwrapError().AddStackFrame(signatureValidationFailureStackFrame); } - ValidationResult issuerSigningKeyValidationResult = - validationParameters.IssuerSigningKeyValidator( + ValidationResult issuerSigningKeyValidationResult; + + try + { + issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator( jsonWebToken.SigningKey, jsonWebToken, validationParameters, configuration, callContext); - if (!issuerSigningKeyValidationResult.IsValid) + + if (!issuerSigningKeyValidationResult.IsValid) + return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types { - StackFrame issuerSigningKeyValidationFailureStackFrame = StackFrames.IssuerSigningKeyValidationFailed ??= new StackFrame(true); - return issuerSigningKeyValidationResult.UnwrapError().AddStackFrame(issuerSigningKeyValidationFailureStackFrame); + return new IssuerSigningKeyValidationError( + new MessageDetail(TokenLogMessages.IDX10274), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + jsonWebToken.SigningKey, + ex); } return new ValidatedToken(jsonWebToken, this, validationParameters) diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs index 3ba8835e1f..c6b14409c2 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs @@ -125,15 +125,32 @@ internal async Task> ValidateTokenAsync( return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed); } - ValidationResult issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator( - samlToken.SigningKey, - samlToken, - validationParameters, - null, - callContext); + ValidationResult issuerSigningKeyValidationResult; + + try + { + issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator( + samlToken.SigningKey, + samlToken, + validationParameters, + null, + callContext); - if (!issuerSigningKeyValidationResult.IsValid) - return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame(); + if (!issuerSigningKeyValidationResult.IsValid) + return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + return new IssuerSigningKeyValidationError( + new MessageDetail(Tokens.LogMessages.IDX10274), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + samlToken.SigningKey, + ex); + } return new ValidatedToken(samlToken, this, validationParameters); } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs index 4df576ab59..8da07673ef 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs @@ -128,17 +128,31 @@ internal async Task> ValidateTokenAsync( return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed); } - var issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator( - samlToken.SigningKey, - samlToken, - validationParameters, - null, - callContext); + ValidationResult issuerSigningKeyValidationResult; - if (!issuerSigningKeyValidationResult.IsValid) + try { - StackFrames.IssuerSigningKeyValidationFailed ??= new StackFrame(true); - return issuerSigningKeyValidationResult.UnwrapError().AddStackFrame(StackFrames.IssuerSigningKeyValidationFailed); + issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator( + samlToken.SigningKey, + samlToken, + validationParameters, + null, + callContext); + + if (!issuerSigningKeyValidationResult.IsValid) + return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + return new IssuerSigningKeyValidationError( + new MessageDetail(Tokens.LogMessages.IDX10274), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + samlToken.SigningKey, + ex); } return new ValidatedToken(samlToken, this, validationParameters); diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 517ca0ead9..c81cb4212e 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -9,11 +9,15 @@ const Microsoft.IdentityModel.Tokens.LogMessages.IDX10276 = "IDX10276: TokenRepl Microsoft.IdentityModel.Tokens.AlgorithmValidationError Microsoft.IdentityModel.Tokens.AlgorithmValidationError.AlgorithmValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidAlgorithm, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.AlgorithmValidationError.InvalidAlgorithm.get -> string +Microsoft.IdentityModel.Tokens.AlgorithmValidationError._invalidAlgorithm -> string Microsoft.IdentityModel.Tokens.AudienceValidationError.AudienceValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Collections.Generic.IList tokenAudiences, System.Collections.Generic.IList validAudiences, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.AudienceValidationError.TokenAudiences.get -> System.Collections.Generic.IList Microsoft.IdentityModel.Tokens.AudienceValidationError.TokenAudiences.set -> void Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidAudiences.get -> System.Collections.Generic.IList Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidAudiences.set -> void +Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError +Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.InvalidSigningKey.get -> Microsoft.IdentityModel.Tokens.SecurityKey +Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.IssuerSigningKeyValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, Microsoft.IdentityModel.Tokens.SecurityKey invalidSigningKey, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.IssuerValidationError.InvalidIssuer.get -> string Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration = 1 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource @@ -39,16 +43,18 @@ Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> Sys Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void Microsoft.IdentityModel.Tokens.ValidationError.AddCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> Microsoft.IdentityModel.Tokens.ValidationError Microsoft.IdentityModel.Tokens.ValidationError.GetException(System.Type exceptionType, System.Exception innerException) -> System.Exception -Microsoft.IdentityModel.Tokens.ValidationError.ValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType failureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void +Microsoft.IdentityModel.Tokens.ValidationError.ValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationDelegate Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.set -> void Microsoft.IdentityModel.Tokens.ValidationResult.Error.get -> Microsoft.IdentityModel.Tokens.ValidationError Microsoft.IdentityModel.Tokens.ValidationResult.IsValid.get -> bool Microsoft.IdentityModel.Tokens.ValidationResult.Result.get -> TResult override Microsoft.IdentityModel.Tokens.AlgorithmValidationError.GetException() -> System.Exception +override Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.GetException() -> System.Exception override Microsoft.IdentityModel.Tokens.SignatureValidationError.GetException() -> System.Exception override Microsoft.IdentityModel.Tokens.TokenReplayValidationError.GetException() -> System.Exception override Microsoft.IdentityModel.Tokens.TokenTypeValidationError.GetException() -> System.Exception +static Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError static Microsoft.IdentityModel.Tokens.SignatureValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.SignatureValidationError static Microsoft.IdentityModel.Tokens.TokenReplayValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenReplayValidationError static Microsoft.IdentityModel.Tokens.TokenTypeValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenTypeValidationError diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 30ce49b65e..02062ddad4 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -90,6 +90,7 @@ internal static class LogMessages public const string IDX10269 = "IDX10269: IssuerValidationDelegate threw an exception, see inner exception."; public const string IDX10272 = "IDX10272: SignatureValidationDelegate threw an exception, see inner exception."; public const string IDX10273 = "IDX10273: AlgorithmValidationDelegate threw an exception, see inner exception."; + public const string IDX10274 = "IDX10274: IssuerSigningKeyValidationDelegate threw an exception, see inner exception."; public const string IDX10275 = "IDX10275: TokenTypeValidationDelegate threw an exception, see inner exception."; public const string IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception."; diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs new file mode 100644 index 0000000000..8f380847ae --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics; +using System; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + internal class IssuerSigningKeyValidationError : ValidationError + { + internal IssuerSigningKeyValidationError( + MessageDetail messageDetail, + ValidationFailureType validationFailureType, + Type exceptionType, + StackFrame stackFrame, + SecurityKey? invalidSigningKey, + Exception? innerException = null) + : base(messageDetail, validationFailureType, exceptionType, stackFrame, innerException) + { + InvalidSigningKey = invalidSigningKey; + } + + internal override Exception GetException() + { + if (ExceptionType == typeof(SecurityTokenInvalidSigningKeyException)) + { + SecurityTokenInvalidSigningKeyException? exception = new(MessageDetail.Message, InnerException) + { + SigningKey = InvalidSigningKey + }; + exception.SetValidationError(this); + + return exception; + } + + return base.GetException(); + } + + internal static new IssuerSigningKeyValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + MessageDetail.NullParameter(parameterName), + ValidationFailureType.NullArgument, + typeof(SecurityTokenArgumentNullException), + stackFrame, + null); // InvalidSigningKey + + protected SecurityKey? InvalidSigningKey { get; } + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs index 5347e72d65..fb8481d1ac 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs @@ -22,13 +22,13 @@ internal class ValidationError /// Creates an instance of /// /// contains information about the exception that is used to generate the exception message. - /// is the type of validation failure that occurred. + /// is the type of validation failure that occurred. /// is the type of exception that occurred. /// is the stack frame where the exception occurred. /// is the inner exception that occurred. internal ValidationError( MessageDetail messageDetail, - ValidationFailureType failureType, + ValidationFailureType validationFailureType, Type exceptionType, StackFrame stackFrame, Exception? innerException = null) @@ -36,7 +36,7 @@ internal ValidationError( InnerException = innerException; MessageDetail = messageDetail; _exceptionType = exceptionType; - FailureType = failureType; + FailureType = validationFailureType; StackFrames = new List(4) { stackFrame diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs index 9ee917bdf9..f20011641c 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs @@ -84,8 +84,8 @@ private class SignatureAlgorithmValidationFailure : ValidationFailureType { inte /// /// 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) { } } + public static readonly ValidationFailureType SigningKeyValidationFailed = new IssuerSigningKeyValidationFailure("IssuerSigningKeyValidationFailed"); + private class IssuerSigningKeyValidationFailure : ValidationFailureType { internal IssuerSigningKeyValidationFailure(string name) : base(name) { } } /// /// Defines a type that represents that lifetime validation failed. @@ -140,6 +140,11 @@ private class XmlValidationFailure : ValidationFailureType { internal XmlValidat public static readonly ValidationFailureType IssuerValidatorThrew = new IssuerValidatorFailure("IssuerValidatorThrew"); private class IssuerValidatorFailure : ValidationFailureType { internal IssuerValidatorFailure(string name) : base(name) { } } + /// + /// Defines a type that represents the fact that the issuer signing key validation delegate threw an exception. + /// + public static readonly ValidationFailureType IssuerSigningKeyValidatorThrew = new IssuerSigningKeyValidationFailure("IssuerSigningKeyValidatorThrew"); + /// /// Defines a type that represents the fact that the signature validation delegate threw an exception. /// diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs index 3e27f653e4..6e4ef95132 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; using System.Security.Cryptography.X509Certificates; using Microsoft.IdentityModel.Logging; @@ -26,7 +25,7 @@ internal delegate ValidationResult IssuerSigningKey SecurityToken securityToken, ValidationParameters validationParameters, BaseConfiguration? configuration, - CallContext? callContext); + CallContext callContext); /// /// SigningKeyValidation @@ -55,21 +54,22 @@ internal static ValidationResult ValidateIssuerSign CallContext? callContext) { if (validationParameters == null) - return ValidationError.NullParameter( + return IssuerSigningKeyValidationError.NullParameter( nameof(validationParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); if (securityKey == null) - return new ValidationError( + return new IssuerSigningKeyValidationError( new MessageDetail(LogMessages.IDX10253, nameof(securityKey)), ValidationFailureType.SigningKeyValidationFailed, typeof(SecurityTokenArgumentNullException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + securityKey); if (securityToken == null) - return ValidationError.NullParameter( + return IssuerSigningKeyValidationError.NullParameter( nameof(securityToken), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); return ValidateIssuerSigningKeyLifeTime(securityKey, validationParameters, callContext); } @@ -98,28 +98,30 @@ internal static ValidationResult ValidateIssuerSign notAfterUtc = cert.NotAfter.ToUniversalTime(); if (notBeforeUtc > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)) - return new ValidationError( + return new IssuerSigningKeyValidationError( new MessageDetail( LogMessages.IDX10248, LogHelper.MarkAsNonPII(notBeforeUtc), LogHelper.MarkAsNonPII(utcNow)), ValidationFailureType.SigningKeyValidationFailed, typeof(SecurityTokenInvalidSigningKeyException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + securityKey); //TODO: Move to CallContext //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 ValidationError( + return new IssuerSigningKeyValidationError( new MessageDetail( LogMessages.IDX10249, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow)), ValidationFailureType.SigningKeyValidationFailed, typeof(SecurityTokenInvalidSigningKeyException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + securityKey); // TODO: Move to CallContext //if (LogHelper.IsEnabled(EventLogLevel.Informational)) diff --git a/src/Microsoft.IdentityModel.Tokens/Validators.cs b/src/Microsoft.IdentityModel.Tokens/Validators.cs index 157588bd51..49946550cd 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validators.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validators.cs @@ -409,13 +409,13 @@ internal static void ValidateIssuerSigningKeyLifeTime(SecurityKey securityKey, T var notAfterUtc = cert.NotAfter.ToUniversalTime(); if (notBeforeUtc > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew)) - throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSigningKeyException(LogHelper.FormatInvariant(LogMessages.IDX10248, LogHelper.MarkAsNonPII(notBeforeUtc), LogHelper.MarkAsNonPII(utcNow)))); + throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSigningKeyException(LogHelper.FormatInvariant(LogMessages.IDX10248, LogHelper.MarkAsNonPII(notBeforeUtc), LogHelper.MarkAsNonPII(utcNow))) { SigningKey = securityKey }); if (LogHelper.IsEnabled(EventLogLevel.Informational)) LogHelper.LogInformation(LogMessages.IDX10250, LogHelper.MarkAsNonPII(notBeforeUtc), LogHelper.MarkAsNonPII(utcNow)); if (notAfterUtc < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate())) - throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSigningKeyException(LogHelper.FormatInvariant(LogMessages.IDX10249, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow)))); + throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSigningKeyException(LogHelper.FormatInvariant(LogMessages.IDX10249, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow))) { SigningKey = securityKey }); if (LogHelper.IsEnabled(EventLogLevel.Informational)) LogHelper.LogInformation(LogMessages.IDX10251, LogHelper.MarkAsNonPII(notAfterUtc), LogHelper.MarkAsNonPII(utcNow)); diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.IssuerSigningKey.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.IssuerSigningKey.cs new file mode 100644 index 0000000000..3b2bd111c6 --- /dev/null +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.IssuerSigningKey.cs @@ -0,0 +1,284 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.IdentityModel.JsonWebTokens.Tests; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; +using Xunit; + +#nullable enable +namespace Microsoft.IdentityModel.JsonWebTokens.Extensibility.Tests +{ + public partial class JsonWebTokenHandlerValidateTokenAsyncTests + { + [Theory, MemberData(nameof(IssuerSigningKey_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility(IssuerSigningKeyExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.IssuerSigningKeyValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.JsonWebTokenHandler.ValidateTokenAsync( + theoryData.JsonWebToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.AddDiff("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.IssuerSigningKeyValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData IssuerSigningKey_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var utcPlusOneHour = utcNow + TimeSpan.FromHours(1); + + #region return CustomIssuerSigningKeyValidationError + // Test cases where delegate is overridden and return a CustomIssuerSigningKeyValidationError + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 160), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 175), + null), + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorUnknownExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate, + extraStackFrames: 2) + { + // CustomIssuerSigningKeyValidationError does not handle the exception type 'NotSupportedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(NotSupportedException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate))), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 205), + null), + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomIssuerSigningKeyValidationError.CustomIssuerSigningKeyValidationFailureType, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 190), + null), + }); + #endregion + + #region return IssuerSigningKeyValidationError + // Test cases where delegate is overridden and return an IssuerSigningKeyValidationError + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 235), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate, + extraStackFrames: 2) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenInvalidIssuerSigningKeyException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 259), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate, + extraStackFrames: 2) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 274), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException, inner: CustomSecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorThrows", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + string.Format(Tokens.LogMessages.IDX10274), + typeof(CustomSecurityTokenInvalidSigningKeyException)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10274), null), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250), + null, + new SecurityTokenInvalidSigningKeyException(nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class IssuerSigningKeyExtensibilityTheoryData : ValidateTokenAsyncBaseTheoryData + { + internal IssuerSigningKeyExtensibilityTheoryData(string testId, DateTime utcNow, IssuerSigningKeyValidationDelegate issuerSigningKeyValidator, int extraStackFrames) : base(testId) + { + JsonWebToken = JsonWebTokenHandler.ReadJsonWebToken( + JsonWebTokenHandler.CreateToken( + new SecurityTokenDescriptor() + { + IssuedAt = utcNow, + NotBefore = utcNow, + Expires = utcNow + TimeSpan.FromHours(1), + })); + + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = SkipValidationDelegates.SkipAudienceValidation, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = issuerSigningKeyValidator, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = (SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext callContext) => + { + token.SigningKey = SigningKey; + + return SigningKey; + }, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public JsonWebToken JsonWebToken { get; } + + public JsonWebTokenHandler JsonWebTokenHandler { get; } = new JsonWebTokenHandler(); + + public bool IsValid { get; set; } + + public SecurityKey SigningKey { get; set; } = KeyingMaterial.DefaultX509SigningCreds_2048_RsaSha2_Sha2.Key; + + internal IssuerSigningKeyValidationError? IssuerSigningKeyValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.TestUtils/SkipValidationDelegates.cs b/test/Microsoft.IdentityModel.TestUtils/SkipValidationDelegates.cs index 2f2bb635e7..90b49be8aa 100644 --- a/test/Microsoft.IdentityModel.TestUtils/SkipValidationDelegates.cs +++ b/test/Microsoft.IdentityModel.TestUtils/SkipValidationDelegates.cs @@ -48,7 +48,7 @@ public static class SkipValidationDelegates SecurityToken securityToken, ValidationParameters validationParameters, BaseConfiguration? configuration, - CallContext? callContext) + CallContext callContext) { return new ValidatedSigningKeyLifetime( null, // ValidFrom diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomIssuerSigningKeyValidationDelegates.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomIssuerSigningKeyValidationDelegates.cs new file mode 100644 index 0000000000..2c94cdaf92 --- /dev/null +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomIssuerSigningKeyValidationDelegates.cs @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.IdentityModel.Tokens; + +#nullable enable +namespace Microsoft.IdentityModel.TestUtils +{ + internal class CustomIssuerSigningKeyValidationDelegates + { + internal static ValidationResult CustomIssuerSigningKeyValidatorDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + // Returns a CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError + return new CustomIssuerSigningKeyValidationError( + new MessageDetail(nameof(CustomIssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult CustomIssuerSigningKeyValidatorCustomExceptionDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new CustomIssuerSigningKeyValidationError( + new MessageDetail(nameof(CustomIssuerSigningKeyValidatorCustomExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new CustomIssuerSigningKeyValidationError( + new MessageDetail(nameof(CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomIssuerSigningKeyValidationError.CustomIssuerSigningKeyValidationFailureType, + typeof(CustomSecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey); + } + + internal static ValidationResult CustomIssuerSigningKeyValidatorUnknownExceptionDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new CustomIssuerSigningKeyValidationError( + new MessageDetail(nameof(CustomIssuerSigningKeyValidatorUnknownExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(NotSupportedException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult CustomIssuerSigningKeyValidatorWithoutGetExceptionOverrideDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new CustomIssuerSigningKeyWithoutGetExceptionValidationOverrideError( + new MessageDetail(nameof(CustomIssuerSigningKeyValidatorWithoutGetExceptionOverrideDelegate), null), + typeof(CustomSecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult IssuerSigningKeyValidatorDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new IssuerSigningKeyValidationError( + new MessageDetail(nameof(IssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult IssuerSigningKeyValidatorThrows( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + throw new CustomSecurityTokenInvalidSigningKeyException(nameof(IssuerSigningKeyValidatorThrows), null); + } + + internal static ValidationResult IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new IssuerSigningKeyValidationError( + new MessageDetail(nameof(IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + + internal static ValidationResult IssuerSigningKeyValidatorCustomExceptionTypeDelegate( + SecurityKey signingKey, + SecurityToken securityToken, + ValidationParameters validationParameters, + BaseConfiguration? configuration, + CallContext callContext) + { + return new IssuerSigningKeyValidationError( + new MessageDetail(nameof(IssuerSigningKeyValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenException), + ValidationError.GetCurrentStackFrame(), + signingKey, + null); + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs index af7361fa0b..7571d4f8aa 100644 --- a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs @@ -156,6 +156,52 @@ public CustomLifetimeWithoutGetExceptionValidationOverrideError( } #endregion + #region IssuerSigningKeyValidationErrors + internal class CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError + { + /// + /// A custom validation failure type. + /// + public static readonly ValidationFailureType CustomIssuerSigningKeyValidationFailureType = new IssuerSigningKeyValidationFailure("CustomIssuerSigningKeyValidationFailureType"); + private class IssuerSigningKeyValidationFailure : ValidationFailureType { internal IssuerSigningKeyValidationFailure(string name) : base(name) { } } + + public CustomIssuerSigningKeyValidationError( + MessageDetail messageDetail, + ValidationFailureType validationFailureType, + Type exceptionType, + StackFrame stackFrame, + SecurityKey? securityKey, + Exception? innerException = null) + : base(messageDetail, validationFailureType, exceptionType, stackFrame, securityKey, innerException) + { + } + + internal override Exception GetException() + { + if (ExceptionType == typeof(CustomSecurityTokenInvalidSigningKeyException)) + { + var exception = new CustomSecurityTokenInvalidSigningKeyException(MessageDetail.Message, InnerException) { SigningKey = InvalidSigningKey }; + exception.SetValidationError(this); + return exception; + } + return base.GetException(); + } + } + + internal class CustomIssuerSigningKeyWithoutGetExceptionValidationOverrideError : IssuerSigningKeyValidationError + { + public CustomIssuerSigningKeyWithoutGetExceptionValidationOverrideError( + MessageDetail messageDetail, + Type exceptionType, + StackFrame stackFrame, + SecurityKey? securityKey, + Exception? innerException = null) + : base(messageDetail, ValidationFailureType.SigningKeyValidationFailed, exceptionType, stackFrame, securityKey, innerException) + { + } + } + #endregion // IssuerSigningKeyValidationErrors + #region TokenTypeValidationErrors internal class CustomTokenTypeValidationError : TokenTypeValidationError { diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.IssuerSigningKey.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.IssuerSigningKey.cs new file mode 100644 index 0000000000..95c1eecfd6 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.IssuerSigningKey.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.TestUtils; + +using Xunit; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens.Saml2.Extensibility.Tests +{ + public partial class Saml2SecurityTokenHandlerValidateTokenAsyncTests + { + [Theory, MemberData(nameof(IssuerSigningKey_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility(IssuerSigningKeyExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.IssuerSigningKeyValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.Saml2SecurityTokenHandler.ValidateTokenAsync( + theoryData.Saml2Token!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.AddDiff("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.IssuerSigningKeyValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData IssuerSigningKey_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var utcPlusOneHour = utcNow + TimeSpan.FromHours(1); + + #region return CustomIssuerSigningKeyValidationError + // Test cases where delegate is overridden and return a CustomIssuerSigningKeyValidationError + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 160), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 175), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorUnknownExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate, + extraStackFrames: 1) + { + // CustomIssuerSigningKeyValidationError does not handle the exception type 'NotSupportedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(NotSupportedException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate))), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 205), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomIssuerSigningKeyValidationError.CustomIssuerSigningKeyValidationFailureType, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 190), + null), + }); + #endregion + + #region return IssuerSigningKeyValidationError + // Test cases where delegate is overridden and return an IssuerSigningKeyValidationError + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 235), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate, + extraStackFrames: 1) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenInvalidIssuerSigningKeyException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 259), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate, + extraStackFrames: 1) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 274), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException, inner: CustomSecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorThrows", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows, + extraStackFrames: 0) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + string.Format(Tokens.LogMessages.IDX10274), + typeof(CustomSecurityTokenInvalidSigningKeyException)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10274), null), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("Saml2SecurityTokenHandler.ValidateToken.Internal.cs", 250), + null, + new SecurityTokenInvalidSigningKeyException(nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class IssuerSigningKeyExtensibilityTheoryData : TheoryDataBase + { + internal IssuerSigningKeyExtensibilityTheoryData(string testId, DateTime utcNow, IssuerSigningKeyValidationDelegate issuerSigningKeyValidator, int extraStackFrames) : base(testId) + { + Saml2Token = (Saml2SecurityToken)Saml2SecurityTokenHandler.CreateToken( + new SecurityTokenDescriptor() + { + Subject = Default.SamlClaimsIdentity, + Issuer = Default.Issuer, + }); + + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = SkipValidationDelegates.SkipAudienceValidation, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = issuerSigningKeyValidator, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = (SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext callContext) => + { + token.SigningKey = SigningKey; + + return SigningKey; + }, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public Saml2SecurityToken Saml2Token { get; } + + public Saml2SecurityTokenHandler Saml2SecurityTokenHandler { get; } = new Saml2SecurityTokenHandler(); + + public bool IsValid { get; set; } + + public SecurityKey SigningKey { get; set; } = KeyingMaterial.DefaultX509SigningCreds_2048_RsaSha2_Sha2.Key; + + internal ValidationParameters? ValidationParameters { get; set; } + + internal IssuerSigningKeyValidationError? IssuerSigningKeyValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.IssuerSigningKey.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.IssuerSigningKey.cs new file mode 100644 index 0000000000..a6d68dda0e --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.IssuerSigningKey.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.IdentityModel.Logging; +using Microsoft.IdentityModel.TestUtils; + +using Xunit; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens.Saml.Extensibility.Tests +{ + public partial class SamlSecurityTokenHandlerValidateTokenAsyncTests + { + [Theory, MemberData(nameof(IssuerSigningKey_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility(IssuerSigningKeyExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.IssuerSigningKeyValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.SamlSecurityTokenHandler.ValidateTokenAsync( + theoryData.SamlToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.AddDiff("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.IssuerSigningKeyValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData IssuerSigningKey_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var utcPlusOneHour = utcNow + TimeSpan.FromHours(1); + + #region return CustomIssuerSigningKeyValidationError + // Test cases where delegate is overridden and return a CustomIssuerSigningKeyValidationError + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 160), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 175), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorUnknownExceptionDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate, + extraStackFrames: 1) + { + // CustomIssuerSigningKeyValidationError does not handle the exception type 'NotSupportedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(NotSupportedException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate))), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 205), + null) + }); + + // CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate)), + IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomIssuerSigningKeyValidationError.CustomIssuerSigningKeyValidationFailureType, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 190), + null), + }); + #endregion + + #region return IssuerSigningKeyValidationError + // Test cases where delegate is overridden and return an IssuerSigningKeyValidationError + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 235), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate, + extraStackFrames: 1) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenInvalidIssuerSigningKeyException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidSigningKeyException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenInvalidSigningKeyException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 259), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorCustomExceptionTypeDelegate", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate, + extraStackFrames: 1) + { + // IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenException), + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate))), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.SigningKeyValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 274), + null) + }); + + // IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException, inner: CustomSecurityTokenInvalidIssuerSigningKeyException + theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData( + "IssuerSigningKeyValidatorThrows", + utcNow, + CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows, + extraStackFrames: 0) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidSigningKeyException), + string.Format(Tokens.LogMessages.IDX10274), + typeof(CustomSecurityTokenInvalidSigningKeyException)), + IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10274), null), + ValidationFailureType.IssuerSigningKeyValidatorThrew, + typeof(SecurityTokenInvalidSigningKeyException), + new StackFrame("SamlSecurityTokenHandler.ValidateToken.Internal.cs", 250), + null, + new SecurityTokenInvalidSigningKeyException(nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class IssuerSigningKeyExtensibilityTheoryData : TheoryDataBase + { + internal IssuerSigningKeyExtensibilityTheoryData(string testId, DateTime utcNow, IssuerSigningKeyValidationDelegate issuerSigningKeyValidator, int extraStackFrames) : base(testId) + { + SamlToken = (SamlSecurityToken)SamlSecurityTokenHandler.CreateToken( + new SecurityTokenDescriptor() + { + Subject = Default.SamlClaimsIdentity, + Issuer = Default.Issuer, + }); + + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = SkipValidationDelegates.SkipAudienceValidation, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = issuerSigningKeyValidator, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = (SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext callContext) => + { + token.SigningKey = SigningKey; + + return SigningKey; + }, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public SamlSecurityToken SamlToken { get; } + + public SamlSecurityTokenHandler SamlSecurityTokenHandler { get; } = new SamlSecurityTokenHandler(); + + public bool IsValid { get; set; } + + public SecurityKey SigningKey { get; set; } = KeyingMaterial.DefaultX509SigningCreds_2048_RsaSha2_Sha2.Key; + + internal ValidationParameters? ValidationParameters { get; set; } + + internal IssuerSigningKeyValidationError? IssuerSigningKeyValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore