Skip to content

Commit

Permalink
Handle potential exceptions thrown by the audience validation delegat…
Browse files Browse the repository at this point in the history
…e on JWT, SAML, and SAML2
  • Loading branch information
iNinja committed Nov 17, 2024
1 parent 2609624 commit 32ad0ac
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,30 @@ private async ValueTask<ValidationResult<ValidatedToken>> ValidateJWSAsync(
if (jsonWebToken.Audiences is not IList<string> tokenAudiences)
tokenAudiences = jsonWebToken.Audiences.ToList();

ValidationResult<string> audienceValidationResult = validationParameters.AudienceValidator(
tokenAudiences, jsonWebToken, validationParameters, callContext);
ValidationResult<string> audienceValidationResult;
try
{
audienceValidationResult = validationParameters.AudienceValidator(
tokenAudiences, jsonWebToken, validationParameters, callContext);

if (!audienceValidationResult.IsValid)
if (!audienceValidationResult.IsValid)
{
StackFrame audienceValidationFailureStackFrame = StackFrames.AudienceValidationFailed ??= new StackFrame(true);
return audienceValidationResult.UnwrapError().AddStackFrame(audienceValidationFailureStackFrame);
}
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
StackFrame audienceValidationFailureStackFrame = StackFrames.AudienceValidationFailed ??= new StackFrame(true);
return audienceValidationResult.UnwrapError().AddStackFrame(audienceValidationFailureStackFrame);
return new AudienceValidationError(
new MessageDetail(TokenLogMessages.IDX10270),
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
tokenAudiences,
null,
ValidationFailureType.AudienceValidatorThrew,
ex);
}

ValidationResult<ValidatedIssuer> issuerValidationResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,34 @@ internal virtual ValidationResult<ValidatedConditions> ValidateConditions(

if (condition is SamlAudienceRestrictionCondition audienceRestriction)
{

// AudienceRestriction.Audiences is an ICollection<Uri> so we need make a conversion to List<string> before calling our audience validator
var audiencesAsList = audienceRestriction.Audiences.Select(static x => x.OriginalString).ToList();

var audienceValidationResult = validationParameters.AudienceValidator(
audiencesAsList,
samlToken,
validationParameters,
callContext);

if (!audienceValidationResult.IsValid)
return audienceValidationResult.UnwrapError();
ValidationResult<string> audienceValidationResult;

try
{
audienceValidationResult = validationParameters.AudienceValidator(
audiencesAsList,
samlToken,
validationParameters,
callContext);

if (!audienceValidationResult.IsValid)
return audienceValidationResult.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 AudienceValidationError(
new MessageDetail(Tokens.LogMessages.IDX10270),
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
audiencesAsList,
validationParameters.ValidAudiences,
ValidationFailureType.AudienceValidatorThrew,
ex);
}

validatedAudience = audienceValidationResult.UnwrapResult();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,31 @@ internal virtual ValidationResult<ValidatedConditions> ValidateConditions(
if (audienceRestriction.Audiences is not List<string> audiencesAsList)
audiencesAsList = [.. audienceRestriction.Audiences];

var audienceValidationResult = validationParameters.AudienceValidator(
audiencesAsList,
samlToken,
validationParameters,
callContext);
if (!audienceValidationResult.IsValid)
ValidationResult<string> audienceValidationResult;

try
{
audienceValidationResult = validationParameters.AudienceValidator(
audiencesAsList,
samlToken,
validationParameters,
callContext);

if (!audienceValidationResult.IsValid)
return audienceValidationResult.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
{
StackFrames.AudienceValidationFailed ??= new StackFrame(true);
return audienceValidationResult.UnwrapError().AddStackFrame(StackFrames.AudienceValidationFailed);
return new AudienceValidationError(
new MessageDetail(Tokens.LogMessages.IDX10270),
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
audiencesAsList,
validationParameters.ValidAudiences,
ValidationFailureType.AudienceValidatorThrew,
ex);
}

// Audience is valid, save it for later.
Expand Down
7 changes: 2 additions & 5 deletions src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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.IDX10270 = "IDX10270: AudienceValidationDelegate threw an exception, see inner exception." -> string
Microsoft.IdentityModel.Tokens.AlgorithmValidationError
Microsoft.IdentityModel.Tokens.AlgorithmValidationError.AlgorithmValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidAlgorithm, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType = null, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.AlgorithmValidationError.InvalidAlgorithm.get -> string
Expand Down Expand Up @@ -34,13 +35,9 @@ 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.TokenTypeValidationError.GetException() -> System.Exception
static Microsoft.IdentityModel.Tokens.AudienceValidationError.AudiencesCountZero -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.AudienceValidationError.AudiencesNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidateAudienceFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidationParametersAudiencesCountZero -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.AudienceValidationError.ValidationParametersNull -> System.Diagnostics.StackFrame
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.AudienceValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType
static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.IssuerValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType
static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoTokenAudiencesProvided -> Microsoft.IdentityModel.Tokens.ValidationFailureType
static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.NoValidationParameterAudiencesProvided -> 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 IDX10270 = "IDX10270: AudienceValidationDelegate 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 @@ -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 that the audience validation delegate threw and exception.
/// </summary>
public static readonly ValidationFailureType AudienceValidatorThrew = new AudienceValidationFailure("AudienceValidatorThrew");
}
}

0 comments on commit 32ad0ac

Please sign in to comment.