From aed25ca6c95f30662bd49222ecd8104bc14896e6 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Thu, 24 Oct 2024 10:25:56 +0100 Subject: [PATCH] Regression tests: Token Type (#2932) * Renamed ValidationParameters.TypeValidator to ValidationParameters.TokenTypeValidator * Removed log from TokenType validation * Added TokenTypeValidationError to create the exception and assign the invalid token type. Updated the token type validator to use it. * Adjusted the creation of SecurityTokenInvalidTypeException to return the correct invalid type when it is empty or null * Added regression/comparison tests around token type validation scenarios * Added test for valid scenario where there are no valid types specified * Return null for the invalid token type if the type is an empty string to keep considency with existing tests. * Updated renamed variable * Addressed post merge issues --- ...nWebTokenHandler.ValidateToken.Internal.cs | 2 +- .../InternalAPI.Shipped.txt | 2 - .../InternalAPI.Unshipped.txt | 8 +- .../Details/TokenTypeValidationError.cs | 40 +++++ .../Validation/ValidationParameters.cs | 4 +- .../Validation/Validators.TokenType.cs | 15 +- ...ndler.ValidateTokenAsyncTests.Algorithm.cs | 2 +- ...eTokenAsyncTests.Audience.Extensibility.cs | 2 +- ...alidateTokenAsyncTests.IssuerSigningKey.cs | 2 +- ...eTokenAsyncTests.Lifetime.Extensibility.cs | 2 +- ...ndler.ValidateTokenAsyncTests.Signature.cs | 3 +- ...ndler.ValidateTokenAsyncTests.TokenType.cs | 142 ++++++++++++++++++ .../Validation/ValidationParametersTests.cs | 2 +- 13 files changed, 206 insertions(+), 20 deletions(-) create mode 100644 src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs create mode 100644 test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.TokenType.cs diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index f1f4ccd521..f99da5e6e2 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -322,7 +322,7 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext, actorValidationResult = innerActorValidationResult; } - ValidationResult typeValidationResult = validationParameters.TypeValidator( + ValidationResult typeValidationResult = validationParameters.TokenTypeValidator( jsonWebToken.Typ, jsonWebToken, validationParameters, callContext); if (!typeValidationResult.IsValid) { diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Shipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Shipped.txt index c81d692aec..0c487acc55 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Shipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Shipped.txt @@ -550,8 +550,6 @@ Microsoft.IdentityModel.Tokens.ValidationParameters.TokenReplayValidator.get -> Microsoft.IdentityModel.Tokens.ValidationParameters.TokenReplayValidator.set -> void Microsoft.IdentityModel.Tokens.ValidationParameters.TryAllIssuerSigningKeys.get -> bool Microsoft.IdentityModel.Tokens.ValidationParameters.TryAllIssuerSigningKeys.set -> void -Microsoft.IdentityModel.Tokens.ValidationParameters.TypeValidator.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationDelegate -Microsoft.IdentityModel.Tokens.ValidationParameters.TypeValidator.set -> void Microsoft.IdentityModel.Tokens.ValidationParameters.ValidAlgorithms.get -> System.Collections.Generic.IList Microsoft.IdentityModel.Tokens.ValidationParameters.ValidAlgorithms.set -> void Microsoft.IdentityModel.Tokens.ValidationParameters.ValidateActor.get -> bool diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 56f33d0862..5816053a79 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -10,13 +10,19 @@ Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationParameters = 2 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource Microsoft.IdentityModel.Tokens.LifetimeValidationError._expires -> System.DateTime Microsoft.IdentityModel.Tokens.LifetimeValidationError._notBefore -> System.DateTime +Microsoft.IdentityModel.Tokens.TokenTypeValidationError +Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType) -> void +Microsoft.IdentityModel.Tokens.TokenTypeValidationError._invalidTokenType -> string Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> System.TimeProvider Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void Microsoft.IdentityModel.Tokens.ValidationError.GetException(System.Type exceptionType, System.Exception innerException) -> System.Exception +Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationDelegate +Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.set -> void Microsoft.IdentityModel.Tokens.ValidationResult.Error.get -> Microsoft.IdentityModel.Tokens.ValidationError Microsoft.IdentityModel.Tokens.ValidationResult.IsValid.get -> bool Microsoft.IdentityModel.Tokens.ValidationResult.Result.get -> TResult override Microsoft.IdentityModel.Tokens.AlgorithmValidationError.GetException() -> System.Exception +override Microsoft.IdentityModel.Tokens.TokenTypeValidationError.GetException() -> System.Exception static Microsoft.IdentityModel.Tokens.AudienceValidationError.AudiencesCountZero -> System.Diagnostics.StackFrame static Microsoft.IdentityModel.Tokens.AudienceValidationError.AudiencesNull -> System.Diagnostics.StackFrame static Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidateAudienceFailed -> System.Diagnostics.StackFrame @@ -25,4 +31,4 @@ static Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidationParamete static Microsoft.IdentityModel.Tokens.Utility.SerializeAsSingleCommaDelimitedString(System.Collections.Generic.IList strings) -> string static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoTokenAudiencesProvided -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoValidationParameterAudiencesProvided -> Microsoft.IdentityModel.Tokens.ValidationFailureType -static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.SignatureAlgorithmValidationFailed -> Microsoft.IdentityModel.Tokens.ValidationFailureType \ No newline at end of file +static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.SignatureAlgorithmValidationFailed -> Microsoft.IdentityModel.Tokens.ValidationFailureType diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs new file mode 100644 index 0000000000..030d510485 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Diagnostics; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + internal class TokenTypeValidationError : ValidationError + { + protected string? _invalidTokenType; + + internal TokenTypeValidationError( + MessageDetail messageDetail, + Type exceptionType, + StackFrame stackFrame, + string? invalidTokenType) + : base(messageDetail, ValidationFailureType.TokenTypeValidationFailed, exceptionType, stackFrame) + { + _invalidTokenType = invalidTokenType; + } + + internal override Exception GetException() + { + if (ExceptionType == typeof(SecurityTokenInvalidTypeException)) + { + SecurityTokenInvalidTypeException exception = new(MessageDetail.Message, InnerException) + { + InvalidType = _invalidTokenType + }; + + return exception; + } + + return base.GetException(); + } + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs index ec63b6665e..100cddaad5 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs @@ -88,7 +88,7 @@ protected ValidationParameters(ValidationParameters other) TokenDecryptionKeys = other.TokenDecryptionKeys; TokenReplayCache = other.TokenReplayCache; TokenReplayValidator = other.TokenReplayValidator; - TypeValidator = other.TypeValidator; + TokenTypeValidator = other.TokenTypeValidator; ValidateActor = other.ValidateActor; ValidateSignatureLast = other.ValidateSignatureLast; ValidateWithLKG = other.ValidateWithLKG; @@ -499,7 +499,7 @@ public TokenReplayValidationDelegate TokenReplayValidator /// /// Thrown when the value is set as null. /// The used to validate the token type of a token - public TokenTypeValidationDelegate TypeValidator + public TokenTypeValidationDelegate TokenTypeValidator { get { return _tokenTypeValidator; } set { _tokenTypeValidator = value ?? throw new ArgumentNullException(nameof(value), "TypeValidator cannot be set as null."); } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs index 096ca3c447..175cc190f7 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs @@ -56,27 +56,28 @@ internal static ValidationResult ValidateTokenType( if (validationParameters.ValidTypes.Count == 0) { - LogHelper.LogVerbose(LogMessages.IDX10255); + //TODO: Move to CallContext? + //LogHelper.LogVerbose(LogMessages.IDX10255); return new ValidatedTokenType(type ?? "null", validationParameters.ValidTypes.Count); } if (string.IsNullOrEmpty(type)) - return new ValidationError( + return new TokenTypeValidationError( new MessageDetail(LogMessages.IDX10256), - ValidationFailureType.TokenTypeValidationFailed, typeof(SecurityTokenInvalidTypeException), - new StackFrame(true)); + new StackFrame(true), + null); // even if it is empty, we report null to match the original behaviour. if (!validationParameters.ValidTypes.Contains(type, StringComparer.Ordinal)) { - return new ValidationError( + return new TokenTypeValidationError( new MessageDetail( LogMessages.IDX10257, LogHelper.MarkAsNonPII(type), LogHelper.MarkAsNonPII(Utility.SerializeAsSingleCommaDelimitedString(validationParameters.ValidTypes))), - ValidationFailureType.TokenTypeValidationFailed, typeof(SecurityTokenInvalidTypeException), - new StackFrame(true)); + new StackFrame(true), + type); } // TODO: Move to CallContext diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs index dfd0c76c86..36fd83ed4a 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs @@ -116,7 +116,7 @@ static ValidationParameters CreateValidationParameters( validationParameters.IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation; validationParameters.LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation; validationParameters.TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation; - validationParameters.TypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; + validationParameters.TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; return validationParameters; } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Audience.Extensibility.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Audience.Extensibility.cs index 26236c6d53..9b2321e348 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Audience.Extensibility.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Audience.Extensibility.cs @@ -194,7 +194,7 @@ static ValidationParameters CreateValidationParameters( validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; validationParameters.LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation; validationParameters.SignatureValidator = SkipValidationDelegates.SkipSignatureValidation; - validationParameters.TypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; + validationParameters.TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; return validationParameters; } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.IssuerSigningKey.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.IssuerSigningKey.cs index 0c7f6ddf53..b9de8fa8a3 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.IssuerSigningKey.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.IssuerSigningKey.cs @@ -106,7 +106,7 @@ static ValidationParameters CreateValidationParameters( validationParameters.IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation; validationParameters.LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation; validationParameters.TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation; - validationParameters.TypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; + validationParameters.TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; return validationParameters; } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Lifetime.Extensibility.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Lifetime.Extensibility.cs index 5c1df1b0b4..dffbcebe58 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Lifetime.Extensibility.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Lifetime.Extensibility.cs @@ -247,7 +247,7 @@ static ValidationParameters CreateValidationParameters(LifetimeValidationDelegat validationParameters.IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation; validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; validationParameters.SignatureValidator = SkipValidationDelegates.SkipSignatureValidation; - validationParameters.TypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; + validationParameters.TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; return validationParameters; } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Signature.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Signature.cs index c72363b715..f6c1b63518 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Signature.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Signature.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. #nullable enable -using System; using System.Threading.Tasks; using Microsoft.IdentityModel.TestUtils; using Microsoft.IdentityModel.Tokens; @@ -122,7 +121,7 @@ static ValidationParameters CreateValidationParameters( validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; validationParameters.LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation; validationParameters.TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation; - validationParameters.TypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; + validationParameters.TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation; validationParameters.TryAllIssuerSigningKeys = tryAllKeys; return validationParameters; diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.TokenType.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.TokenType.cs new file mode 100644 index 0000000000..cb543864f3 --- /dev/null +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.TokenType.cs @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable enable +using System.Threading.Tasks; +using Microsoft.IdentityModel.TestUtils; +using Microsoft.IdentityModel.Tokens; +using Xunit; + +namespace Microsoft.IdentityModel.JsonWebTokens.Tests +{ + public partial class JsonWebTokenHandlerValidateTokenAsyncTests + { + [Theory, MemberData(nameof(ValidateTokenAsync_TokenTypeTestCases), DisableDiscoveryEnumeration = true)] + public async Task ValidateTokenAsync_TokenType(ValidateTokenAsyncTokenTypeTheoryData theoryData) + { + var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_TokenType", theoryData); + + string jwtString = CreateTokenForTokenTypeValidation(theoryData.UseEmptyType, theoryData.CustomTokenType); + + await ValidateAndCompareResults(jwtString, theoryData, context); + + TestUtilities.AssertFailIfErrors(context); + } + + public static TheoryData ValidateTokenAsync_TokenTypeTestCases + { + get + { + var theoryData = new TheoryData(); + + theoryData.Add(new ValidateTokenAsyncTokenTypeTheoryData("Valid_JwtToken") + { + TokenValidationParameters = CreateTokenValidationParameters(), + ValidationParameters = CreateValidationParameters(), + }); + + theoryData.Add(new ValidateTokenAsyncTokenTypeTheoryData("Valid_UnknownTokenType_NoValidTokenTypes") + { + // If there are no valid token types, any token type is valid + CustomTokenType = "SomeUnknownType", + TokenValidationParameters = CreateTokenValidationParameters(null), + ValidationParameters = CreateValidationParameters(null), + }); + + theoryData.Add(new ValidateTokenAsyncTokenTypeTheoryData("Valid_CustomToken_AddedAsValidTokenType") + { + CustomTokenType = "PPT", + TokenValidationParameters = CreateTokenValidationParameters(validTokenType: "PPT"), + ValidationParameters = CreateValidationParameters(validTokenType: "PPT"), + }); + + theoryData.Add(new ValidateTokenAsyncTokenTypeTheoryData("Invalid_CustomToken_NotAddedAsValidTokenType") + { + CustomTokenType = "PPT", + TokenValidationParameters = CreateTokenValidationParameters(), + ValidationParameters = CreateValidationParameters(), + ExpectedIsValid = false, + ExpectedException = ExpectedException.SecurityTokenInvalidTypeException("IDX10257:"), + }); + + theoryData.Add(new ValidateTokenAsyncTokenTypeTheoryData("Invalid_EmptyTokenType") + { + UseEmptyType = true, + TokenValidationParameters = CreateTokenValidationParameters(), + ValidationParameters = CreateValidationParameters(), + ExpectedIsValid = false, + ExpectedException = ExpectedException.SecurityTokenInvalidTypeException("IDX10256:"), + }); + + return theoryData; + + static TokenValidationParameters CreateTokenValidationParameters(string? validTokenType = "JWT") + { + // only validate the signature and issuer signing key + var tokenValidationParameters = new TokenValidationParameters() + { + ValidateAudience = false, + ValidateIssuer = false, + ValidateLifetime = false, + ValidateTokenReplay = false, + ValidateIssuerSigningKey = false, + RequireSignedTokens = false, + }; + + if (validTokenType is not null) + tokenValidationParameters.ValidTypes = [validTokenType]; + + return tokenValidationParameters; + } + + static ValidationParameters CreateValidationParameters(string? validTokenType = "JWT") + { + ValidationParameters validationParameters = new ValidationParameters(); + + // Skip all validations except token type + validationParameters.AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation; + validationParameters.AudienceValidator = SkipValidationDelegates.SkipAudienceValidation; + validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; + validationParameters.IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation; + validationParameters.LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation; + validationParameters.SignatureValidator = SkipValidationDelegates.SkipSignatureValidation; + validationParameters.TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation; + + if (validTokenType is not null) + validationParameters.ValidTypes.Add(validTokenType); + + return validationParameters; + } + } + } + + public class ValidateTokenAsyncTokenTypeTheoryData : ValidateTokenAsyncBaseTheoryData + { + public ValidateTokenAsyncTokenTypeTheoryData(string testId) : base(testId) { } + + public bool UseEmptyType { get; set; } = false; + + public string? CustomTokenType { get; set; } = null; + } + + // Custom JWT with empty string for type + private static string emptyTypeJWT = "eyJ0eXAiOiIiLCJhbGciOiJub25lIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTcyOTY5NDI1OCwiZXhwIjoxNzI5Njk3ODU4fQ."; + + private static string CreateTokenForTokenTypeValidation(bool useEmptyType = false, string? tokenType = null) + { + if (useEmptyType) + return emptyTypeJWT; + + JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler(); + + SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor + { + Subject = Default.ClaimsIdentity, + TokenType = tokenType ?? "JWT", + }; + + return jsonWebTokenHandler.CreateToken(securityTokenDescriptor); + } + } +} +#nullable restore diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidationParametersTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidationParametersTests.cs index 30b0151c33..c88c9eba40 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidationParametersTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidationParametersTests.cs @@ -17,7 +17,7 @@ public void SetValidators_NullValue_ThrowsArgumentNullException() Assert.Throws(() => validationParameters.IssuerValidatorAsync = null); Assert.Throws(() => validationParameters.TokenReplayValidator = null); Assert.Throws(() => validationParameters.LifetimeValidator = null); - Assert.Throws(() => validationParameters.TypeValidator = null); + Assert.Throws(() => validationParameters.TokenTypeValidator = null); Assert.Throws(() => validationParameters.AudienceValidator = null); Assert.Throws(() => validationParameters.IssuerSigningKeyValidator = null); }