From 416ffa0dccf4137f3f5c6ced8839f722f31e39de Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Sun, 17 Nov 2024 16:26:03 +0000 Subject: [PATCH 1/6] Handle potential exceptions thrown by the audience validation delegate on JWT, SAML, and SAML2 --- ...nWebTokenHandler.ValidateToken.Internal.cs | 27 +++++++++++--- ...rityTokenHandler.ValidateToken.Internal.cs | 36 +++++++++++++------ ...rityTokenHandler.ValidateToken.Internal.cs | 32 ++++++++++++----- .../InternalAPI.Unshipped.txt | 5 ++- .../LogMessages.cs | 2 +- .../Validation/ValidationFailureType.cs | 5 +++ 6 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index 18fa21fcf9..8aa384e622 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -267,13 +267,30 @@ private async ValueTask> ValidateJWSAsync( if (jsonWebToken.Audiences is not IList tokenAudiences) tokenAudiences = jsonWebToken.Audiences.ToList(); - ValidationResult audienceValidationResult = validationParameters.AudienceValidator( - tokenAudiences, jsonWebToken, validationParameters, callContext); + ValidationResult audienceValidationResult; + try + { + audienceValidationResult = validationParameters.AudienceValidator( + tokenAudiences, jsonWebToken, validationParameters, callContext); - if (!audienceValidationResult.IsValid) + if (!audienceValidationResult.IsValid) + { + StackFrame audienceValidationFailureStackFrame = StackFrames.AudienceValidationFailed ??= new StackFrame(true); + return audienceValidationResult.UnwrapError().AddStackFrame(audienceValidationFailureStackFrame); + } + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types { - StackFrame audienceValidationFailureStackFrame = StackFrames.AudienceValidationFailed ??= new StackFrame(true); - return audienceValidationResult.UnwrapError().AddStackFrame(audienceValidationFailureStackFrame); + return new AudienceValidationError( + new MessageDetail(TokenLogMessages.IDX10270), + typeof(SecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null, + ValidationFailureType.AudienceValidatorThrew, + ex); } ValidationResult issuerValidationResult; 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 7d45db493a..7ace68799d 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs @@ -145,18 +145,34 @@ internal virtual ValidationResult ValidateConditions( if (condition is SamlAudienceRestrictionCondition audienceRestriction) { - // AudienceRestriction.Audiences is an ICollection so we need make a conversion to List before calling our audience validator var audiencesAsList = audienceRestriction.Audiences.Select(static x => x.OriginalString).ToList(); - - var audienceValidationResult = validationParameters.AudienceValidator( - audiencesAsList, - samlToken, - validationParameters, - callContext); - - if (!audienceValidationResult.IsValid) - return audienceValidationResult.UnwrapError(); + ValidationResult audienceValidationResult; + + try + { + audienceValidationResult = validationParameters.AudienceValidator( + audiencesAsList, + samlToken, + validationParameters, + callContext); + + if (!audienceValidationResult.IsValid) + return audienceValidationResult.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 AudienceValidationError( + new MessageDetail(Tokens.LogMessages.IDX10270), + typeof(SecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + audiencesAsList, + validationParameters.ValidAudiences, + ValidationFailureType.AudienceValidatorThrew, + ex); + } validatedAudience = audienceValidationResult.UnwrapResult(); } 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 2ff1a01def..84de6bd725 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs @@ -181,15 +181,31 @@ internal virtual ValidationResult ValidateConditions( if (audienceRestriction.Audiences is not List audiencesAsList) audiencesAsList = [.. audienceRestriction.Audiences]; - var audienceValidationResult = validationParameters.AudienceValidator( - audiencesAsList, - samlToken, - validationParameters, - callContext); - if (!audienceValidationResult.IsValid) + ValidationResult audienceValidationResult; + + try + { + audienceValidationResult = validationParameters.AudienceValidator( + audiencesAsList, + samlToken, + validationParameters, + callContext); + + if (!audienceValidationResult.IsValid) + return audienceValidationResult.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 { - StackFrames.AudienceValidationFailed ??= new StackFrame(true); - return audienceValidationResult.UnwrapError().AddStackFrame(StackFrames.AudienceValidationFailed); + return new AudienceValidationError( + new MessageDetail(Tokens.LogMessages.IDX10270), + typeof(SecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + audiencesAsList, + validationParameters.ValidAudiences, + ValidationFailureType.AudienceValidatorThrew, + ex); } // Audience is valid, save it for later. diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 23c18b30a7..f20db8a841 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -1,8 +1,7 @@ const Microsoft.IdentityModel.Tokens.LogMessages.IDX10002 = "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'." -> string 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.IDX10270 = "IDX10270: AudienceValidationDelegate 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 @@ -39,9 +38,9 @@ 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.TokenTypeValidationError.GetException() -> System.Exception -static Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError 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.AudienceValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType 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 diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index 59c48703f3..fa394920aa 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 IDX10270 = "IDX10270: AudienceValidationDelegate 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..576007c54f 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 that the audience validation delegate threw and exception. + /// + public static readonly ValidationFailureType AudienceValidatorThrew = new AudienceValidationFailure("AudienceValidatorThrew"); } } From e7a37a9ef6612985557f6c6c9407201a85d63091 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Sun, 17 Nov 2024 16:26:47 +0000 Subject: [PATCH 2/6] Added cusotm audience validation delegates for testing (cherry picked from commit 2f336c2d8eb0ca6ac2d5966baf12c3c6d0d01a4d) --- .../CustomAudienceValidationDelegates.cs | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs new file mode 100644 index 0000000000..3362aea29c --- /dev/null +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Microsoft.IdentityModel.Tokens; + +#nullable enable +namespace Microsoft.IdentityModel.TestUtils +{ + internal class CustomAudienceValidationDelegates + { + internal static ValidationResult CustomAudienceValidatorDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + // Returns a CustomAudienceValidationError : AudienceValidationError + return new CustomAudienceValidationError( + new MessageDetail(nameof(CustomAudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult CustomAudienceValidatorCustomExceptionDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomAudienceValidationError( + new MessageDetail(nameof(CustomAudienceValidatorCustomExceptionDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomAudienceValidationError( + new MessageDetail(nameof(CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null, + CustomAudienceValidationError.CustomAudienceValidationFailureType); + } + + internal static ValidationResult CustomAudienceValidatorUnknownExceptionDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomAudienceValidationError( + new MessageDetail(nameof(CustomAudienceValidatorUnknownExceptionDelegate), null), + typeof(NotSupportedException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult CustomAudienceValidatorWithoutGetExceptionOverrideDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new CustomAudienceWithoutGetExceptionValidationOverrideError( + new MessageDetail(nameof(CustomAudienceValidatorWithoutGetExceptionOverrideDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult AudienceValidatorDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new AudienceValidationError( + new MessageDetail(nameof(AudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult AudienceValidatorThrows( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + throw new CustomSecurityTokenInvalidAudienceException(nameof(AudienceValidatorThrows), null); + } + + internal static ValidationResult AudienceValidatorCustomAudienceExceptionTypeDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new AudienceValidationError( + new MessageDetail(nameof(AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + + internal static ValidationResult AudienceValidatorCustomExceptionTypeDelegate( + IList tokenAudiences, + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) + { + return new AudienceValidationError( + new MessageDetail(nameof(AudienceValidatorCustomExceptionTypeDelegate), null), + typeof(CustomSecurityTokenException), + ValidationError.GetCurrentStackFrame(), + tokenAudiences, + null); + } + } +} +#nullable restore From b1539a6c4392191a881c8113512a48f13856887b Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Sun, 17 Nov 2024 16:27:17 +0000 Subject: [PATCH 3/6] Added audience extensibility tests for JWT, SAML, and SAML2 (cherry picked from commit f5b4362f7241348c9c28e17eaae9c5c69e96b6e9) --- ...nWebTokenHandler.Extensibility.Audience.cs | 283 +++++++++++++++++ ...rityTokenHandler.Extensibility.Audience.cs | 288 ++++++++++++++++++ ...rityTokenHandler.Extensibility.Audience.cs | 288 ++++++++++++++++++ 3 files changed, 859 insertions(+) create mode 100644 test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs create mode 100644 test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs create mode 100644 test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs new file mode 100644 index 0000000000..e820a5144a --- /dev/null +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +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 Microsoft.IdentityModel.Tokens.Json.Tests; +using Xunit; + +#nullable enable +namespace Microsoft.IdentityModel.JsonWebTokens.Extensibility.Tests +{ + public partial class JsonWebTokenHandlerValidateTokenAsyncTests + { + [Theory, MemberData(nameof(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.AudienceValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.JsonWebTokenHandler.ValidateTokenAsync( + theoryData.JsonWebToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + ValidatedToken validatedToken = validationResult.UnwrapResult(); + if (validatedToken.ValidatedAudience is not null) + IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData Audience_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + string audience = "CustomAudience"; + List tokenAudiences = [audience]; + + #region return CustomAudienceValidationError + // Test cases where delegate is overridden and return a CustomAudienceValidationError + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 160), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 175), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorUnknownExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, + extraStackFrames: 2) + { + // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + typeof(NotSupportedException), + new StackFrame("CustomAudienceValidationDelegates.cs", 205), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 190), + tokenAudiences, + null, // validAudiences + CustomAudienceValidationError.CustomAudienceValidationFailureType), + }); + #endregion + + #region return AudienceValidationError + // Test cases where delegate is overridden and return an AudienceValidationError + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 235), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomAudienceExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 259), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + typeof(CustomSecurityTokenException), + new StackFrame("CustomAudienceValidationDelegates.cs", 274), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorThrows", + audience, + CustomAudienceValidationDelegates.AudienceValidatorThrows, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + string.Format(Tokens.LogMessages.IDX10270), + typeof(CustomSecurityTokenInvalidAudienceException)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10270), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250), + tokenAudiences, + null, + ValidationFailureType.AudienceValidatorThrew, + new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class AudienceExtensibilityTheoryData : ValidateTokenAsyncBaseTheoryData + { + internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) + { + JsonWebToken = JsonUtilities.CreateUnsignedJsonWebToken("aud", audience); + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = audienceValidator, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public JsonWebToken JsonWebToken { get; } + + public JsonWebTokenHandler JsonWebTokenHandler { get; } = new JsonWebTokenHandler(); + + public bool IsValid { get; set; } + + internal string? ValidatedAudience { get; set; } + + internal AudienceValidationError? AudienceValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs new file mode 100644 index 0000000000..7741ec8d58 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +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(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.AudienceValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.Saml2SecurityTokenHandler.ValidateTokenAsync( + theoryData.Saml2Token!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + ValidatedToken validatedToken = validationResult.UnwrapResult(); + if (validatedToken.ValidatedAudience is not null) + IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData Audience_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + string audience = Default.Audience; + List tokenAudiences = [audience]; + + #region return CustomAudienceValidationError + // Test cases where delegate is overridden and return a CustomAudienceValidationError + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 160), + tokenAudiences, + null, // validAudiences + ValidationFailureType.AudienceValidationFailed) + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 175), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorUnknownExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, + extraStackFrames: 2) + { + // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + typeof(NotSupportedException), + new StackFrame("CustomAudienceValidationDelegates.cs", 205), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 190), + tokenAudiences, + null, + CustomAudienceValidationError.CustomAudienceValidationFailureType), + }); + #endregion + + #region return AudienceValidationError + // Test cases where delegate is overridden and return an AudienceValidationError + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 235), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomAudienceExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 259), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + typeof(CustomSecurityTokenException), + new StackFrame("CustomAudienceValidationDelegates.cs", 274), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorThrows", + audience, + CustomAudienceValidationDelegates.AudienceValidatorThrows, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + string.Format(Tokens.LogMessages.IDX10270), + typeof(CustomSecurityTokenInvalidAudienceException)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10270), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("Saml2SecurityTokenHandler.ValidateToken.Internal.cs", 250), + tokenAudiences, + null, + ValidationFailureType.AudienceValidatorThrew, + new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class AudienceExtensibilityTheoryData : TheoryDataBase + { + internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) + { + Saml2Token = (Saml2SecurityToken)Saml2SecurityTokenHandler.CreateToken(new() + { + Subject = Default.SamlClaimsIdentity, + Audience = audience, + Issuer = Default.Issuer, + }); + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = audienceValidator, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public Saml2SecurityToken Saml2Token { get; } + + public Saml2SecurityTokenHandler Saml2SecurityTokenHandler { get; } = new Saml2SecurityTokenHandler(); + + public bool IsValid { get; set; } + + internal string? ValidatedAudience { get; set; } + + internal ValidationParameters? ValidationParameters { get; set; } + + internal AudienceValidationError? AudienceValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs new file mode 100644 index 0000000000..ed4c5f3168 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +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(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); + context.IgnoreType = false; + for (int i = 0; i < theoryData.ExtraStackFrames; i++) + theoryData.AudienceValidationError!.AddStackFrame(new StackFrame(false)); + + try + { + ValidationResult validationResult = await theoryData.SamlSecurityTokenHandler.ValidateTokenAsync( + theoryData.SamlToken!, + theoryData.ValidationParameters!, + theoryData.CallContext, + CancellationToken.None); + + if (validationResult.IsValid) + { + ValidatedToken validatedToken = validationResult.UnwrapResult(); + if (validatedToken.ValidatedAudience is not null) + IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + } + else + { + ValidationError validationError = validationResult.UnwrapError(); + IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); + theoryData.ExpectedException.ProcessException(validationError.GetException(), context); + } + } + catch (Exception ex) + { + theoryData.ExpectedException.ProcessException(ex, context); + } + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData Audience_ExtensibilityTestCases + { + get + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + string audience = Default.Audience; + List tokenAudiences = [audience]; + + #region return CustomAudienceValidationError + // Test cases where delegate is overridden and return a CustomAudienceValidationError + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 160), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed) + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 175), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorUnknownExceptionDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, + extraStackFrames: 2) + { + // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + typeof(NotSupportedException), + new StackFrame("CustomAudienceValidationDelegates.cs", 205), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), + AudienceValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 190), + tokenAudiences, + null, + CustomAudienceValidationError.CustomAudienceValidationFailureType), + }); + #endregion + + #region return AudienceValidationError + // Test cases where delegate is overridden and return an AudienceValidationError + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorDelegate, + extraStackFrames: 2) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 235), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomAudienceExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 259), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomExceptionTypeDelegate", + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, + extraStackFrames: 2) + { + // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + typeof(CustomSecurityTokenException), + new StackFrame("CustomAudienceValidationDelegates.cs", 274), + tokenAudiences, + null, + ValidationFailureType.AudienceValidationFailed), + }); + + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorThrows", + audience, + CustomAudienceValidationDelegates.AudienceValidatorThrows, + extraStackFrames: 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + string.Format(Tokens.LogMessages.IDX10270), + typeof(CustomSecurityTokenInvalidAudienceException)), + AudienceValidationError = new AudienceValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10270), null), + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("SamlSecurityTokenHandler.ValidateToken.Internal.cs", 250), + tokenAudiences, + null, + ValidationFailureType.AudienceValidatorThrew, + new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } + + public class AudienceExtensibilityTheoryData : TheoryDataBase + { + internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) + { + SamlToken = (SamlSecurityToken)SamlSecurityTokenHandler.CreateToken(new() + { + Subject = Default.SamlClaimsIdentity, + Audience = audience, + Issuer = Default.Issuer, + }); + ValidationParameters = new ValidationParameters + { + AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, + AudienceValidator = audienceValidator, + IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, + IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, + LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, + SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, + TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, + TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation + }; + + ExtraStackFrames = extraStackFrames; + } + + public SamlSecurityToken SamlToken { get; } + + public SamlSecurityTokenHandler SamlSecurityTokenHandler { get; } = new SamlSecurityTokenHandler(); + + public bool IsValid { get; set; } + + internal string? ValidatedAudience { get; set; } + + internal ValidationParameters? ValidationParameters { get; set; } + + internal AudienceValidationError? AudienceValidationError { get; set; } + + internal int ExtraStackFrames { get; } + } + } +} +#nullable restore From 45623f032fb39e7bbfab1ddeca1800a2441c1183 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Thu, 21 Nov 2024 22:00:07 +0000 Subject: [PATCH 4/6] Updated validation failure type position in tests --- ...nWebTokenHandler.ValidateToken.Internal.cs | 2 +- ...rityTokenHandler.ValidateToken.Internal.cs | 3 +- ...rityTokenHandler.ValidateToken.Internal.cs | 3 +- ...nWebTokenHandler.Extensibility.Audience.cs | 30 +++++++++---------- .../CustomAudienceValidationDelegates.cs | 10 +++++-- ...rityTokenHandler.Extensibility.Audience.cs | 30 +++++++++---------- ...rityTokenHandler.Extensibility.Audience.cs | 30 +++++++++---------- 7 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index 8aa384e622..9684c96089 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -285,11 +285,11 @@ private async ValueTask> ValidateJWSAsync( { return new AudienceValidationError( new MessageDetail(TokenLogMessages.IDX10270), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, null, - ValidationFailureType.AudienceValidatorThrew, ex); } 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 7ace68799d..1cc2b1ec8e 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Diagnostics; using System.Linq; using System.Threading; @@ -166,11 +167,11 @@ internal virtual ValidationResult ValidateConditions( { return new AudienceValidationError( new MessageDetail(Tokens.LogMessages.IDX10270), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), audiencesAsList, validationParameters.ValidAudiences, - ValidationFailureType.AudienceValidatorThrew, ex); } 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 84de6bd725..781e9c98a9 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -200,11 +201,11 @@ internal virtual ValidationResult ValidateConditions( { return new AudienceValidationError( new MessageDetail(Tokens.LogMessages.IDX10270), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), audiencesAsList, validationParameters.ValidAudiences, - ValidationFailureType.AudienceValidatorThrew, ex); } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs index e820a5144a..c385394603 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs @@ -79,11 +79,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 160), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -99,11 +99,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 175), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException @@ -122,11 +122,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(NotSupportedException), new StackFrame("CustomAudienceValidationDelegates.cs", 205), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType @@ -142,11 +142,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomAudienceValidationError.CustomAudienceValidationFailureType, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 190), tokenAudiences, - null, // validAudiences - CustomAudienceValidationError.CustomAudienceValidationFailureType), + null) // validAudiences }); #endregion @@ -165,11 +165,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 235), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -188,11 +188,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 259), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException @@ -211,11 +211,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenException), new StackFrame("CustomAudienceValidationDelegates.cs", 274), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException @@ -232,11 +232,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( string.Format(Tokens.LogMessages.IDX10270), null), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250), tokenAudiences, null, - ValidationFailureType.AudienceValidatorThrew, new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) ) }); diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs index 3362aea29c..8b5010a8be 100644 --- a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomAudienceValidationDelegates.cs @@ -19,6 +19,7 @@ internal static ValidationResult CustomAudienceValidatorDelegate( // Returns a CustomAudienceValidationError : AudienceValidationError return new CustomAudienceValidationError( new MessageDetail(nameof(CustomAudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, @@ -33,6 +34,7 @@ internal static ValidationResult CustomAudienceValidatorCustomExceptionD { return new CustomAudienceValidationError( new MessageDetail(nameof(CustomAudienceValidatorCustomExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, @@ -47,11 +49,11 @@ internal static ValidationResult CustomAudienceValidatorCustomExceptionC { return new CustomAudienceValidationError( new MessageDetail(nameof(CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomAudienceValidationError.CustomAudienceValidationFailureType, typeof(CustomSecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, - null, - CustomAudienceValidationError.CustomAudienceValidationFailureType); + null); } internal static ValidationResult CustomAudienceValidatorUnknownExceptionDelegate( @@ -62,6 +64,7 @@ internal static ValidationResult CustomAudienceValidatorUnknownException { return new CustomAudienceValidationError( new MessageDetail(nameof(CustomAudienceValidatorUnknownExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(NotSupportedException), ValidationError.GetCurrentStackFrame(), tokenAudiences, @@ -90,6 +93,7 @@ internal static ValidationResult AudienceValidatorDelegate( { return new AudienceValidationError( new MessageDetail(nameof(AudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, @@ -113,6 +117,7 @@ internal static ValidationResult AudienceValidatorCustomAudienceExceptio { return new AudienceValidationError( new MessageDetail(nameof(AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), ValidationError.GetCurrentStackFrame(), tokenAudiences, @@ -127,6 +132,7 @@ internal static ValidationResult AudienceValidatorCustomExceptionTypeDel { return new AudienceValidationError( new MessageDetail(nameof(AudienceValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenException), ValidationError.GetCurrentStackFrame(), tokenAudiences, diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs index 7741ec8d58..1a82613b1a 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs @@ -77,11 +77,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 160), tokenAudiences, - null, // validAudiences - ValidationFailureType.AudienceValidationFailed) + null) // validAudiences }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -97,11 +97,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 175), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException @@ -120,11 +120,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(NotSupportedException), new StackFrame("CustomAudienceValidationDelegates.cs", 205), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType @@ -140,11 +140,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomAudienceValidationError.CustomAudienceValidationFailureType, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 190), tokenAudiences, - null, - CustomAudienceValidationError.CustomAudienceValidationFailureType), + null), }); #endregion @@ -163,11 +163,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 235), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -186,11 +186,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 259), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException @@ -209,11 +209,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenException), new StackFrame("CustomAudienceValidationDelegates.cs", 274), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException @@ -230,11 +230,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( string.Format(Tokens.LogMessages.IDX10270), null), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), new StackFrame("Saml2SecurityTokenHandler.ValidateToken.Internal.cs", 250), tokenAudiences, null, - ValidationFailureType.AudienceValidatorThrew, new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) ) }); diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs index ed4c5f3168..3c68dde2be 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs @@ -77,11 +77,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 160), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed) + null) }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -97,11 +97,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 175), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException @@ -120,11 +120,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(NotSupportedException), new StackFrame("CustomAudienceValidationDelegates.cs", 205), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType @@ -140,11 +140,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new CustomAudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomAudienceValidationError.CustomAudienceValidationFailureType, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 190), tokenAudiences, - null, - CustomAudienceValidationError.CustomAudienceValidationFailureType), + null), }); #endregion @@ -163,11 +163,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(SecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 235), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException @@ -186,11 +186,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenInvalidAudienceException), new StackFrame("CustomAudienceValidationDelegates.cs", 259), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException @@ -209,11 +209,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, typeof(CustomSecurityTokenException), new StackFrame("CustomAudienceValidationDelegates.cs", 274), tokenAudiences, - null, - ValidationFailureType.AudienceValidationFailed), + null), }); // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException @@ -230,11 +230,11 @@ public static TheoryData Audience_Extensibility AudienceValidationError = new AudienceValidationError( new MessageDetail( string.Format(Tokens.LogMessages.IDX10270), null), + ValidationFailureType.AudienceValidatorThrew, typeof(SecurityTokenInvalidAudienceException), new StackFrame("SamlSecurityTokenHandler.ValidateToken.Internal.cs", 250), tokenAudiences, null, - ValidationFailureType.AudienceValidatorThrew, new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) ) }); From 6e9d6d3874123705c3a8a21140509ea0a45a129f Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Tue, 26 Nov 2024 14:52:53 +0000 Subject: [PATCH 5/6] Handle success case as unexpected in audience extensibility tests --- .../JsonWebTokenHandler.Extensibility.Audience.cs | 4 +--- .../Saml2SecurityTokenHandler.Extensibility.Audience.cs | 4 +--- .../SamlSecurityTokenHandler.Extensibility.Audience.cs | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs index c385394603..46874df0c9 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs @@ -36,9 +36,7 @@ public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExt if (validationResult.IsValid) { - ValidatedToken validatedToken = validationResult.UnwrapResult(); - if (validatedToken.ValidatedAudience is not null) - IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + context.Diffs.Add("validationResult.IsValid == true, expected false"); } else { diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs index 1a82613b1a..9ed8486d61 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs @@ -34,9 +34,7 @@ public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExt if (validationResult.IsValid) { - ValidatedToken validatedToken = validationResult.UnwrapResult(); - if (validatedToken.ValidatedAudience is not null) - IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + context.Diffs.Add("validationResult.IsValid == true, expected false"); } else { diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs index 3c68dde2be..609cd20733 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs @@ -34,9 +34,7 @@ public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExt if (validationResult.IsValid) { - ValidatedToken validatedToken = validationResult.UnwrapResult(); - if (validatedToken.ValidatedAudience is not null) - IdentityComparer.AreStringsEqual(validatedToken.ValidatedAudience, theoryData.ValidatedAudience, context); + context.Diffs.Add("validationResult.IsValid == true, expected false"); } else { From 0a47c4fcf94f45c4a72d1448a42ec2e3625c7aaf Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Wed, 4 Dec 2024 11:46:03 +0000 Subject: [PATCH 6/6] Removed duplicate test code adopting the refactored approach after merging dev --- ...nWebTokenHandler.Extensibility.Audience.cs | 280 ++--------------- .../Tests/AudienceExtensibilityTestCases.cs | 217 +++++++++++++ .../Tests/AudienceExtensibilityTheoryData.cs | 28 ++ ...rityTokenHandler.Extensibility.Audience.cs | 285 ++---------------- ...rityTokenHandler.Extensibility.Audience.cs | 285 ++---------------- 5 files changed, 299 insertions(+), 796 deletions(-) create mode 100644 test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTestCases.cs create mode 100644 test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTheoryData.cs diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs index 46874df0c9..d0d7e02b77 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.Extensibility.Audience.cs @@ -1,16 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -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 Microsoft.IdentityModel.Tokens.Json.Tests; +using Microsoft.IdentityModel.TestUtils.TokenValidationExtensibility.Tests; using Xunit; #nullable enable @@ -18,263 +10,27 @@ namespace Microsoft.IdentityModel.JsonWebTokens.Extensibility.Tests { public partial class JsonWebTokenHandlerValidateTokenAsyncTests { - [Theory, MemberData(nameof(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] - public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) + [Theory, MemberData( + nameof(GenerateAudienceExtensibilityTestCases), + parameters: ["JWT", 2], + DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility( + AudienceExtensibilityTheoryData theoryData) { - var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); - context.IgnoreType = false; - for (int i = 0; i < theoryData.ExtraStackFrames; i++) - theoryData.AudienceValidationError!.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 == true, expected false"); - } - else - { - ValidationError validationError = validationResult.UnwrapError(); - IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); - theoryData.ExpectedException.ProcessException(validationError.GetException(), context); - } - } - catch (Exception ex) - { - theoryData.ExpectedException.ProcessException(ex, context); - } - - TestUtilities.AssertFailIfErrors(context); - } - - public static TheoryData Audience_ExtensibilityTestCases - { - get - { - var theoryData = new TheoryData(); - CallContext callContext = new CallContext(); - string audience = "CustomAudience"; - List tokenAudiences = [audience]; - - #region return CustomAudienceValidationError - // Test cases where delegate is overridden and return a CustomAudienceValidationError - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 160), - tokenAudiences, - null) - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 175), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorUnknownExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, - extraStackFrames: 2) - { - // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(NotSupportedException), - new StackFrame("CustomAudienceValidationDelegates.cs", 205), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), - CustomAudienceValidationError.CustomAudienceValidationFailureType, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 190), - tokenAudiences, - null) // validAudiences - }); - #endregion - - #region return AudienceValidationError - // Test cases where delegate is overridden and return an AudienceValidationError - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 235), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomAudienceExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' - ExpectedException = ExpectedException.SecurityTokenException( - LogHelper.FormatInvariant( - Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 259), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenException), - new StackFrame("CustomAudienceValidationDelegates.cs", 274), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorThrows", - audience, - CustomAudienceValidationDelegates.AudienceValidatorThrows, - extraStackFrames: 1) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - string.Format(Tokens.LogMessages.IDX10270), - typeof(CustomSecurityTokenInvalidAudienceException)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - string.Format(Tokens.LogMessages.IDX10270), null), - ValidationFailureType.AudienceValidatorThrew, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250), - tokenAudiences, - null, - new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) - ) - }); - #endregion - - return theoryData; - } + await ExtensibilityTesting.ValidateTokenAsync_Extensibility( + theoryData, + this, + nameof(ValidateTokenAsync_AudienceValidator_Extensibility)); } - public class AudienceExtensibilityTheoryData : ValidateTokenAsyncBaseTheoryData + public static TheoryData GenerateAudienceExtensibilityTestCases( + string tokenHandlerType, + int extraStackFrames) { - internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) - { - JsonWebToken = JsonUtilities.CreateUnsignedJsonWebToken("aud", audience); - ValidationParameters = new ValidationParameters - { - AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, - AudienceValidator = audienceValidator, - IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, - IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, - LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, - SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, - TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, - TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation - }; - - ExtraStackFrames = extraStackFrames; - } - - public JsonWebToken JsonWebToken { get; } - - public JsonWebTokenHandler JsonWebTokenHandler { get; } = new JsonWebTokenHandler(); - - public bool IsValid { get; set; } - - internal string? ValidatedAudience { get; set; } - - internal AudienceValidationError? AudienceValidationError { get; set; } - - internal int ExtraStackFrames { get; } + return ExtensibilityTesting.GenerateAudienceExtensibilityTestCases( + tokenHandlerType, + extraStackFrames, + "JsonWebTokenHandler.ValidateToken.Internal.cs"); } } } diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTestCases.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTestCases.cs new file mode 100644 index 0000000000..d6d56aa50f --- /dev/null +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTestCases.cs @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using Xunit; +using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.Logging; +using System.Collections.Generic; + +#nullable enable +namespace Microsoft.IdentityModel.TestUtils.TokenValidationExtensibility.Tests +{ + public partial class ExtensibilityTesting + { + public static TheoryData GenerateAudienceExtensibilityTestCases( + string tokenHandlerType, + int extraStackFrames, + string stackFrameFileName) + { + var theoryData = new TheoryData(); + CallContext callContext = new CallContext(); + string issuerGuid = Guid.NewGuid().ToString(); + var audience = Default.Audience; + List tokenAudiences = [audience]; + + #region return CustomAudienceValidationError + // Test cases where delegate is overridden and return a CustomAudienceValidationError + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, + extraStackFrames: extraStackFrames) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), + ValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null) + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, + extraStackFrames: extraStackFrames) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), + ValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorUnknownExceptionDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, + extraStackFrames: extraStackFrames) + { + // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), + ValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(NotSupportedException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null), + }); + + // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType + theoryData.Add(new AudienceExtensibilityTheoryData( + "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, + extraStackFrames: extraStackFrames) + { + ExpectedException = new ExpectedException( + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), + ValidationError = new CustomAudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), + CustomAudienceValidationError.CustomAudienceValidationFailureType, + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null) // validAudiences + }); + #endregion + + #region return AudienceValidationError + // Test cases where delegate is overridden and return an AudienceValidationError + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.AudienceValidatorDelegate, + extraStackFrames: extraStackFrames) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), + ValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(SecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomAudienceExceptionTypeDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, + extraStackFrames: extraStackFrames) + { + // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' + ExpectedException = ExpectedException.SecurityTokenException( + LogHelper.FormatInvariant( + Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; + typeof(CustomSecurityTokenInvalidAudienceException), + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), + ValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(CustomSecurityTokenInvalidAudienceException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null) + }); + + // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorCustomExceptionTypeDelegate", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, + extraStackFrames: extraStackFrames) + { + // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), + ValidationError = new AudienceValidationError( + new MessageDetail( + nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), + ValidationFailureType.AudienceValidationFailed, + typeof(CustomSecurityTokenException), + new StackFrame("CustomAudienceValidationDelegates.cs", 0), + tokenAudiences, + null) + }); + + // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException + theoryData.Add(new AudienceExtensibilityTheoryData( + "AudienceValidatorThrows", + tokenHandlerType, + audience, + CustomAudienceValidationDelegates.AudienceValidatorThrows, + extraStackFrames: extraStackFrames - 1) + { + ExpectedException = new ExpectedException( + typeof(SecurityTokenInvalidAudienceException), + string.Format(Tokens.LogMessages.IDX10270), + typeof(CustomSecurityTokenInvalidAudienceException)), + ValidationError = new AudienceValidationError( + new MessageDetail( + string.Format(Tokens.LogMessages.IDX10270), null), + ValidationFailureType.AudienceValidatorThrew, + typeof(SecurityTokenInvalidAudienceException), + new StackFrame(stackFrameFileName, 0), + tokenAudiences, + null, + new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) + ) + }); + #endregion + + return theoryData; + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTheoryData.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTheoryData.cs new file mode 100644 index 0000000000..7b1da2d0ad --- /dev/null +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/Tests/AudienceExtensibilityTheoryData.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.IdentityModel.Tokens; + +#nullable enable +namespace Microsoft.IdentityModel.TestUtils.TokenValidationExtensibility.Tests +{ + public class AudienceExtensibilityTheoryData : ExtensibilityTheoryData + { + internal AudienceExtensibilityTheoryData( + string testId, + string tokenHandlerType, + string audience, + AudienceValidationDelegate audienceValidationDelegate, + int extraStackFrames) : base(testId, tokenHandlerType, extraStackFrames) + { + SecurityTokenDescriptor = new() + { + Issuer = Default.Issuer, + Audience = audience, + }; + + ValidationParameters.AudienceValidator = audienceValidationDelegate; + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs index 9ed8486d61..254667ea18 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandler.Extensibility.Audience.cs @@ -1,14 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; using System.Threading.Tasks; -using Microsoft.IdentityModel.Logging; -using Microsoft.IdentityModel.TestUtils; - +using Microsoft.IdentityModel.TestUtils.TokenValidationExtensibility.Tests; using Xunit; #nullable enable @@ -16,270 +10,27 @@ namespace Microsoft.IdentityModel.Tokens.Saml2.Extensibility.Tests { public partial class Saml2SecurityTokenHandlerValidateTokenAsyncTests { - [Theory, MemberData(nameof(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] - public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) - { - var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); - context.IgnoreType = false; - for (int i = 0; i < theoryData.ExtraStackFrames; i++) - theoryData.AudienceValidationError!.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 == true, expected false"); - } - else - { - ValidationError validationError = validationResult.UnwrapError(); - IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); - theoryData.ExpectedException.ProcessException(validationError.GetException(), context); - } - } - catch (Exception ex) - { - theoryData.ExpectedException.ProcessException(ex, context); - } - - TestUtilities.AssertFailIfErrors(context); - } - - public static TheoryData Audience_ExtensibilityTestCases + [Theory, MemberData( + nameof(GenerateAudienceExtensibilityTestCases), + parameters: ["SAML2", 2], + DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility( + AudienceExtensibilityTheoryData theoryData) { - get - { - var theoryData = new TheoryData(); - CallContext callContext = new CallContext(); - string audience = Default.Audience; - List tokenAudiences = [audience]; - - #region return CustomAudienceValidationError - // Test cases where delegate is overridden and return a CustomAudienceValidationError - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 160), - tokenAudiences, - null) // validAudiences - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 175), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorUnknownExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, - extraStackFrames: 2) - { - // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(NotSupportedException), - new StackFrame("CustomAudienceValidationDelegates.cs", 205), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), - CustomAudienceValidationError.CustomAudienceValidationFailureType, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 190), - tokenAudiences, - null), - }); - #endregion - - #region return AudienceValidationError - // Test cases where delegate is overridden and return an AudienceValidationError - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 235), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomAudienceExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' - ExpectedException = ExpectedException.SecurityTokenException( - LogHelper.FormatInvariant( - Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 259), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenException), - new StackFrame("CustomAudienceValidationDelegates.cs", 274), - tokenAudiences, - null) - }); - - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorThrows", - audience, - CustomAudienceValidationDelegates.AudienceValidatorThrows, - extraStackFrames: 1) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - string.Format(Tokens.LogMessages.IDX10270), - typeof(CustomSecurityTokenInvalidAudienceException)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - string.Format(Tokens.LogMessages.IDX10270), null), - ValidationFailureType.AudienceValidatorThrew, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("Saml2SecurityTokenHandler.ValidateToken.Internal.cs", 250), - tokenAudiences, - null, - new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) - ) - }); - #endregion - - return theoryData; - } + await ExtensibilityTesting.ValidateTokenAsync_Extensibility( + theoryData, + this, + nameof(ValidateTokenAsync_AudienceValidator_Extensibility)); } - public class AudienceExtensibilityTheoryData : TheoryDataBase + public static TheoryData GenerateAudienceExtensibilityTestCases( + string tokenHandlerType, + int extraStackFrames) { - internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) - { - Saml2Token = (Saml2SecurityToken)Saml2SecurityTokenHandler.CreateToken(new() - { - Subject = Default.SamlClaimsIdentity, - Audience = audience, - Issuer = Default.Issuer, - }); - ValidationParameters = new ValidationParameters - { - AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, - AudienceValidator = audienceValidator, - IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, - IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, - LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, - SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, - TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, - TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation - }; - - ExtraStackFrames = extraStackFrames; - } - - public Saml2SecurityToken Saml2Token { get; } - - public Saml2SecurityTokenHandler Saml2SecurityTokenHandler { get; } = new Saml2SecurityTokenHandler(); - - public bool IsValid { get; set; } - - internal string? ValidatedAudience { get; set; } - - internal ValidationParameters? ValidationParameters { get; set; } - - internal AudienceValidationError? AudienceValidationError { get; set; } - - internal int ExtraStackFrames { get; } + return ExtensibilityTesting.GenerateAudienceExtensibilityTestCases( + tokenHandlerType, + extraStackFrames, + "Saml2SecurityTokenHandler.ValidateToken.Internal.cs"); } } } diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs index 609cd20733..9e6285389f 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandler.Extensibility.Audience.cs @@ -1,14 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; using System.Threading.Tasks; -using Microsoft.IdentityModel.Logging; -using Microsoft.IdentityModel.TestUtils; - +using Microsoft.IdentityModel.TestUtils.TokenValidationExtensibility.Tests; using Xunit; #nullable enable @@ -16,270 +10,27 @@ namespace Microsoft.IdentityModel.Tokens.Saml.Extensibility.Tests { public partial class SamlSecurityTokenHandlerValidateTokenAsyncTests { - [Theory, MemberData(nameof(Audience_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)] - public async Task ValidateTokenAsync_AudienceValidator_Extensibility(AudienceExtensibilityTheoryData theoryData) - { - var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_AudienceValidator_Extensibility)}", theoryData); - context.IgnoreType = false; - for (int i = 0; i < theoryData.ExtraStackFrames; i++) - theoryData.AudienceValidationError!.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 == true, expected false"); - } - else - { - ValidationError validationError = validationResult.UnwrapError(); - IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.AudienceValidationError, context); - theoryData.ExpectedException.ProcessException(validationError.GetException(), context); - } - } - catch (Exception ex) - { - theoryData.ExpectedException.ProcessException(ex, context); - } - - TestUtilities.AssertFailIfErrors(context); - } - - public static TheoryData Audience_ExtensibilityTestCases + [Theory, MemberData( + nameof(GenerateAudienceExtensibilityTestCases), + parameters: ["SAML", 2], + DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_AudienceValidator_Extensibility( + AudienceExtensibilityTheoryData theoryData) { - get - { - var theoryData = new TheoryData(); - CallContext callContext = new CallContext(); - string audience = Default.Audience; - List tokenAudiences = [audience]; - - #region return CustomAudienceValidationError - // Test cases where delegate is overridden and return a CustomAudienceValidationError - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 160), - tokenAudiences, - null) - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 175), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorUnknownExceptionDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate, - extraStackFrames: 2) - { - // CustomAudienceValidationError 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(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate))), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorUnknownExceptionDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(NotSupportedException), - new StackFrame("CustomAudienceValidationDelegates.cs", 205), - tokenAudiences, - null), - }); - - // CustomAudienceValidationError : AudienceValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType - theoryData.Add(new AudienceExtensibilityTheoryData( - "CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate", - audience, - CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate)), - AudienceValidationError = new CustomAudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.CustomAudienceValidatorCustomExceptionCustomFailureTypeDelegate), null), - CustomAudienceValidationError.CustomAudienceValidationFailureType, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 190), - tokenAudiences, - null), - }); - #endregion - - #region return AudienceValidationError - // Test cases where delegate is overridden and return an AudienceValidationError - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorDelegate, - extraStackFrames: 2) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 235), - tokenAudiences, - null), - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidAudienceException : SecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomAudienceExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError does not handle the exception type 'CustomSecurityTokenInvalidAudienceException' - ExpectedException = ExpectedException.SecurityTokenException( - LogHelper.FormatInvariant( - Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'."; - typeof(CustomSecurityTokenInvalidAudienceException), - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomAudienceExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenInvalidAudienceException), - new StackFrame("CustomAudienceValidationDelegates.cs", 259), - tokenAudiences, - null), - }); - - // AudienceValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorCustomExceptionTypeDelegate", - audience, - CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate, - extraStackFrames: 2) - { - // AudienceValidationError 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(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate))), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - nameof(CustomAudienceValidationDelegates.AudienceValidatorCustomExceptionTypeDelegate), null), - ValidationFailureType.AudienceValidationFailed, - typeof(CustomSecurityTokenException), - new StackFrame("CustomAudienceValidationDelegates.cs", 274), - tokenAudiences, - null), - }); - - // AudienceValidationError : ValidationError, ExceptionType: SecurityTokenInvalidAudienceException, inner: CustomSecurityTokenInvalidAudienceException - theoryData.Add(new AudienceExtensibilityTheoryData( - "AudienceValidatorThrows", - audience, - CustomAudienceValidationDelegates.AudienceValidatorThrows, - extraStackFrames: 1) - { - ExpectedException = new ExpectedException( - typeof(SecurityTokenInvalidAudienceException), - string.Format(Tokens.LogMessages.IDX10270), - typeof(CustomSecurityTokenInvalidAudienceException)), - AudienceValidationError = new AudienceValidationError( - new MessageDetail( - string.Format(Tokens.LogMessages.IDX10270), null), - ValidationFailureType.AudienceValidatorThrew, - typeof(SecurityTokenInvalidAudienceException), - new StackFrame("SamlSecurityTokenHandler.ValidateToken.Internal.cs", 250), - tokenAudiences, - null, - new SecurityTokenInvalidAudienceException(nameof(CustomAudienceValidationDelegates.AudienceValidatorThrows)) - ) - }); - #endregion - - return theoryData; - } + await ExtensibilityTesting.ValidateTokenAsync_Extensibility( + theoryData, + this, + nameof(ValidateTokenAsync_AudienceValidator_Extensibility)); } - public class AudienceExtensibilityTheoryData : TheoryDataBase + public static TheoryData GenerateAudienceExtensibilityTestCases( + string tokenHandlerType, + int extraStackFrames) { - internal AudienceExtensibilityTheoryData(string testId, string audience, AudienceValidationDelegate audienceValidator, int extraStackFrames) : base(testId) - { - SamlToken = (SamlSecurityToken)SamlSecurityTokenHandler.CreateToken(new() - { - Subject = Default.SamlClaimsIdentity, - Audience = audience, - Issuer = Default.Issuer, - }); - ValidationParameters = new ValidationParameters - { - AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation, - AudienceValidator = audienceValidator, - IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation, - IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation, - LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation, - SignatureValidator = SkipValidationDelegates.SkipSignatureValidation, - TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation, - TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation - }; - - ExtraStackFrames = extraStackFrames; - } - - public SamlSecurityToken SamlToken { get; } - - public SamlSecurityTokenHandler SamlSecurityTokenHandler { get; } = new SamlSecurityTokenHandler(); - - public bool IsValid { get; set; } - - internal string? ValidatedAudience { get; set; } - - internal ValidationParameters? ValidationParameters { get; set; } - - internal AudienceValidationError? AudienceValidationError { get; set; } - - internal int ExtraStackFrames { get; } + return ExtensibilityTesting.GenerateAudienceExtensibilityTestCases( + tokenHandlerType, + extraStackFrames, + "SamlSecurityTokenHandler.ValidateToken.Internal.cs"); } } }