Skip to content

Commit

Permalink
Extensibility tests: Token Type - JWT (#3030)
Browse files Browse the repository at this point in the history
* Updated TokenTypeValidationError and updated the default token type validation delegate to use it

* Added log message and validation failure type for the case where the token type validation delegate throws

* Added custom validation error and validation delegates for token type validation

(cherry picked from commit 058c87e)

* Handle the case where the token type validation delegate throws in JsonWebTokenHandler

(cherry picked from commit 63ac325)

* Added extensibility tests for token type validation on JWT

(cherry picked from commit 658ac48)

* Updated validation failure type position in tests

* Update src/Microsoft.IdentityModel.Tokens/Validation/ValidationFailureType.cs

Co-authored-by: Westin Musser <[email protected]>

---------

Co-authored-by: Westin Musser <[email protected]>
  • Loading branch information
iNinja and westin-m authored Nov 25, 2024
1 parent 6150749 commit 9463f20
Show file tree
Hide file tree
Showing 9 changed files with 496 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,28 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext,
actorValidationResult = innerActorValidationResult;
}

ValidationResult<ValidatedTokenType> typeValidationResult = validationParameters.TokenTypeValidator(
jsonWebToken.Typ, jsonWebToken, validationParameters, callContext);
if (!typeValidationResult.IsValid)
ValidationResult<ValidatedTokenType> typeValidationResult;

try
{
StackFrame typeValidationFailureStackFrame = StackFrames.TypeValidationFailed ??= new StackFrame(true);
return typeValidationResult.UnwrapError().AddStackFrame(typeValidationFailureStackFrame);
typeValidationResult = validationParameters.TokenTypeValidator(
jsonWebToken.Typ, jsonWebToken, validationParameters, callContext);

if (!typeValidationResult.IsValid)
return typeValidationResult.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 TokenTypeValidationError(
new MessageDetail(TokenLogMessages.IDX10275),
ValidationFailureType.TokenTypeValidatorThrew,
typeof(SecurityTokenInvalidTypeException),
ValidationError.GetCurrentStackFrame(),
jsonWebToken.Typ,
ex);
}

// The signature validation delegate is yet to be migrated to ValidationParameters.
Expand Down
5 changes: 2 additions & 3 deletions src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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
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
Expand All @@ -25,7 +24,7 @@ Microsoft.IdentityModel.Tokens.LifetimeValidationError.LifetimeValidationError(M
Microsoft.IdentityModel.Tokens.LifetimeValidationError.NotBefore.get -> System.DateTime?
Microsoft.IdentityModel.Tokens.TokenTypeValidationError
Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.TokenTypeValidationError._invalidTokenType -> string
Microsoft.IdentityModel.Tokens.TokenTypeValidationError.InvalidTokenType.get -> string
Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> System.TimeProvider
Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void
Microsoft.IdentityModel.Tokens.ValidationError.AddCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> Microsoft.IdentityModel.Tokens.ValidationError
Expand All @@ -39,7 +38,7 @@ Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.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.TokenTypeValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenTypeValidationError
static Microsoft.IdentityModel.Tokens.Utility.SerializeAsSingleCommaDelimitedString(System.Collections.Generic.IList<string> strings) -> string
static Microsoft.IdentityModel.Tokens.ValidationError.GetCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> System.Diagnostics.StackFrame
static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.IssuerValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.IdentityModel.Tokens/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 IDX10275 = "IDX10275: TokenTypeValidationDelegate 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.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ namespace Microsoft.IdentityModel.Tokens
{
internal class TokenTypeValidationError : ValidationError
{
protected string? _invalidTokenType;

internal TokenTypeValidationError(
MessageDetail messageDetail,
ValidationFailureType validationFailureType,
Expand All @@ -20,7 +18,7 @@ internal TokenTypeValidationError(
Exception? innerException = null)
: base(messageDetail, validationFailureType, exceptionType, stackFrame, innerException)
{
_invalidTokenType = invalidTokenType;
InvalidTokenType = invalidTokenType;
}

internal override Exception GetException()
Expand All @@ -29,14 +27,24 @@ internal override Exception GetException()
{
SecurityTokenInvalidTypeException exception = new(MessageDetail.Message, InnerException)
{
InvalidType = _invalidTokenType
InvalidType = InvalidTokenType
};
exception.SetValidationError(this);

return exception;
}

return base.GetException();
}

internal static new TokenTypeValidationError NullParameter(string parameterName, StackFrame stackFrame) => new(
MessageDetail.NullParameter(parameterName),
ValidationFailureType.NullArgument,
typeof(SecurityTokenArgumentNullException),
stackFrame,
null); // invalidTokenType

protected string? InvalidTokenType { get; }
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,10 @@ private class XmlValidationFailure : ValidationFailureType { internal XmlValidat
/// </summary>
public static readonly ValidationFailureType IssuerValidatorThrew = new IssuerValidatorFailure("IssuerValidatorThrew");
private class IssuerValidatorFailure : ValidationFailureType { internal IssuerValidatorFailure(string name) : base(name) { } }

/// <summary>
/// Defines a type that represents the fact that the token type validation delegate threw an exception.
/// </summary>
public static readonly ValidationFailureType TokenTypeValidatorThrew = new TokenTypeValidationFailure("TokenTypeValidatorThrew");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.IdentityModel.Logging;

Expand Down Expand Up @@ -45,14 +44,14 @@ internal static ValidationResult<ValidatedTokenType> ValidateTokenType(
#pragma warning restore CA1801 // TODO: remove pragma disable once callContext is used for logging
{
if (securityToken == null)
return ValidationError.NullParameter(
return TokenTypeValidationError.NullParameter(
nameof(securityToken),
new StackFrame(true));
ValidationError.GetCurrentStackFrame());

if (validationParameters == null)
return ValidationError.NullParameter(
return TokenTypeValidationError.NullParameter(
nameof(validationParameters),
new StackFrame(true));
ValidationError.GetCurrentStackFrame());

if (validationParameters.ValidTypes.Count == 0)
{
Expand All @@ -66,7 +65,7 @@ internal static ValidationResult<ValidatedTokenType> ValidateTokenType(
new MessageDetail(LogMessages.IDX10256),
ValidationFailureType.TokenTypeValidationFailed,
typeof(SecurityTokenInvalidTypeException),
new StackFrame(true),
ValidationError.GetCurrentStackFrame(),
null); // even if it is empty, we report null to match the original behaviour.

if (!validationParameters.ValidTypes.Contains(type, StringComparer.Ordinal))
Expand All @@ -78,7 +77,7 @@ internal static ValidationResult<ValidatedTokenType> ValidateTokenType(
LogHelper.MarkAsNonPII(Utility.SerializeAsSingleCommaDelimitedString(validationParameters.ValidTypes))),
ValidationFailureType.TokenTypeValidationFailed,
typeof(SecurityTokenInvalidTypeException),
new StackFrame(true),
ValidationError.GetCurrentStackFrame(),
type);
}

Expand Down
Loading

0 comments on commit 9463f20

Please sign in to comment.