Skip to content

Commit

Permalink
Added extensibility tests for issuer signing key validation
Browse files Browse the repository at this point in the history
  • Loading branch information
iNinja committed Nov 20, 2024
1 parent f7b0db7 commit e432f8c
Show file tree
Hide file tree
Showing 3 changed files with 850 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.IdentityModel.JsonWebTokens.Tests;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.TestUtils;
using Microsoft.IdentityModel.Tokens;
using Xunit;

#nullable enable
namespace Microsoft.IdentityModel.JsonWebTokens.Extensibility.Tests
{
public partial class JsonWebTokenHandlerValidateTokenAsyncTests
{
[Theory, MemberData(nameof(IssuerSigningKey_ExtensibilityTestCases), DisableDiscoveryEnumeration = true)]
public async Task ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility(IssuerSigningKeyExtensibilityTheoryData theoryData)
{
var context = TestUtilities.WriteHeader($"{this}.{nameof(ValidateTokenAsync_IssuerSigningKeyValidator_Extensibility)}", theoryData);
context.IgnoreType = false;
for (int i = 0; i < theoryData.ExtraStackFrames; i++)
theoryData.IssuerSigningKeyValidationError!.AddStackFrame(new StackFrame(false));

try
{
ValidationResult<ValidatedToken> validationResult = await theoryData.JsonWebTokenHandler.ValidateTokenAsync(
theoryData.JsonWebToken!,
theoryData.ValidationParameters!,
theoryData.CallContext,
CancellationToken.None);

if (validationResult.IsValid)
{
context.AddDiff("validationResult.IsValid is true, expected false");
}
else
{
ValidationError validationError = validationResult.UnwrapError();
IdentityComparer.AreValidationErrorsEqual(validationError, theoryData.IssuerSigningKeyValidationError, context);
theoryData.ExpectedException.ProcessException(validationError.GetException(), context);
}
}
catch (Exception ex)
{
theoryData.ExpectedException.ProcessException(ex, context);
}

TestUtilities.AssertFailIfErrors(context);
}

public static TheoryData<IssuerSigningKeyExtensibilityTheoryData> IssuerSigningKey_ExtensibilityTestCases
{
get
{
var theoryData = new TheoryData<IssuerSigningKeyExtensibilityTheoryData>();
CallContext callContext = new CallContext();
var utcNow = DateTime.UtcNow;
var utcPlusOneHour = utcNow + TimeSpan.FromHours(1);

#region return CustomIssuerSigningKeyValidationError
// Test cases where delegate is overridden and return a CustomIssuerSigningKeyValidationError
// CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"CustomIssuerSigningKeyValidatorDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate,
extraStackFrames: 2)
{
ExpectedException = new ExpectedException(
typeof(SecurityTokenInvalidSigningKeyException),
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate)),
IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorDelegate), null),
typeof(SecurityTokenInvalidSigningKeyException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 160),
null,
ValidationFailureType.SigningKeyValidationFailed)
});

// CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"CustomIssuerSigningKeyValidatorCustomExceptionDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate,
extraStackFrames: 2)
{
ExpectedException = new ExpectedException(
typeof(CustomSecurityTokenInvalidSigningKeyException),
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate)),
IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionDelegate), null),
typeof(CustomSecurityTokenInvalidSigningKeyException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 175),
null,
ValidationFailureType.SigningKeyValidationFailed),
});

// CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"CustomIssuerSigningKeyValidatorUnknownExceptionDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate,
extraStackFrames: 2)
{
// CustomIssuerSigningKeyValidationError 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(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate))),
IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorUnknownExceptionDelegate), null),
typeof(NotSupportedException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 205),
null,
ValidationFailureType.SigningKeyValidationFailed),
});

// CustomIssuerSigningKeyValidationError : IssuerSigningKeyValidationError, ExceptionType: NotSupportedException : SystemException, ValidationFailureType: CustomAudienceValidationFailureType
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate,
extraStackFrames: 2)
{
ExpectedException = new ExpectedException(
typeof(CustomSecurityTokenInvalidSigningKeyException),
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate)),
IssuerSigningKeyValidationError = new CustomIssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.CustomIssuerSigningKeyValidatorCustomExceptionCustomFailureTypeDelegate), null),
typeof(CustomSecurityTokenInvalidSigningKeyException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 190),
null,
CustomIssuerSigningKeyValidationError.CustomIssuerSigningKeyValidationFailureType),
});
#endregion

#region return IssuerSigningKeyValidationError
// Test cases where delegate is overridden and return an IssuerSigningKeyValidationError
// IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"IssuerSigningKeyValidatorDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate,
extraStackFrames: 2)
{
ExpectedException = new ExpectedException(
typeof(SecurityTokenInvalidSigningKeyException),
nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate)),
IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorDelegate), null),
typeof(SecurityTokenInvalidSigningKeyException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 235),
null,
ValidationFailureType.SigningKeyValidationFailed)
});

// IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenInvalidIssuerSigningKeyException : SecurityTokenInvalidIssuerSigningKeyException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate,
extraStackFrames: 2)
{
// IssuerSigningKeyValidationError does not handle the exception type 'CustomSecurityTokenInvalidIssuerSigningKeyException'
ExpectedException = ExpectedException.SecurityTokenException(
LogHelper.FormatInvariant(
Tokens.LogMessages.IDX10002, // "IDX10002: Unknown exception type returned. Type: '{0}'. Message: '{1}'.";
typeof(CustomSecurityTokenInvalidSigningKeyException),
nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate))),
IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomIssuerSigningKeyExceptionTypeDelegate), null),
typeof(CustomSecurityTokenInvalidSigningKeyException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 259),
null,
ValidationFailureType.SigningKeyValidationFailed)
});

// IssuerSigningKeyValidationError : ValidationError, ExceptionType: CustomSecurityTokenException : SystemException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"IssuerSigningKeyValidatorCustomExceptionTypeDelegate",
utcNow,
CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate,
extraStackFrames: 2)
{
// IssuerSigningKeyValidationError 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(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate))),
IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError(
new MessageDetail(
nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorCustomExceptionTypeDelegate), null),
typeof(CustomSecurityTokenException),
new StackFrame("CustomIssuerSigningKeyValidationDelegates.cs", 274),
null,
ValidationFailureType.SigningKeyValidationFailed)
});

// IssuerSigningKeyValidationError : ValidationError, ExceptionType: SecurityTokenInvalidIssuerSigningKeyException, inner: CustomSecurityTokenInvalidIssuerSigningKeyException
theoryData.Add(new IssuerSigningKeyExtensibilityTheoryData(
"IssuerSigningKeyValidatorThrows",
utcNow,
CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows,
extraStackFrames: 1)
{
ExpectedException = new ExpectedException(
typeof(SecurityTokenInvalidSigningKeyException),
string.Format(Tokens.LogMessages.IDX10274),
typeof(CustomSecurityTokenInvalidSigningKeyException)),
IssuerSigningKeyValidationError = new IssuerSigningKeyValidationError(
new MessageDetail(
string.Format(Tokens.LogMessages.IDX10274), null),
typeof(SecurityTokenInvalidSigningKeyException),
new StackFrame("JsonWebTokenHandler.ValidateToken.Internal.cs", 250),
null,
ValidationFailureType.IssuerSigningKeyValidatorThrew,
new SecurityTokenInvalidSigningKeyException(nameof(CustomIssuerSigningKeyValidationDelegates.IssuerSigningKeyValidatorThrows))
)
});
#endregion

return theoryData;
}
}

public class IssuerSigningKeyExtensibilityTheoryData : ValidateTokenAsyncBaseTheoryData
{
internal IssuerSigningKeyExtensibilityTheoryData(string testId, DateTime utcNow, IssuerSigningKeyValidationDelegate issuerSigningKeyValidator, int extraStackFrames) : base(testId)
{
JsonWebToken = JsonWebTokenHandler.ReadJsonWebToken(
JsonWebTokenHandler.CreateToken(
new SecurityTokenDescriptor()
{
IssuedAt = utcNow,
NotBefore = utcNow,
Expires = utcNow + TimeSpan.FromHours(1),
}));

ValidationParameters = new ValidationParameters
{
AlgorithmValidator = SkipValidationDelegates.SkipAlgorithmValidation,
AudienceValidator = SkipValidationDelegates.SkipAudienceValidation,
IssuerValidatorAsync = SkipValidationDelegates.SkipIssuerValidation,
IssuerSigningKeyValidator = issuerSigningKeyValidator,
LifetimeValidator = SkipValidationDelegates.SkipLifetimeValidation,
SignatureValidator = (SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext? callContext) =>
{
token.SigningKey = SigningKey;

return SigningKey;
},
TokenReplayValidator = SkipValidationDelegates.SkipTokenReplayValidation,
TokenTypeValidator = SkipValidationDelegates.SkipTokenTypeValidation
};

ExtraStackFrames = extraStackFrames;
}

public JsonWebToken JsonWebToken { get; }

public JsonWebTokenHandler JsonWebTokenHandler { get; } = new JsonWebTokenHandler();

public bool IsValid { get; set; }

public SecurityKey SigningKey { get; set; } = KeyingMaterial.DefaultX509SigningCreds_2048_RsaSha2_Sha2.Key;

internal IssuerSigningKeyValidationError? IssuerSigningKeyValidationError { get; set; }

internal int ExtraStackFrames { get; }
}
}
}
#nullable restore
Loading

0 comments on commit e432f8c

Please sign in to comment.