Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression tests: Issuer #2868

Merged
merged 10 commits into from
Oct 15, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10001 = "IDX10001: Invalid argument '{0}'. Argument must be of type '{1}'." -> string
Microsoft.IdentityModel.Tokens.IssuerValidationError
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10001 = "IDX10001: Invalid argument '{0}'. Argument must be of type '{1}'." -> string
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10502 = "IDX10502: Signature validation failed. The token's kid is: '{0}', but did not match any keys in ValidationParameters or Configuration and TryAllIssuerSigningKeys is false. Number of keys in ValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'.\ntoken: '{3}'." -> string
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10518 = "IDX10518: Signature validation failed. Algorithm validation failed with error: '{0}'." -> string
Microsoft.IdentityModel.Tokens.AlgorithmValidationDelegate
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.DecryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.DecryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.EncryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignWithRsaCryptoServiceProviderProxyUsingOffset(byte[] bytes, int offset, int length) -> byte[]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
Original file line number Diff line number Diff line change
@@ -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 IssuerValidationError : ValidationError
{
private string? _invalidIssuer;

internal IssuerValidationError(
MessageDetail messageDetail,
Type exceptionType,
StackFrame stackFrame,
string? invalidIssuer)
: base(messageDetail, ValidationFailureType.IssuerValidationFailed, exceptionType, stackFrame)
{
_invalidIssuer = invalidIssuer;
}

public override Exception GetException()
{
if (ExceptionType == typeof(SecurityTokenInvalidIssuerException))
{
SecurityTokenInvalidIssuerException exception = new(MessageDetail.Message, InnerException)
{
InvalidIssuer = _invalidIssuer
};

return exception;
}

return base.GetException();
}
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn
{
if (string.IsNullOrWhiteSpace(issuer))
{
return new ValidationError(
return new IssuerValidationError(
new MessageDetail(LogMessages.IDX10211),
ValidationFailureType.IssuerValidationFailed,
typeof(SecurityTokenInvalidIssuerException),
new StackFrame(true));
new StackFrame(true),
issuer);
}

if (validationParameters == null)
Expand All @@ -84,11 +84,11 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn

// Return failed IssuerValidationResult if all possible places to validate against are null or empty.
if (validationParameters.ValidIssuers.Count == 0 && string.IsNullOrWhiteSpace(configuration?.Issuer))
return new ValidationError(
return new IssuerValidationError(
new MessageDetail(LogMessages.IDX10211),
ValidationFailureType.IssuerValidationFailed,
typeof(SecurityTokenInvalidIssuerException),
new StackFrame(true));
new StackFrame(true),
issuer);

if (configuration != null)
{
Expand Down Expand Up @@ -130,15 +130,15 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn
}
}

return new ValidationError(
return new IssuerValidationError(
new MessageDetail(
LogMessages.IDX10212,
LogHelper.MarkAsNonPII(issuer),
LogHelper.MarkAsNonPII(Utility.SerializeAsSingleCommaDelimitedString(validationParameters.ValidIssuers)),
LogHelper.MarkAsNonPII(configuration?.Issuer)),
ValidationFailureType.IssuerValidationFailed,
typeof(SecurityTokenInvalidIssuerException),
new StackFrame(true));
new StackFrame(true),
issuer);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public async Task ValidateTokenAsync_Audience(ValidateTokenAsyncAudienceTheoryDa
{
var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_Audience", theoryData);

string jwtString = CreateToken(theoryData.Audience);
string jwtString = CreateTokenWithAudience(theoryData.Audience);

await ValidateAndCompareResults(jwtString, theoryData, context);

Expand Down Expand Up @@ -155,7 +155,7 @@ public ValidateTokenAsyncAudienceTheoryData(string testId) : base(testId) { }
public string? Audience { get; internal set; } = Default.Audience;
}

private static string CreateToken(string? audience)
private static string CreateTokenWithAudience(string? audience)
{
JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler();

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

#nullable enable
using System.Threading.Tasks;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.TestUtils;
using Microsoft.IdentityModel.Tokens;
using Xunit;

namespace Microsoft.IdentityModel.JsonWebTokens.Tests
{
public partial class JsonWebTokenHandlerValidateTokenAsyncTests
{
[Theory, MemberData(nameof(ValidateTokenAsync_IssuerTestCases), DisableDiscoveryEnumeration = true)]
public async Task ValidateTokenAsync_Issuer(ValidateTokenAsyncIssuerTheoryData theoryData)
{
var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_Issuer", theoryData);

string jwtString = CreateTokenWithIssuer(theoryData.TokenIssuer);

await ValidateAndCompareResults(jwtString, theoryData, context);

TestUtilities.AssertFailIfErrors(context);
}

public static TheoryData<ValidateTokenAsyncIssuerTheoryData> ValidateTokenAsync_IssuerTestCases
{
get
{
return new TheoryData<ValidateTokenAsyncIssuerTheoryData>
{
new ValidateTokenAsyncIssuerTheoryData("Valid_IssuerIsValidIssuer")
{
TokenIssuer = Default.Issuer,
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
},
new ValidateTokenAsyncIssuerTheoryData("Valid_IssuerIsConfigurationIssuer")
{
TokenIssuer = Default.Issuer,
TokenValidationParameters = CreateTokenValidationParameters(configurationIssuer: Default.Issuer),
ValidationParameters = CreateValidationParameters(configurationIssuer: Default.Issuer),
},
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsNotValid")
{
TokenIssuer = "InvalidIssuer",
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
ExpectedIsValid = false,
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10205:"),
ExpectedExceptionValidationParameters = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10212:"),
},
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsNull")
{
TokenIssuer = null,
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
ExpectedIsValid = false,
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
},
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsEmpty")
{
TokenIssuer = string.Empty,
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
ExpectedIsValid = false,
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
},
new ValidateTokenAsyncIssuerTheoryData("Invalid_NoValidIssuersProvided")
{
TokenIssuer = Default.Issuer,
TokenValidationParameters = CreateTokenValidationParameters(),
ValidationParameters = CreateValidationParameters(),
ExpectedIsValid = false,
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10204:"),
ExpectedExceptionValidationParameters = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
},
};

static TokenValidationParameters CreateTokenValidationParameters(
string? validIssuer = null, string? configurationIssuer = null)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidateTokenReplay = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = Default.AsymmetricSigningKey,
ValidAudiences = [Default.Audience],
ValidIssuer = validIssuer
};

if (configurationIssuer is not null)
{
var validConfig = new OpenIdConnectConfiguration() { Issuer = configurationIssuer };
tokenValidationParameters.ConfigurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(validConfig);
}

return tokenValidationParameters;
}

static ValidationParameters CreateValidationParameters(
string? validIssuer = null, string? configurationIssuer = null)
{
ValidationParameters validationParameters = new ValidationParameters();
validationParameters.ValidAudiences.Add(Default.Audience);
validationParameters.IssuerSigningKeys.Add(Default.AsymmetricSigningKey);

if (configurationIssuer is not null)
{
var validConfig = new OpenIdConnectConfiguration() { Issuer = configurationIssuer };
validationParameters.ConfigurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(validConfig);
}

if (validIssuer is not null)
validationParameters.ValidIssuers.Add(validIssuer);

return validationParameters;
}
}
}

public class ValidateTokenAsyncIssuerTheoryData : ValidateTokenAsyncBaseTheoryData
{
public ValidateTokenAsyncIssuerTheoryData(string testId) : base(testId) { }

public string? TokenIssuer { get; set; }
}

private static string CreateTokenWithIssuer(string? issuer)
{
JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler();

SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor
{
Subject = Default.ClaimsIdentity,
SigningCredentials = Default.AsymmetricSigningCredentials,
Audience = Default.Audience,
Issuer = issuer,
};

return jsonWebTokenHandler.CreateToken(securityTokenDescriptor);
}
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public async Task ValidateTokenAsync_Lifetime(ValidateTokenAsyncLifetimeTheoryDa
{
var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_Lifetime", theoryData);

string jwtString = CreateToken(theoryData.IssuedAt, theoryData.NotBefore, theoryData.Expires);
string jwtString = CreateTokenWithLifetime(theoryData.IssuedAt, theoryData.NotBefore, theoryData.Expires);

await ValidateAndCompareResults(jwtString, theoryData, context);

Expand Down Expand Up @@ -155,7 +155,7 @@ public ValidateTokenAsyncLifetimeTheoryData(string testId) : base(testId) { }
public DateTime? Expires { get; set; }
}

private static string CreateToken(DateTime? issuedAt, DateTime? notBefore, DateTime? expires)
private static string CreateTokenWithLifetime(DateTime? issuedAt, DateTime? notBefore, DateTime? expires)
{
JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler();
jsonWebTokenHandler.SetDefaultTimesOnTokenCreation = false; // Allow for null values to be passed in to validate.
Expand Down
Loading