Skip to content

Commit

Permalink
Merge branch 'dev' into iinglese/validated-token-logging
Browse files Browse the repository at this point in the history
  • Loading branch information
iNinja authored Dec 9, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents d548705 + 039e8f8 commit 9bf5d44
Showing 26 changed files with 1,554 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -255,25 +255,57 @@ private async ValueTask<ValidationResult<ValidatedToken>> ValidateJWSAsync(
DateTime? expires = jsonWebToken.HasPayloadClaim(JwtRegisteredClaimNames.Exp) ? jsonWebToken.ValidTo : null;
DateTime? notBefore = jsonWebToken.HasPayloadClaim(JwtRegisteredClaimNames.Nbf) ? jsonWebToken.ValidFrom : null;

ValidationResult<ValidatedLifetime> lifetimeValidationResult = validationParameters.LifetimeValidator(
notBefore, expires, jsonWebToken, validationParameters, callContext);
ValidationResult<ValidatedLifetime> lifetimeValidationResult;

if (!lifetimeValidationResult.IsValid)
try
{
lifetimeValidationResult = validationParameters.LifetimeValidator(
notBefore, expires, jsonWebToken, validationParameters, callContext);

if (!lifetimeValidationResult.IsValid)
return lifetimeValidationResult.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
{
StackFrame lifetimeValidationFailureStackFrame = StackFrames.LifetimeValidationFailed ??= new StackFrame(true);
return lifetimeValidationResult.UnwrapError().AddStackFrame(lifetimeValidationFailureStackFrame);
return new LifetimeValidationError(
new MessageDetail(TokenLogMessages.IDX10271),
ValidationFailureType.LifetimeValidatorThrew,
typeof(SecurityTokenInvalidLifetimeException),
ValidationError.GetCurrentStackFrame(),
notBefore,
expires,
ex);
}

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;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Microsoft.IdentityModel.Tokens.Saml.LogMessages.IDX11402 = "IDX11402: Unable to read SamlSecurityToken. Exception thrown: '{0}'." -> string
const Microsoft.IdentityModel.Tokens.Saml2.LogMessages.IDX13003 = "IDX13003: Unable to read Saml2SecurityToken. Exception thrown: '{0}'." -> string
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.CreateClaimsIdentity(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, string issuer) -> System.Security.Claims.ClaimsIdentity
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedAudience.get -> string
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions.ValidatedAudience.set -> void
@@ -12,12 +13,15 @@ Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(
Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(string token, 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.Saml.SamlValidationError
Microsoft.IdentityModel.Tokens.Saml.SamlValidationError.SamlValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.CreateClaimsIdentity(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, string issuer) -> System.Security.Claims.ClaimsIdentity
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames
Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.SecurityToken securityToken, 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.ValidateTokenAsync(string token, 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.Saml2ValidationError
Microsoft.IdentityModel.Tokens.Saml2.Saml2ValidationError.Saml2ValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.Exception innerException = null) -> void
override Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.CreateClaimsIdentityInternal(Microsoft.IdentityModel.Tokens.SecurityToken securityToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, string issuer) -> System.Security.Claims.ClaimsIdentity
override Microsoft.IdentityModel.Tokens.Saml.SamlValidationError.GetException() -> System.Exception
override Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.CreateClaimsIdentityInternal(Microsoft.IdentityModel.Tokens.SecurityToken securityToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, string issuer) -> System.Security.Claims.ClaimsIdentity
override Microsoft.IdentityModel.Tokens.Saml2.Saml2ValidationError.GetException() -> System.Exception
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.IssuerValidationFailed -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.SignatureValidationFailed -> System.Diagnostics.StackFrame
@@ -44,6 +48,7 @@ static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.TokenNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.TokenValidationParametersNull -> System.Diagnostics.StackFrame
static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateSignature(Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.SecurityKey>
virtual Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ProcessStatements(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, string issuer, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters) -> System.Collections.Generic.IEnumerable<System.Security.Claims.ClaimsIdentity>
virtual Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ReadSamlToken(string token, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken>
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>
virtual Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ReadSaml2Token(string token, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult<Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using Microsoft.IdentityModel.Logging;

#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
{
internal override ClaimsIdentity CreateClaimsIdentityInternal(SecurityToken securityToken, ValidationParameters validationParameters, string issuer)
{
return CreateClaimsIdentity((SamlSecurityToken)securityToken, validationParameters, issuer);
}

internal ClaimsIdentity CreateClaimsIdentity(SamlSecurityToken samlToken, ValidationParameters validationParameters, string issuer)
{
if (samlToken == null)
throw LogHelper.LogArgumentNullException(nameof(samlToken));

if (samlToken.Assertion == null)
throw LogHelper.LogArgumentNullException(LogMessages.IDX11110);

var actualIssuer = issuer;
if (string.IsNullOrWhiteSpace(issuer))
actualIssuer = ClaimsIdentity.DefaultIssuer;

IEnumerable<ClaimsIdentity> identities = ProcessStatements(
samlToken,
actualIssuer,
validationParameters);

return identities.First();
}

/// <summary>
/// Processes all statements to generate claims.
/// </summary>
/// <param name="samlToken">A <see cref="SamlSecurityToken"/> that will be used to create the claims.</param>
/// <param name="issuer">The issuer.</param>
/// <param name="validationParameters">The <see cref="TokenValidationParameters"/> to be used for validating the token.</param>
/// <returns>A <see cref="IEnumerable{ClaimsIdentity}"/> containing the claims from the <see cref="SamlSecurityToken"/>.</returns>
/// <exception cref="SamlSecurityTokenException">if the statement is not a <see cref="SamlSubjectStatement"/>.</exception>
internal virtual IEnumerable<ClaimsIdentity> ProcessStatements(SamlSecurityToken samlToken, string issuer, ValidationParameters validationParameters)
{
if (samlToken == null)
throw LogHelper.LogArgumentNullException(nameof(samlToken));

if (validationParameters == null)
throw LogHelper.LogArgumentNullException(nameof(validationParameters));

var identityDict = new Dictionary<SamlSubject, ClaimsIdentity>(SamlSubjectEqualityComparer);
foreach (SamlStatement? item in samlToken.Assertion.Statements)
{
if (item is not SamlSubjectStatement statement)
throw LogHelper.LogExceptionMessage(new SamlSecurityTokenException(LogMessages.IDX11515));

if (!identityDict.TryGetValue(statement.Subject, out ClaimsIdentity? identity))
{
identity = validationParameters.CreateClaimsIdentity(samlToken, issuer);
ProcessSubject(statement.Subject, identity, issuer);
identityDict.Add(statement.Subject, identity);
}

if (statement is SamlAttributeStatement attrStatement)
ProcessAttributeStatement(attrStatement, identity, issuer);
else if (statement is SamlAuthenticationStatement authnStatement)
ProcessAuthenticationStatement(authnStatement, identity, issuer);
else if (statement is SamlAuthorizationDecisionStatement authzStatement)
ProcessAuthorizationDecisionStatement(authzStatement, identity, issuer);
else
ProcessCustomSubjectStatement(statement, identity, issuer);
}

return identityDict.Values;
}
}
}
#nullable restore
Loading

0 comments on commit 9bf5d44

Please sign in to comment.