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

Remove exceptions thrown during issuer validation. Add validation source. #2643

Merged
merged 5 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Microsoft.IdentityModel.Tokens/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static class LogMessages
{
#pragma warning disable 1591
// general
// public const string IDX10000 = "IDX10000:";
public const string IDX10000 = "IDX10000: The parameter '{0}' cannot be a 'null' or an empty object. ";
brentschmaltz marked this conversation as resolved.
Show resolved Hide resolved

// properties, configuration
public const string IDX10101 = "IDX10101: MaximumTokenSizeInBytes must be greater than zero. value: '{0}'";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,27 @@ namespace Microsoft.IdentityModel.Tokens
/// </summary>
internal class IssuerValidationResult : ValidationResult
{
internal enum ValidationSource
iNinja marked this conversation as resolved.
Show resolved Hide resolved
{
NotValidated = 0,
IssuerIsConfigurationIssuer,
IssuerIsValidIssuer,
IssuerIsAmongValidIssuers
}

private Exception _exception;

/// <summary>
/// Creates an instance of <see cref="IssuerValidationResult"/>
/// </summary>
/// <paramref name="issuer"/> is the issuer that was validated successfully.
public IssuerValidationResult(string issuer)
/// <paramref name="source"/> is the <see cref="ValidationSource"/> indicating how this issuer was validated.
public IssuerValidationResult(string issuer, ValidationSource source = ValidationSource.NotValidated)
: base(ValidationFailureType.ValidationSucceeded)
{
Issuer = issuer;
IsValid = true;
Source = source;
}

/// <summary>
Expand All @@ -30,11 +40,13 @@ public IssuerValidationResult(string issuer)
/// <paramref name="issuer"/> is the issuer that was intended to be validated.
/// <paramref name="validationFailure"/> is the <see cref="ValidationFailureType"/> that occurred during validation.
/// <paramref name="exceptionDetail"/> is the <see cref="ExceptionDetail"/> that occurred during validation.
public IssuerValidationResult(string issuer, ValidationFailureType validationFailure, ExceptionDetail exceptionDetail)
/// <paramref name="source"/> is the <see cref="ValidationSource"/> indicating how this issuer was validated.
public IssuerValidationResult(string issuer, ValidationFailureType validationFailure, ExceptionDetail exceptionDetail, ValidationSource source = ValidationSource.NotValidated)
: base(validationFailure, exceptionDetail)
{
Issuer = issuer;
IsValid = false;
Source = source;
}

/// <summary>
Expand Down Expand Up @@ -65,5 +77,7 @@ public override Exception Exception
/// Gets the issuer that was validated or intended to be validated.
/// </summary>
public string Issuer { get; }

public ValidationSource Source { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,28 @@ internal static async Task<IssuerValidationResult> ValidateIssuerAsync(
}

if (validationParameters == null)
throw LogHelper.LogArgumentNullException(nameof(validationParameters));
return new IssuerValidationResult(
issuer,
ValidationFailureType.NullArgument,
new ExceptionDetail(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII(nameof(validationParameters))),
typeof(ArgumentNullException),
new StackFrame(true),
null));

if (securityToken == null)
throw LogHelper.LogArgumentNullException(nameof(securityToken));
return new IssuerValidationResult(
issuer,
ValidationFailureType.NullArgument,
new ExceptionDetail(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII(nameof(securityToken))),
typeof(ArgumentNullException),
new StackFrame(true),
null));

BaseConfiguration configuration = null;
if (validationParameters.ConfigurationManager != null)
Expand All @@ -234,7 +252,6 @@ internal static async Task<IssuerValidationResult> ValidateIssuerAsync(
new StackFrame(true)));
}

// TODO - we should distinguish if configuration, TVP.ValidIssuer or TVP.ValidIssuers was used to validate the issuer.
if (configuration != null)
{
if (string.Equals(configuration.Issuer, issuer))
Expand All @@ -245,13 +262,15 @@ internal static async Task<IssuerValidationResult> ValidateIssuerAsync(
if (LogHelper.IsEnabled(EventLogLevel.Informational))
LogHelper.LogInformation(LogMessages.IDX10236, LogHelper.MarkAsNonPII(issuer), callContext);

return new IssuerValidationResult(issuer);
return new IssuerValidationResult(issuer,
IssuerValidationResult.ValidationSource.IssuerIsConfigurationIssuer);
}
}

if (string.Equals(validationParameters.ValidIssuer, issuer))
{
return new IssuerValidationResult(issuer);
return new IssuerValidationResult(issuer,
IssuerValidationResult.ValidationSource.IssuerIsValidIssuer);
}

if (validationParameters.ValidIssuers != null)
Expand All @@ -271,7 +290,8 @@ internal static async Task<IssuerValidationResult> ValidateIssuerAsync(
if (LogHelper.IsEnabled(EventLogLevel.Informational))
LogHelper.LogInformation(LogMessages.IDX10236, LogHelper.MarkAsNonPII(issuer));

return new IssuerValidationResult(issuer);
return new IssuerValidationResult(issuer,
IssuerValidationResult.ValidationSource.IssuerIsAmongValidIssuers);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,9 @@ internal static bool AreIssuerValidationResultsEqual(
if (issuerValidationResult1.Issuer != issuerValidationResult2.Issuer)
localContext.Diffs.Add($"IssuerValidationResult1.Issuer: {issuerValidationResult1.Issuer} != IssuerValidationResult2.Issuer: {issuerValidationResult2.Issuer}");

if (issuerValidationResult1.Source != issuerValidationResult2.Source)
localContext.Diffs.Add($"IssuerValidationResult1.Source: {issuerValidationResult1.Source} != IssuerValidationResult2.Source: {issuerValidationResult2.Source}");

// true => both are not null.
if (ContinueCheckingEquality(issuerValidationResult1.Exception, issuerValidationResult2.Exception, localContext))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.TestUtils;
using Microsoft.IdentityModel.Tokens.Json.Tests;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Xunit;

namespace Microsoft.IdentityModel.Tokens.Validation.Tests
Expand All @@ -29,7 +30,9 @@ public async Task IssuerValidatorAsyncTests(IssuerValidationResultsTheoryData th
new CallContext(),
CancellationToken.None).ConfigureAwait(false);

theoryData.ExpectedException.ProcessException(issuerValidationResult.Exception, context);
if (issuerValidationResult.Exception != null)
theoryData.ExpectedException.ProcessException(issuerValidationResult.Exception, context);

IdentityComparer.AreIssuerValidationResultsEqual(
issuerValidationResult,
theoryData.IssuerValidationResult,
Expand Down Expand Up @@ -92,6 +95,90 @@ public static TheoryData<IssuerValidationResultsTheoryData> IssuerValdationResul
ValidationParameters = new TokenValidationParameters(),
});

theoryData.Add(new IssuerValidationResultsTheoryData("NULL_ValidationParameters")
{
ExpectedException = ExpectedException.ArgumentNullException("IDX10000:"),
Issuer = issClaim,
IssuerValidationResult = new IssuerValidationResult(
issClaim,
ValidationFailureType.NullArgument,
new ExceptionDetail(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII("validationParameters")),
typeof(ArgumentNullException),
new StackFrame(true),
null)),
IsValid = false,
SecurityToken = JsonUtilities.CreateUnsignedJsonWebToken(JwtRegisteredClaimNames.Iss, issClaim),
ValidationParameters = null
});

theoryData.Add(new IssuerValidationResultsTheoryData("NULL_SecurityToken")
{
ExpectedException = ExpectedException.ArgumentNullException("IDX10000:"),
Issuer = issClaim,
IssuerValidationResult = new IssuerValidationResult(
issClaim,
ValidationFailureType.NullArgument,
new ExceptionDetail(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII("securityToken")),
typeof(ArgumentNullException),
new StackFrame(true),
null)),
IsValid = false,
SecurityToken = null,
ValidationParameters = new TokenValidationParameters()
});

var validConfig = new OpenIdConnectConfiguration() { Issuer = issClaim };
theoryData.Add(new IssuerValidationResultsTheoryData("Valid_FromConfig")
{
ExpectedException = ExpectedException.NoExceptionExpected,
Issuer = issClaim,
IssuerValidationResult = new IssuerValidationResult(
issClaim,
IssuerValidationResult.ValidationSource.IssuerIsConfigurationIssuer),
IsValid = true,
SecurityToken = JsonUtilities.CreateUnsignedJsonWebToken(JwtRegisteredClaimNames.Iss, issClaim),
ValidationParameters = new TokenValidationParameters()
{
ConfigurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(validConfig)
}
});

theoryData.Add(new IssuerValidationResultsTheoryData("Valid_FromValidationParametersValidIssuer")
{
ExpectedException = ExpectedException.NoExceptionExpected,
Issuer = issClaim,
IssuerValidationResult = new IssuerValidationResult(
issClaim,
IssuerValidationResult.ValidationSource.IssuerIsValidIssuer),
IsValid = true,
SecurityToken = JsonUtilities.CreateUnsignedJsonWebToken(JwtRegisteredClaimNames.Iss, issClaim),
ValidationParameters = new TokenValidationParameters()
{
ValidIssuer = issClaim
}
});

theoryData.Add(new IssuerValidationResultsTheoryData("Valid_FromValidationParametersValidIssuers")
{
ExpectedException = ExpectedException.NoExceptionExpected,
Issuer = issClaim,
IssuerValidationResult = new IssuerValidationResult(
issClaim,
IssuerValidationResult.ValidationSource.IssuerIsAmongValidIssuers),
IsValid = true,
SecurityToken = JsonUtilities.CreateUnsignedJsonWebToken(JwtRegisteredClaimNames.Iss, issClaim),
ValidationParameters = new TokenValidationParameters()
{
ValidIssuers = [issClaim]
}
});

return theoryData;
}
}
Expand Down