Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedAudience.get -> string
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedAudience.set -> void
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedConditions() -> void
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedConditions(string ValidatedAudience, Microsoft.IdentityModel.Tokens.ValidatedLifetime? ValidatedLifetime) -> void
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedLifetime.get -> Microsoft.IdentityModel.Tokens.ValidatedLifetime?
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedLifetime.set -> void
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.ValidatedToken>>
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.ValidatedToken>>
Microsoft.IdentityModel.Tokens.Saml2.SamlSecurityTokenHandler.ValidateTokenAsync(SamlSecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.ValidatedToken>>
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.AssertionConditionsNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.AssertionNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.AudienceValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.LifetimeValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.OneTimeUseValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.TokenNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.TokenValidationParametersNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.AssertionConditionsNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.AssertionNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.AudienceValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.LifetimeValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.OneTimeUseValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.TokenNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.TokenValidationParametersNull -> System.Diagnostics.StackFrame
virtual Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateConditions(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

#nullable enable
namespace Microsoft.IdentityModel.Tokens.Saml
{
/// <summary>
/// A <see cref="SecurityTokenHandler"/> designed for creating and validating Saml Tokens. See: http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
/// </summary>
public partial class SamlSecurityTokenHandler : SecurityTokenHandler
{
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
internal async Task<ValidationResult<ValidatedToken>> ValidateTokenAsync(
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
SamlSecurityToken samlToken,
ValidationParameters validationParameters,
CallContext callContext,
#pragma warning disable CA1801 // Review unused parameters
CancellationToken cancellationToken)
#pragma warning restore CA1801 // Review unused parameters
{
if (samlToken is null)
{
StackFrames.TokenNull ??= new StackFrame(true);
return ValidationError.NullParameter(
nameof(samlToken),
StackFrames.TokenNull);
}

if (validationParameters is null)
{
StackFrames.TokenValidationParametersNull ??= new StackFrame(true);
return ValidationError.NullParameter(
nameof(validationParameters),
StackFrames.TokenValidationParametersNull);
}

var conditionsResult = ValidateConditions(samlToken, validationParameters, callContext);

if (!conditionsResult.IsSuccess)
{
return conditionsResult.UnwrapError().AddStackFrame(new StackFrame(true));
}

return new ValidatedToken(samlToken, this, validationParameters);
}

// ValidatedConditions is basically a named tuple but using a record struct better expresses the intent.
internal record struct ValidatedConditions(string? ValidatedAudience, ValidatedLifetime? ValidatedLifetime);

internal virtual ValidationResult<ValidatedConditions> ValidateConditions(SamlSecurityToken samlToken, ValidationParameters validationParameters, CallContext callContext)
{
if (samlToken.Assertion is null)
{
StackFrames.AssertionNull ??= new StackFrame(true);
return ValidationError.NullParameter(
nameof(samlToken.Assertion),
StackFrames.AssertionNull);
}

if (samlToken.Assertion.Conditions is null)
{
StackFrames.AssertionConditionsNull ??= new StackFrame(true);
return ValidationError.NullParameter(
nameof(samlToken.Assertion.Conditions),
StackFrames.AssertionConditionsNull);
}

var lifetimeValidationResult = validationParameters.LifetimeValidator(
samlToken.Assertion.Conditions.NotBefore,
samlToken.Assertion.Conditions.NotOnOrAfter,
samlToken,
validationParameters,
callContext);

if (!lifetimeValidationResult.IsSuccess)
{
StackFrames.LifetimeValidationFailed ??= new StackFrame(true);
return lifetimeValidationResult.UnwrapError().AddStackFrame(StackFrames.LifetimeValidationFailed);
}

string? validatedAudience = null;
foreach (var condition in samlToken.Assertion.Conditions.Conditions)
{

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.IsSuccess)
return audienceValidationResult.UnwrapError();

validatedAudience = audienceValidationResult.UnwrapResult();
}

if (validatedAudience != null)
break;
}

return new ValidatedConditions(validatedAudience, lifetimeValidationResult.UnwrapResult());
}
}
}
#nullable restore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Diagnostics;

#nullable enable
namespace Microsoft.IdentityModel.Tokens.Saml
{
public partial class SamlSecurityTokenHandler : SecurityTokenHandler
{
// Cached stack frames to build exceptions from validation errors
internal static class StackFrames
{
// Stack frames from ValidateTokenAsync using SecurityToken
internal static StackFrame? TokenNull;
internal static StackFrame? TokenValidationParametersNull;

// Stack frames from ValidateConditions
internal static StackFrame? AudienceValidationFailed;
internal static StackFrame? AssertionNull;
internal static StackFrame? AssertionConditionsNull;
internal static StackFrame? LifetimeValidationFailed;
internal static StackFrame? OneTimeUseValidationFailed;
}
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Microsoft.IdentityModel.Tokens.Saml
/// which supports validating tokens passed as strings using <see cref="TokenValidationParameters"/>.
/// </summary>
///
public class SamlSecurityTokenHandler : SecurityTokenHandler
public partial class SamlSecurityTokenHandler : SecurityTokenHandler
{
internal const string Actor = "Actor";
private const string _className = "Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler";
Expand Down
Loading
Loading