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

SAML and SAML2 Extensibility Testing: Audience #3006

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8df289b
Updated JWT issuer extensibility tests to highlight the scenarios whe…
iNinja Nov 12, 2024
fa09f97
Updated ValidationError comparison to ensure the generated exception …
iNinja Nov 12, 2024
cacfd73
Updated the validation errors and custom exceptions to provide the ex…
iNinja Nov 12, 2024
64294e8
Handle potential exception thrown by custom issuer validation delegat…
iNinja Nov 12, 2024
93bc465
Added tests for issuer extensibility on SAML
iNinja Nov 12, 2024
2b4a743
Added exception handling to SAML2 issuer validation. Added issuer ext…
iNinja Nov 12, 2024
3495724
Updated comment around stack trace comparison
iNinja Nov 12, 2024
8a1706f
Renamed file to align better with the other extensibility tests
iNinja Nov 12, 2024
4da5a32
Replaced static audience validation stack frames with simplified caching
iNinja Nov 12, 2024
62e862b
Added custom exceptions, validation errors, and validation delegates …
iNinja Nov 12, 2024
e4e98c2
Added nullability annotations to ValidationError, removed unused refe…
iNinja Nov 12, 2024
e2b55e2
Updated AudienceValidationError to provide the stack trace when gener…
iNinja Nov 12, 2024
0d9980d
Renamed and aligned JWT audience extensbiility tests to match the sty…
iNinja Nov 12, 2024
7dcc1eb
Added log message for audience validation delegate throwing
iNinja Nov 12, 2024
af4426e
Updated unused line parameter for the test stack frames
iNinja Nov 14, 2024
a43a234
Handle audience validation delegate exception in SAML. Added tests
iNinja Nov 14, 2024
b0fcd7b
Handle audience validation delegate exception in SAML2. Added tests
iNinja Nov 14, 2024
fbf54b3
Merge branch 'dev' into iinglese/extensibility-testing-audience
iNinja Nov 14, 2024
d79f7af
Moved custom exceptions, validation errors, and validation delegates …
iNinja Nov 14, 2024
40e2d72
Updated tests to match the renamed files
iNinja Nov 14, 2024
4978669
Merge branch 'dev' into iinglese/extensibility-testing-audience
iNinja Nov 14, 2024
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
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),
ValidationFailureType.AudienceValidatorThrew,
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
tokenAudiences,
null,
ex);
}

ValidationResult<ValidatedIssuer> issuerValidationResult;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -60,22 +61,34 @@ internal async Task<ValidationResult<ValidatedToken>> ValidateTokenAsync(
ValidationResult<ValidatedConditions> conditionsResult = ValidateConditions(samlToken, validationParameters, callContext);

if (!conditionsResult.IsValid)
return conditionsResult.UnwrapError().AddCurrentStackFrame();

try
{
StackFrames.AssertionConditionsValidationFailed ??= new StackFrame(true);
return conditionsResult.UnwrapError().AddStackFrame(StackFrames.AssertionConditionsValidationFailed);
ValidationResult<ValidatedIssuer> issuerValidationResult = await validationParameters.IssuerValidatorAsync(
samlToken.Issuer,
samlToken,
validationParameters,
callContext,
cancellationToken).ConfigureAwait(false);

if (!issuerValidationResult.IsValid)
{
StackFrames.IssuerValidationFailed ??= new StackFrame(true);
return issuerValidationResult.UnwrapError().AddStackFrame(StackFrames.IssuerValidationFailed);
}
}

ValidationResult<ValidatedIssuer> issuerValidationResult = await validationParameters.IssuerValidatorAsync(
samlToken.Issuer,
samlToken,
validationParameters,
callContext,
cancellationToken).ConfigureAwait(false);

if (!issuerValidationResult.IsValid)
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
StackFrames.IssuerValidationFailed ??= new StackFrame(true);
return issuerValidationResult.UnwrapError().AddStackFrame(StackFrames.IssuerValidationFailed);
return new IssuerValidationError(
new MessageDetail(Tokens.LogMessages.IDX10269),
ValidationFailureType.IssuerValidatorThrew,
typeof(SecurityTokenInvalidIssuerException),
ValidationError.GetCurrentStackFrame(),
samlToken.Issuer,
ex);
}

ValidationResult<SecurityKey> signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext);
Expand Down Expand Up @@ -145,18 +158,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),
ValidationFailureType.AudienceValidatorThrew,
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
audiencesAsList,
validationParameters.ValidAudiences,
ex);
}

validatedAudience = audienceValidationResult.UnwrapResult();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
Expand Down Expand Up @@ -69,17 +70,32 @@ internal async Task<ValidationResult<ValidatedToken>> ValidateTokenAsync(
return conditionsResult.UnwrapError().AddStackFrame(StackFrames.AssertionConditionsValidationFailed);
}

ValidationResult<ValidatedIssuer> validatedIssuerResult = await validationParameters.IssuerValidatorAsync(
samlToken.Issuer,
samlToken,
validationParameters,
callContext,
cancellationToken).ConfigureAwait(false);
try
{
ValidationResult<ValidatedIssuer> issuerValidationResult = await validationParameters.IssuerValidatorAsync(
samlToken.Issuer,
samlToken,
validationParameters,
callContext,
cancellationToken).ConfigureAwait(false);

if (!validatedIssuerResult.IsValid)
if (!issuerValidationResult.IsValid)
{
StackFrames.IssuerValidationFailed ??= new StackFrame(true);
return issuerValidationResult.UnwrapError().AddStackFrame(StackFrames.IssuerValidationFailed);
}
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
StackFrames.IssuerValidationFailed ??= new StackFrame(true);
return validatedIssuerResult.UnwrapError().AddStackFrame(StackFrames.IssuerValidationFailed);
return new IssuerValidationError(
new MessageDetail(Tokens.LogMessages.IDX10269),
ValidationFailureType.IssuerValidatorThrew,
typeof(SecurityTokenInvalidIssuerException),
ValidationError.GetCurrentStackFrame(),
samlToken.Issuer,
ex);
}

var signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext);
Expand Down Expand Up @@ -181,15 +197,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),
ValidationFailureType.AudienceValidatorThrew,
typeof(SecurityTokenInvalidAudienceException),
ValidationError.GetCurrentStackFrame(),
audiencesAsList,
validationParameters.ValidAudiences,
ex);
}

// Audience is valid, save it for later.
Expand Down
13 changes: 7 additions & 6 deletions src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
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) -> 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 failureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Collections.Generic.IList<string> tokenAudiences, System.Collections.Generic.IList<string> validAudiences) -> void
Microsoft.IdentityModel.Tokens.AudienceValidationError.AudienceValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType failureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Collections.Generic.IList<string> tokenAudiences, System.Collections.Generic.IList<string> validAudiences, System.Exception innerException) -> 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.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) -> void
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer, System.Exception innerException) -> void
Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration = 1 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource
Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationParameters = 2 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource
Microsoft.IdentityModel.Tokens.LifetimeValidationError._expires -> System.DateTime
Expand All @@ -21,20 +25,17 @@ 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.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.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
1 change: 1 addition & 0 deletions src/Microsoft.IdentityModel.Tokens/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +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
Expand Down
Loading
Loading