From 5b28851689f3b387f6fb3201863fff7821ecd345 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 22 Nov 2024 21:14:55 +0000 Subject: [PATCH 1/5] Added TokenReplayValidationError and updated the default delegate to use it --- .../InternalAPI.Unshipped.txt | 14 +++-- .../Details/TokenReplayValidationError.cs | 54 +++++++++++++++++++ .../Validation/Validators.TokenReplay.cs | 24 +++++---- 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 23c18b30a7..d4b1d46530 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -12,10 +12,6 @@ Microsoft.IdentityModel.Tokens.AudienceValidationError.TokenAudiences.get -> Sys 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.InvalidSigningKey.set -> void -Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.IssuerSigningKeyValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, Microsoft.IdentityModel.Tokens.SecurityKey invalidSigningKey, Microsoft.IdentityModel.Tokens.ValidationFailureType failureType = null, 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 @@ -23,6 +19,9 @@ Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationPar Microsoft.IdentityModel.Tokens.LifetimeValidationError.Expires.get -> System.DateTime? Microsoft.IdentityModel.Tokens.LifetimeValidationError.LifetimeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.DateTime? notBefore, System.DateTime? expires, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.LifetimeValidationError.NotBefore.get -> System.DateTime? +Microsoft.IdentityModel.Tokens.TokenReplayValidationError +Microsoft.IdentityModel.Tokens.TokenReplayValidationError.ExpirationTime.get -> System.DateTime? +Microsoft.IdentityModel.Tokens.TokenReplayValidationError.TokenReplayValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.DateTime? expirationTime, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.TokenTypeValidationError Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.TokenTypeValidationError._invalidTokenType -> string @@ -37,17 +36,16 @@ Microsoft.IdentityModel.Tokens.ValidationResult.Error.get -> Microsoft. 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.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.TokenReplayValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenReplayValidationError static Microsoft.IdentityModel.Tokens.Utility.SerializeAsSingleCommaDelimitedString(System.Collections.Generic.IList strings) -> string static Microsoft.IdentityModel.Tokens.ValidationError.GetCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> System.Diagnostics.StackFrame static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.IssuerValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType -static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.LifetimeValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoTokenAudiencesProvided -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoValidationParameterAudiencesProvided -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.SignatureAlgorithmValidationFailed -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenExceedsMaximumSize -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenIsNotSigned -> Microsoft.IdentityModel.Tokens.ValidationFailureType -static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenTypeValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType +static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenReplayValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.XmlValidationFailed -> Microsoft.IdentityModel.Tokens.ValidationFailureType diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs new file mode 100644 index 0000000000..02d2c53d4a --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + internal class TokenReplayValidationError : ValidationError + { + internal TokenReplayValidationError( + MessageDetail messageDetail, + ValidationFailureType validationFailureType, + Type exceptionType, + StackFrame stackFrame, + DateTime? expirationTime, + Exception? innerException = null) + : base(messageDetail, validationFailureType, exceptionType, stackFrame, innerException) + { + ExpirationTime = expirationTime; + } + + internal override Exception GetException() + { + if (ExceptionType == typeof(SecurityTokenReplayDetectedException)) + { + SecurityTokenReplayDetectedException exception = new(MessageDetail.Message, InnerException); + exception.SetValidationError(this); + + return exception; + } + else if (ExceptionType == typeof(SecurityTokenReplayAddFailedException)) + { + SecurityTokenReplayAddFailedException exception = new(MessageDetail.Message, InnerException); + exception.SetValidationError(this); + + return exception; + } + + return base.GetException(); + } + + internal static new TokenReplayValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + MessageDetail.NullParameter(parameterName), + ValidationFailureType.NullArgument, + typeof(SecurityTokenArgumentNullException), + stackFrame, + null); + + protected DateTime? ExpirationTime { get; } + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs index 064a6cc491..3e8de4ffd9 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; namespace Microsoft.IdentityModel.Tokens { @@ -43,44 +42,47 @@ public static partial class Validators #pragma warning restore CA1801 // Review unused parameters { if (string.IsNullOrWhiteSpace(securityToken)) - return ValidationError.NullParameter( + return TokenReplayValidationError.NullParameter( nameof(securityToken), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); if (validationParameters == null) - return ValidationError.NullParameter( + return TokenReplayValidationError.NullParameter( nameof(validationParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); // check if token if replay cache is set, then there must be an expiration time. if (validationParameters.TokenReplayCache != null) { if (expirationTime == null) - return new ValidationError( + return new TokenReplayValidationError( new MessageDetail( LogMessages.IDX10227, securityToken), ValidationFailureType.TokenReplayValidationFailed, typeof(SecurityTokenNoExpirationException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + expirationTime); if (validationParameters.TokenReplayCache.TryFind(securityToken)) - return new ValidationError( + return new TokenReplayValidationError( new MessageDetail( LogMessages.IDX10228, securityToken), ValidationFailureType.TokenReplayValidationFailed, typeof(SecurityTokenReplayDetectedException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + expirationTime); if (!validationParameters.TokenReplayCache.TryAdd(securityToken, expirationTime.Value)) - return new ValidationError( + return new TokenReplayValidationError( new MessageDetail( LogMessages.IDX10229, securityToken), ValidationFailureType.TokenReplayValidationFailed, typeof(SecurityTokenReplayAddFailedException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame(), + expirationTime); } // if it reaches here, that means no token replay is detected. From 7db24b6f94a30dfc36c3454eaea10948d7e0bd9c Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 22 Nov 2024 21:15:55 +0000 Subject: [PATCH 2/5] Added log message, custom validation errors, custom delegates, and validation failure type for the token replay validation extensibility tests --- .../InternalAPI.Unshipped.txt | 2 +- .../LogMessages.cs | 2 +- .../Validation/ValidationFailureType.cs | 5 + .../CustomTokenReplayValidationDelegates.cs | 135 ++++++++++++++++++ .../CustomValidationErrors.cs | 48 +++++++ 5 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomTokenReplayValidationDelegates.cs diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index d4b1d46530..986ba57a91 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -2,7 +2,7 @@ const Microsoft.IdentityModel.Tokens.LogMessages.IDX10002 = "IDX10002: Unknown e const Microsoft.IdentityModel.Tokens.LogMessages.IDX10268 = "IDX10268: Unable to validate audience, validationParameters.ValidAudiences.Count == 0." -> string const Microsoft.IdentityModel.Tokens.LogMessages.IDX10269 = "IDX10269: IssuerValidationDelegate threw an exception, see inner exception." -> string const Microsoft.IdentityModel.Tokens.LogMessages.IDX10271 = "IDX10271: LifetimeValidationDelegate threw an exception, see inner exception." -> string -const Microsoft.IdentityModel.Tokens.LogMessages.IDX10275 = "IDX10275: TokenTypeValidationDelegate threw an exception, see inner exception." -> string +const Microsoft.IdentityModel.Tokens.LogMessages.IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception." -> string 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 diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 59c48703f3..0c52effe4d 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -88,7 +88,7 @@ internal static class LogMessages public const string IDX10267 = "IDX10267: '{0}' has been called by a derived class '{1}' which has not implemented this method. For this call graph to succeed, '{1}' will need to implement '{0}'."; public const string IDX10268 = "IDX10268: Unable to validate audience, validationParameters.ValidAudiences.Count == 0."; public const string IDX10269 = "IDX10269: IssuerValidationDelegate threw an exception, see inner exception."; - + public const string IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception."; // 10500 - SignatureValidation public const string IDX10500 = "IDX10500: Signature validation failed. No security keys were provided to validate the signature."; diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs index e512d2af5d..8cc90842ef 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs @@ -134,5 +134,10 @@ 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 token replay validation delegate threw an exception. + /// + public static readonly ValidationFailureType TokenReplayValidatorThrew = new TokenReplayValidationFailure("TokenReplayValidatorThrew"); } } diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomTokenReplayValidationDelegates.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomTokenReplayValidationDelegates.cs new file mode 100644 index 0000000000..6e10f6cba8 --- /dev/null +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomTokenReplayValidationDelegates.cs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Microsoft.IdentityModel.Tokens; + +#nullable enable +namespace Microsoft.IdentityModel.TestUtils +{ + internal class CustomTokenReplayValidationDelegates + { + internal static ValidationResult CustomTokenReplayValidationDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + // Returns a CustomTokenReplayValidationError : IssuerValidationError + return new CustomTokenReplayValidationError( + new MessageDetail(nameof(CustomTokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + + internal static ValidationResult CustomTokenReplayValidatorCustomExceptionDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomTokenReplayValidationError( + new MessageDetail(nameof(CustomTokenReplayValidatorCustomExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + + internal static ValidationResult CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomTokenReplayValidationError( + new MessageDetail(nameof(CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomTokenReplayValidationError.CustomTokenReplayValidationFailureType, + typeof(CustomSecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime, + null); + } + + internal static ValidationResult CustomTokenReplayValidatorUnknownExceptionDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomTokenReplayValidationError( + new MessageDetail(nameof(CustomTokenReplayValidatorUnknownExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(NotSupportedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + + internal static ValidationResult CustomTokenReplayValidatorWithoutGetExceptionOverrideDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomTokenReplayWithoutGetExceptionValidationOverrideError( + new MessageDetail(nameof(CustomTokenReplayValidatorWithoutGetExceptionOverrideDelegate), null), + typeof(CustomSecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + + internal static ValidationResult TokenReplayValidationDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new TokenReplayValidationError( + new MessageDetail(nameof(TokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + + internal static ValidationResult TokenReplayValidatorThrows( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + throw new CustomSecurityTokenReplayDetectedException(nameof(TokenReplayValidatorThrows), null); + } + + internal static ValidationResult TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new TokenReplayValidationError( + new MessageDetail(nameof(TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + internal static ValidationResult TokenReplayValidatorCustomExceptionTypeDelegate( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new TokenReplayValidationError( + new MessageDetail(nameof(TokenReplayValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenException), + ValidationError.GetCurrentStackFrame(), + expirationTime); + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs index 382a57a634..3ef0dcf508 100644 --- a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs @@ -156,6 +156,54 @@ public CustomLifetimeWithoutGetExceptionValidationOverrideError( } #endregion + #region TokenReplayValidationErrors + internal class CustomTokenReplayValidationError : TokenReplayValidationError + { + /// + /// A custom validation failure type. + /// + public static readonly ValidationFailureType CustomTokenReplayValidationFailureType = new TokenReplayValidationFailure("CustomTokenReplayValidationFailureType"); + private class TokenReplayValidationFailure : ValidationFailureType { internal TokenReplayValidationFailure(string name) : base(name) { } } + + public CustomTokenReplayValidationError( + MessageDetail messageDetail, + ValidationFailureType validationFailureType, + Type exceptionType, + StackFrame stackFrame, + DateTime? expirationTime, + Exception? innerException = null) + : base(messageDetail, validationFailureType, exceptionType, stackFrame, expirationTime, innerException) + { + } + + internal override Exception GetException() + { + if (ExceptionType == typeof(CustomSecurityTokenReplayDetectedException)) + { + var exception = new CustomSecurityTokenReplayDetectedException(MessageDetail.Message, InnerException); + exception.SetValidationError(this); + + return exception; + } + + return base.GetException(); + } + } + + internal class CustomTokenReplayWithoutGetExceptionValidationOverrideError : TokenReplayValidationError + { + public CustomTokenReplayWithoutGetExceptionValidationOverrideError( + MessageDetail messageDetail, + Type exceptionType, + StackFrame stackFrame, + DateTime? expirationTime, + Exception? innerException = null) + : base(messageDetail, ValidationFailureType.TokenReplayValidationFailed, exceptionType, stackFrame, expirationTime, innerException) + { + } + } + #endregion + // Other custom validation errors to be added here for signature validation, issuer signing key, etc. } #nullable restore From 158d09d28b40c35068f939f9cb56a5e45560b77a Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 22 Nov 2024 21:16:21 +0000 Subject: [PATCH 3/5] Handle the potential case where the token replay delegate throws --- ...nWebTokenHandler.ValidateToken.Internal.cs | 24 +++++++++++--- ...rityTokenHandler.ValidateToken.Internal.cs | 33 ++++++++++++++----- ...rityTokenHandler.ValidateToken.Internal.cs | 31 +++++++++++++---- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index 18fa21fcf9..696a4b01e0 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -301,13 +301,27 @@ private async ValueTask> ValidateJWSAsync( ex); } - ValidationResult replayValidationResult = validationParameters.TokenReplayValidator( - expires, jsonWebToken.EncodedToken, validationParameters, callContext); + ValidationResult replayValidationResult; - if (!replayValidationResult.IsValid) + try { - StackFrame replayValidationFailureStackFrame = StackFrames.ReplayValidationFailed ??= new StackFrame(true); - return replayValidationResult.UnwrapError().AddStackFrame(replayValidationFailureStackFrame); + replayValidationResult = validationParameters.TokenReplayValidator( + expires, jsonWebToken.EncodedToken, validationParameters, callContext); + + if (!replayValidationResult.IsValid) + return replayValidationResult.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 TokenReplayValidationError( + new MessageDetail(TokenLogMessages.IDX10276), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + expires, + ex); } ValidationResult? actorValidationResult = null; 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 24b0cea3ba..5899b2e244 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs @@ -78,14 +78,31 @@ internal async Task> ValidateTokenAsync( if (samlToken.Assertion.Conditions is not null) { - ValidationResult tokenReplayValidationResult = Validators.ValidateTokenReplay( - samlToken.Assertion.Conditions.NotOnOrAfter, - samlToken.Assertion.CanonicalString, - validationParameters, - callContext); - - if (!tokenReplayValidationResult.IsValid) - return tokenReplayValidationResult.UnwrapError().AddCurrentStackFrame(); + ValidationResult tokenReplayValidationResult; + + try + { + tokenReplayValidationResult = validationParameters.TokenReplayValidator( + samlToken.Assertion.Conditions.NotOnOrAfter, + samlToken.Assertion.CanonicalString, + validationParameters, + callContext); + + if (!tokenReplayValidationResult.IsValid) + return tokenReplayValidationResult.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 TokenReplayValidationError( + new MessageDetail(Tokens.LogMessages.IDX10276), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + samlToken.Assertion.Conditions.NotOnOrAfter, + ex); + } } ValidationResult signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext); 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 f60c3817ad..1b64555dd0 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs @@ -82,14 +82,31 @@ internal async Task> ValidateTokenAsync( if (samlToken.Assertion.Conditions is not null) { - ValidationResult tokenReplayValidationResult = Validators.ValidateTokenReplay( - samlToken.Assertion.Conditions.NotOnOrAfter, - samlToken.Assertion.CanonicalString, - validationParameters, - callContext); + ValidationResult tokenReplayValidationResult; - if (!tokenReplayValidationResult.IsValid) - return tokenReplayValidationResult.UnwrapError().AddCurrentStackFrame(); + try + { + tokenReplayValidationResult = validationParameters.TokenReplayValidator( + samlToken.Assertion.Conditions.NotOnOrAfter, + samlToken.Assertion.CanonicalString, + validationParameters, + callContext); + + if (!tokenReplayValidationResult.IsValid) + return tokenReplayValidationResult.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 TokenReplayValidationError( + new MessageDetail(Tokens.LogMessages.IDX10276), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + ValidationError.GetCurrentStackFrame(), + samlToken.Assertion.Conditions.NotOnOrAfter, + ex); + } } var signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext); From 0b35d52470aca2c99c2915b8279c9f7bf8cca3a6 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 22 Nov 2024 21:16:36 +0000 Subject: [PATCH 4/5] Added extensibility tests for token replay --- ...bTokenHandler.Extensibility.TokenReplay.cs | 277 +++++++++++++++++ ...yTokenHandler.Extensibility.TokenReplay.cs | 279 ++++++++++++++++++ ...yTokenHandler.Extensibility.TokenReplay.cs | 279 ++++++++++++++++++ 3 files changed, 835 insertions(+) create mode 100644 test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.TokenReplay.cs create mode 100644 test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.TokenReplay.cs create mode 100644 test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.TokenReplay.cs diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.TokenReplay.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.TokenReplay.cs new file mode 100644 index 0000000000..3f96081d85 --- /dev/null +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.TokenReplay.cs @@ -0,0 +1,277 @@ +// 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(TokenReplay_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_TokenReplayValidator_Extensibility(TokenReplayExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_TokenReplayValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.TokenReplayValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.JsonWebTokenHandler.ValidateTokenAsync( + theoryData.JsonWebToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.Diffs.Add("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.TokenReplayValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData TokenReplay_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var expirationTime = utcNow + TimeSpan.FromHours(1); + + #region return CustomTokenReplayValidationError + // Test cases where delegate is overridden and return a CustomTokenReplayValidationError + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 160), + expirationTime) + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 175), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorUnknownExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate, + extraStackFrames: 2) + { + // CustomTokenReplayValidationError 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(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate))), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 205), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomTokenReplayValidationError.CustomTokenReplayValidationFailureType, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 190), + expirationTime), + }); + #endregion + + #region return TokenReplayValidationError + // Test cases where delegate is overridden and return an TokenReplayValidationError + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 235), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate, + extraStackFrames: 2) + { + // TokenReplayValidationError does not handle the exception type 'CustomSecurityTokenReplayDetectedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 259), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate, + extraStackFrames: 2) + { + // TokenReplayValidationError 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(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 274), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException, inner: CustomSecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorThrows", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + string.Format(Tokens.LogMessages.IDX10276), + typeof(CustomSecurityTokenReplayDetectedException)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10276), null), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250), + expirationTime, + new SecurityTokenReplayDetectedException(nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class TokenReplayExtensibilityTheoryData : ValidateTokenAsyncBaseTheoryData + { + internal TokenReplayExtensibilityTheoryData(string testId, DateTime utcNow, TokenReplayValidationDelegate tokenReplayValidator, 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 = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = tokenReplayValidator, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public JsonWebToken JsonWebToken { get; } + + public JsonWebTokenHandler JsonWebTokenHandler { get; } = new JsonWebTokenHandler(); + + public bool IsValid { get; set; } + + internal TokenReplayValidationError? TokenReplayValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.TokenReplay.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.TokenReplay.cs new file mode 100644 index 0000000000..3266a4595a --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.TokenReplay.cs @@ -0,0 +1,279 @@ +// 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(TokenReplay_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_TokenReplayValidator_Extensibility(TokenReplayExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_TokenReplayValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.TokenReplayValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.Saml2SecurityTokenHandler.ValidateTokenAsync( + theoryData.Saml2Token!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.Diffs.Add("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.TokenReplayValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData TokenReplay_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var expirationTime = utcNow + TimeSpan.FromHours(1); + + #region return CustomTokenReplayValidationError + // Test cases where delegate is overridden and return a CustomTokenReplayValidationError + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 160), + expirationTime) + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 175), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorUnknownExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate, + extraStackFrames: 1) + { + // CustomTokenReplayValidationError 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(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate))), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 205), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomTokenReplayValidationError.CustomTokenReplayValidationFailureType, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 190), + expirationTime), + }); + #endregion + + #region return TokenReplayValidationError + // Test cases where delegate is overridden and return an TokenReplayValidationError + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 235), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate, + extraStackFrames: 1) + { + // TokenReplayValidationError does not handle the exception type 'CustomSecurityTokenReplayDetectedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 259), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate, + extraStackFrames: 1) + { + // TokenReplayValidationError 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(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 274), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException, inner: CustomSecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorThrows", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows, + extraStackFrames: 0) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + string.Format(Tokens.LogMessages.IDX10276), + typeof(CustomSecurityTokenReplayDetectedException)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10276), null), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("Saml2SecurityTokenHandler.ValidateToken.Internal.cs", 250), + expirationTime, + new SecurityTokenReplayDetectedException(nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class TokenReplayExtensibilityTheoryData : TheoryDataBase + { + internal TokenReplayExtensibilityTheoryData(string testId, DateTime utcNow, TokenReplayValidationDelegate tokenReplayValidator, int extraStackFrames) : base(testId) + { + Saml2Token = (Saml2SecurityToken)Saml2SecurityTokenHandler.CreateToken( + new SecurityTokenDescriptor() + { + Subject = Default.SamlClaimsIdentity, + Issuer = Default.Issuer, + IssuedAt = utcNow, + NotBefore = utcNow, + Expires = utcNow + TimeSpan.FromHours(1), + }); + + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = SkipValidationDelegates.SkipAudienceValidation, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = tokenReplayValidator, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public Saml2SecurityToken Saml2Token { get; } + + public Saml2SecurityTokenHandler Saml2SecurityTokenHandler { get; } = new Saml2SecurityTokenHandler(); + + public bool IsValid { get; set; } + + internal ValidationParameters? ValidationParameters { get; set; } + + internal TokenReplayValidationError? TokenReplayValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.TokenReplay.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.TokenReplay.cs new file mode 100644 index 0000000000..c603ebcacd --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.TokenReplay.cs @@ -0,0 +1,279 @@ +// 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(TokenReplay_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_TokenReplayValidator_Extensibility(TokenReplayExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_TokenReplayValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.TokenReplayValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.SamlSecurityTokenHandler.ValidateTokenAsync( + theoryData.SamlToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + context.Diffs.Add("validationResult.IsValid is true, expected false"); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.TokenReplayValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData TokenReplay_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + var utcNow = DateTime.UtcNow; + var expirationTime = utcNow + TimeSpan.FromHours(1); + + #region return CustomTokenReplayValidationError + // Test cases where delegate is overridden and return a CustomTokenReplayValidationError + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 160), + expirationTime) + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 175), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorUnknownExceptionDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate, + extraStackFrames: 1) + { + // CustomTokenReplayValidationError 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(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate))), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorUnknownExceptionDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 205), + expirationTime), + }); + + // CustomTokenReplayValidationError : TokenReplayValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate)), + TokenReplayValidationError = new CustomTokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.CustomTokenReplayValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomTokenReplayValidationError.CustomTokenReplayValidationFailureType, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 190), + expirationTime), + }); + #endregion + + #region return TokenReplayValidationError + // Test cases where delegate is overridden and return an TokenReplayValidationError + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidationDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidationDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 235), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenReplayDetectedException : SecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate, + extraStackFrames: 1) + { + // TokenReplayValidationError does not handle the exception type 'CustomSecurityTokenReplayDetectedException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenReplayDetectedException), + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomTokenReplayDetectedExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenReplayDetectedException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 259), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorCustomExceptionTypeDelegate", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate, + extraStackFrames: 1) + { + // TokenReplayValidationError 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(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate))), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.TokenReplayValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomTokenReplayValidationDelegates.cs", 274), + expirationTime) + }); + + // TokenReplayValidationError : ValidationError, ExceptionType: SecurityTokenReplayDetectedException, inner: CustomSecurityTokenReplayDetectedException + theoryData.Add(new TokenReplayExtensibilityTheoryData( + "TokenReplayValidatorThrows", + utcNow, + CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows, + extraStackFrames: 0) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenReplayDetectedException), + string.Format(Tokens.LogMessages.IDX10276), + typeof(CustomSecurityTokenReplayDetectedException)), + TokenReplayValidationError = new TokenReplayValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10276), null), + ValidationFailureType.TokenReplayValidatorThrew, + typeof(SecurityTokenReplayDetectedException), + new StackFrame("SamlSecurityTokenHandler.ValidateToken.Internal.cs", 250), + expirationTime, + new SecurityTokenReplayDetectedException(nameof(CustomTokenReplayValidationDelegates.TokenReplayValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class TokenReplayExtensibilityTheoryData : TheoryDataBase + { + internal TokenReplayExtensibilityTheoryData(string testId, DateTime utcNow, TokenReplayValidationDelegate tokenReplayValidator, int extraStackFrames) : base(testId) + { + SamlToken = (SamlSecurityToken)SamlSecurityTokenHandler.CreateToken( + new SecurityTokenDescriptor() + { + Subject = Default.SamlClaimsIdentity, + Issuer = Default.Issuer, + IssuedAt = utcNow, + NotBefore = utcNow, + Expires = utcNow + TimeSpan.FromHours(1), + }); + + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = SkipValidationDelegates.SkipAudienceValidation, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = tokenReplayValidator, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public SamlSecurityToken SamlToken { get; } + + public SamlSecurityTokenHandler SamlSecurityTokenHandler { get; } = new SamlSecurityTokenHandler(); + + public bool IsValid { get; set; } + + internal ValidationParameters? ValidationParameters { get; set; } + + internal TokenReplayValidationError? TokenReplayValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore From 1b6b4b71959ffb8207f15d816f63f29cba9daa90 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Mon, 25 Nov 2024 14:15:18 +0000 Subject: [PATCH 5/5] Resolved post merge unshipped API errors raised by Visual Studio --- src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 8d7985620f..6f21480055 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -23,8 +23,8 @@ Microsoft.IdentityModel.Tokens.TokenReplayValidationError Microsoft.IdentityModel.Tokens.TokenReplayValidationError.ExpirationTime.get -> System.DateTime? Microsoft.IdentityModel.Tokens.TokenReplayValidationError.TokenReplayValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.DateTime? expirationTime, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.TokenTypeValidationError -Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.TokenTypeValidationError.InvalidTokenType.get -> string +Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> System.TimeProvider Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void Microsoft.IdentityModel.Tokens.ValidationError.AddCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> Microsoft.IdentityModel.Tokens.ValidationError @@ -49,4 +49,5 @@ static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.SignatureAl static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenExceedsMaximumSize -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenIsNotSigned -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenReplayValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType +static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.TokenTypeValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.XmlValidationFailed -> Microsoft.IdentityModel.Tokens.ValidationFailureType