Skip to content

Commit

Permalink
Extensibility tests: Issuer signing key - JWT, SAML and SAML2 (#3029)
Browse files Browse the repository at this point in the history
* Added failure type and log message for the case where the issuer signing key validator throws an exception

* Added IssuerSigningKeyValidationError and updated its use within the signing key validation

* Removed optionality from the CallContext in the issuer signing key validation delegate, updated the test skip validation delegates

(cherry picked from commit a4476e1)

* Added custom validation delegates and validation errors for issuer signing key extensibility testing

(cherry picked from commit ad1e0bd)

* Handle the case where the issuer signing key validator throws an exception

(cherry picked from commit f7b0db7)

* Added extensibility tests for issuer signing key validation

(cherry picked from commit e432f8c)

* Updated validation failure type position in tests

* Apply suggestions from code review

Co-authored-by: jennyf19 <jeferrie@microsoft.com>

* Added missing SecurityKey to the legacy implementation of ValidateIssuerSigningKey

---------

Co-authored-by: jennyf19 <jeferrie@microsoft.com>
  • Loading branch information
iNinja and jennyf19 authored Nov 25, 2024
1 parent 8fd166c commit ae57a3c
Show file tree
Hide file tree
Showing 16 changed files with 1,198 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -383,13 +383,27 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext,
return signatureValidationResult.UnwrapError().AddStackFrame(signatureValidationFailureStackFrame);
}

ValidationResult<ValidatedSigningKeyLifetime> issuerSigningKeyValidationResult =
validationParameters.IssuerSigningKeyValidator(
ValidationResult<ValidatedSigningKeyLifetime> issuerSigningKeyValidationResult;

try
{
issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator(
jsonWebToken.SigningKey, jsonWebToken, validationParameters, configuration, callContext);
if (!issuerSigningKeyValidationResult.IsValid)

if (!issuerSigningKeyValidationResult.IsValid)
return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
StackFrame issuerSigningKeyValidationFailureStackFrame = StackFrames.IssuerSigningKeyValidationFailed ??= new StackFrame(true);
return issuerSigningKeyValidationResult.UnwrapError().AddStackFrame(issuerSigningKeyValidationFailureStackFrame);
return new IssuerSigningKeyValidationError(
new MessageDetail(TokenLogMessages.IDX10274),
ValidationFailureType.IssuerSigningKeyValidatorThrew,
typeof(SecurityTokenInvalidSigningKeyException),
ValidationError.GetCurrentStackFrame(),
jsonWebToken.SigningKey,
ex);
}

return new ValidatedToken(jsonWebToken, this, validationParameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,32 @@ internal async Task<ValidationResult<ValidatedToken>> ValidateTokenAsync(
return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed);
}

ValidationResult<ValidatedSigningKeyLifetime> issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator(
samlToken.SigningKey,
samlToken,
validationParameters,
null,
callContext);
ValidationResult<ValidatedSigningKeyLifetime> issuerSigningKeyValidationResult;

try
{
issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator(
samlToken.SigningKey,
samlToken,
validationParameters,
null,
callContext);

if (!issuerSigningKeyValidationResult.IsValid)
return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame();
if (!issuerSigningKeyValidationResult.IsValid)
return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
return new IssuerSigningKeyValidationError(
new MessageDetail(Tokens.LogMessages.IDX10274),
ValidationFailureType.IssuerSigningKeyValidatorThrew,
typeof(SecurityTokenInvalidSigningKeyException),
ValidationError.GetCurrentStackFrame(),
samlToken.SigningKey,
ex);
}

return new ValidatedToken(samlToken, this, validationParameters);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,31 @@ internal async Task<ValidationResult<ValidatedToken>> ValidateTokenAsync(
return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed);
}

var issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator(
samlToken.SigningKey,
samlToken,
validationParameters,
null,
callContext);
ValidationResult<ValidatedSigningKeyLifetime> issuerSigningKeyValidationResult;

if (!issuerSigningKeyValidationResult.IsValid)
try
{
StackFrames.IssuerSigningKeyValidationFailed ??= new StackFrame(true);
return issuerSigningKeyValidationResult.UnwrapError().AddStackFrame(StackFrames.IssuerSigningKeyValidationFailed);
issuerSigningKeyValidationResult = validationParameters.IssuerSigningKeyValidator(
samlToken.SigningKey,
samlToken,
validationParameters,
null,
callContext);

if (!issuerSigningKeyValidationResult.IsValid)
return issuerSigningKeyValidationResult.UnwrapError().AddCurrentStackFrame();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
return new IssuerSigningKeyValidationError(
new MessageDetail(Tokens.LogMessages.IDX10274),
ValidationFailureType.IssuerSigningKeyValidatorThrew,
typeof(SecurityTokenInvalidSigningKeyException),
ValidationError.GetCurrentStackFrame(),
samlToken.SigningKey,
ex);
}

return new ValidatedToken(samlToken, this, validationParameters);
Expand Down
8 changes: 7 additions & 1 deletion src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ const Microsoft.IdentityModel.Tokens.LogMessages.IDX10276 = "IDX10276: TokenRepl
Microsoft.IdentityModel.Tokens.AlgorithmValidationError
Microsoft.IdentityModel.Tokens.AlgorithmValidationError.AlgorithmValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidAlgorithm, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.AlgorithmValidationError.InvalidAlgorithm.get -> string
Microsoft.IdentityModel.Tokens.AlgorithmValidationError._invalidAlgorithm -> string
Microsoft.IdentityModel.Tokens.AudienceValidationError.AudienceValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Collections.Generic.IList<string> tokenAudiences, System.Collections.Generic.IList<string> validAudiences, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.AudienceValidationError.TokenAudiences.get -> System.Collections.Generic.IList<string>
Microsoft.IdentityModel.Tokens.AudienceValidationError.TokenAudiences.set -> void
Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidAudiences.get -> System.Collections.Generic.IList<string>
Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidAudiences.set -> void
Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError
Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.InvalidSigningKey.get -> Microsoft.IdentityModel.Tokens.SecurityKey
Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.IssuerSigningKeyValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, Microsoft.IdentityModel.Tokens.SecurityKey invalidSigningKey, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.IssuerValidationError.InvalidIssuer.get -> string
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration = 1 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource
Expand All @@ -39,16 +43,18 @@ Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> Sys
Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void
Microsoft.IdentityModel.Tokens.ValidationError.AddCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> Microsoft.IdentityModel.Tokens.ValidationError
Microsoft.IdentityModel.Tokens.ValidationError.GetException(System.Type exceptionType, System.Exception innerException) -> System.Exception
Microsoft.IdentityModel.Tokens.ValidationError.ValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType failureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.ValidationError.ValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationDelegate
Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.set -> void
Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.Error.get -> Microsoft.IdentityModel.Tokens.ValidationError
Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.IsValid.get -> bool
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.SignatureValidationError.GetException() -> System.Exception
override Microsoft.IdentityModel.Tokens.TokenReplayValidationError.GetException() -> System.Exception
override Microsoft.IdentityModel.Tokens.TokenTypeValidationError.GetException() -> System.Exception
static Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError
static Microsoft.IdentityModel.Tokens.SignatureValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.SignatureValidationError
static Microsoft.IdentityModel.Tokens.TokenReplayValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenReplayValidationError
static Microsoft.IdentityModel.Tokens.TokenTypeValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenTypeValidationError
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.IdentityModel.Tokens/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ internal static class LogMessages
public const string IDX10269 = "IDX10269: IssuerValidationDelegate threw an exception, see inner exception.";
public const string IDX10272 = "IDX10272: SignatureValidationDelegate threw an exception, see inner exception.";
public const string IDX10273 = "IDX10273: AlgorithmValidationDelegate threw an exception, see inner exception.";
public const string IDX10274 = "IDX10274: IssuerSigningKeyValidationDelegate threw an exception, see inner exception.";
public const string IDX10275 = "IDX10275: TokenTypeValidationDelegate threw an exception, see inner exception.";
public const string IDX10276 = "IDX10276: TokenReplayValidationDelegate threw an exception, see inner exception.";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Diagnostics;
using System;

#nullable enable
namespace Microsoft.IdentityModel.Tokens
{
internal class IssuerSigningKeyValidationError : ValidationError
{
internal IssuerSigningKeyValidationError(
MessageDetail messageDetail,
ValidationFailureType validationFailureType,
Type exceptionType,
StackFrame stackFrame,
SecurityKey? invalidSigningKey,
Exception? innerException = null)
: base(messageDetail, validationFailureType, exceptionType, stackFrame, innerException)
{
InvalidSigningKey = invalidSigningKey;
}

internal override Exception GetException()
{
if (ExceptionType == typeof(SecurityTokenInvalidSigningKeyException))
{
SecurityTokenInvalidSigningKeyException? exception = new(MessageDetail.Message, InnerException)
{
SigningKey = InvalidSigningKey
};
exception.SetValidationError(this);

return exception;
}

return base.GetException();
}

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

protected SecurityKey? InvalidSigningKey { get; }
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ internal class ValidationError
/// Creates an instance of <see cref="ValidationError"/>
/// </summary>
/// <param name="messageDetail"/> contains information about the exception that is used to generate the exception message.
/// <param name="failureType"/> is the type of validation failure that occurred.
/// <param name="validationFailureType"/> is the type of validation failure that occurred.
/// <param name="exceptionType"/> is the type of exception that occurred.
/// <param name="stackFrame"/> is the stack frame where the exception occurred.
/// <param name="innerException"/> is the inner exception that occurred.
internal ValidationError(
MessageDetail messageDetail,
ValidationFailureType failureType,
ValidationFailureType validationFailureType,
Type exceptionType,
StackFrame stackFrame,
Exception? innerException = null)
{
InnerException = innerException;
MessageDetail = messageDetail;
_exceptionType = exceptionType;
FailureType = failureType;
FailureType = validationFailureType;
StackFrames = new List<StackFrame>(4)
{
stackFrame
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ private class SignatureAlgorithmValidationFailure : ValidationFailureType { inte
/// <summary>
/// Defines a type that represents that signing key validation failed.
/// </summary>
public static readonly ValidationFailureType SigningKeyValidationFailed = new SigningKeyValidationFailure("SigningKeyValidationFailed");
private class SigningKeyValidationFailure : ValidationFailureType { internal SigningKeyValidationFailure(string name) : base(name) { } }
public static readonly ValidationFailureType SigningKeyValidationFailed = new IssuerSigningKeyValidationFailure("IssuerSigningKeyValidationFailed");
private class IssuerSigningKeyValidationFailure : ValidationFailureType { internal IssuerSigningKeyValidationFailure(string name) : base(name) { } }

/// <summary>
/// Defines a type that represents that lifetime validation failed.
Expand Down Expand Up @@ -140,6 +140,11 @@ private class XmlValidationFailure : ValidationFailureType { internal XmlValidat
public static readonly ValidationFailureType IssuerValidatorThrew = new IssuerValidatorFailure("IssuerValidatorThrew");
private class IssuerValidatorFailure : ValidationFailureType { internal IssuerValidatorFailure(string name) : base(name) { } }

/// <summary>
/// Defines a type that represents the fact that the issuer signing key validation delegate threw an exception.
/// </summary>
public static readonly ValidationFailureType IssuerSigningKeyValidatorThrew = new IssuerSigningKeyValidationFailure("IssuerSigningKeyValidatorThrew");

/// <summary>
/// Defines a type that represents the fact that the signature validation delegate threw an exception.
/// </summary>
Expand Down
Loading

0 comments on commit ae57a3c

Please sign in to comment.