Skip to content
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

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/Delegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.JsonWebTokens.Results;

namespace Microsoft.IdentityModel.Tokens
{
Expand Down Expand Up @@ -171,6 +172,19 @@ namespace Microsoft.IdentityModel.Tokens
public delegate SecurityToken TransformBeforeSignatureValidation(SecurityToken token, TokenValidationParameters validationParameters);

#nullable enable
/// <summary>
/// Resolves the signing key used for validating a token's signature.
/// </summary>
/// <param name="token">The string representation of the token being validated.</param>
/// <param name="securityToken">The <see cref="SecurityToken"/> being validated, which may be null.</param>
/// <param name="kid">The key identifier, which may be null.</param>
/// <param name="validationParameters">The <see cref="ValidationParameters"/> to be used for validating the token.</param>
/// <param name="configuration">The <see cref="BaseConfiguration"/> to be used for validating the token.</param>
/// <param name="callContext">The <see cref="CallContext"/> used for logging.</param>
/// <returns>The <see cref="SecurityKey"/> used to validate the signature.</returns>
/// <remarks>If both <see cref="IssuerSigningKeyResolverUsingConfiguration"/> and <see cref="IssuerSigningKeyResolver"/> are set, <see cref="IssuerSigningKeyResolverUsingConfiguration"/> takes priority.</remarks>
internal delegate SecurityKey? IssuerSigningKeyResolverDelegate(string token, SecurityToken? securityToken, string? kid, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext? callContext);

/// <summary>
/// Resolves the decryption key for the security token.
/// </summary>
Expand All @@ -181,5 +195,16 @@ namespace Microsoft.IdentityModel.Tokens
/// <param name="callContext">The <see cref="CallContext"/> to be used for logging.</param>
/// <returns>The <see cref="SecurityKey"/> used to decrypt the token.</returns>
internal delegate IList<SecurityKey> ResolveTokenDecryptionKeyDelegate(string token, SecurityToken securityToken, string kid, ValidationParameters validationParameters, CallContext? callContext);

/// <summary>
/// Validates the signature of the security token.
/// </summary>
/// <param name="token">The <see cref="SecurityToken"/> with a signature.</param>
/// <param name="validationParameters">The <see cref="ValidationParameters"/> to be used for validating the token.</param>
/// <param name="configuration">The <see cref="BaseConfiguration"/> to be used for validating the token.</param>
/// <param name="callContext">The <see cref="CallContext"/> to be used for logging.</param>
/// <remarks>This method is not expected to throw.</remarks>
/// <returns>The validated <see cref="SecurityToken"/>.</returns>
internal delegate SignatureValidationResult SignatureValidatorDelegate(SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext? callContext);
#nullable restore
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Microsoft.IdentityModel.Tokens;

namespace Microsoft.IdentityModel.JsonWebTokens.Results
{
#nullable enable
/// <summary>
/// Contains the result of validating a signature.
/// The <see cref="TokenValidationResult"/> contains a collection of <see cref="ValidationResult"/> for each step in the token validation.
/// </summary>
internal class SignatureValidationResult: ValidationResult
{
private Exception? _exception;

/// <summary>
/// Creates an instance of <see cref="SignatureValidationResult"/> representing the successful result of validating a signature.
/// </summary>
public SignatureValidationResult(bool isValid, ValidationFailureType validationFailureType) : base(validationFailureType)
{
IsValid = isValid;
}

/// <summary>
/// Creates an instance of <see cref="SignatureValidationResult"/> representing the failed result of validating a signature.
/// </summary>
/// <param name="validationFailure"> is the <see cref="ValidationFailure"/> that occurred while validating the signature.</param>
/// <param name="exceptionDetail"> contains the <see cref="ExceptionDetail"/> of the error that occurred while validating the signature.</param>
public SignatureValidationResult(ValidationFailureType validationFailure, ExceptionDetail? exceptionDetail)
: base(validationFailure, exceptionDetail)
{
IsValid = false;
}

/// <summary>
/// Creates an instance of <see cref="SignatureValidationResult"/> representing a successful validation.
/// </summary>
internal static SignatureValidationResult Success() =>
new SignatureValidationResult(true, ValidationFailureType.ValidationSucceeded);

/// <summary>
/// Creates an instance of <see cref="SignatureValidationResult"/> representing a failure due to a null parameter.
/// </summary>
/// <param name="parameterName">The name of the null parameter.</param>
internal static SignatureValidationResult NullParameterFailure(string parameterName) =>
new SignatureValidationResult(
ValidationFailureType.SignatureValidationFailed,
ExceptionDetail.NullParameter(parameterName));

/// <summary>
/// Gets the <see cref="Exception"/> that occurred while validating the signature.
/// </summary>
public override Exception? Exception
{
get
{
if (_exception != null || ExceptionDetail == null)
return _exception;

HasValidOrExceptionWasRead = true;
_exception = ExceptionDetail.GetException();
_exception.Source = "Microsoft.IdentityModel.JsonWebTokens";

if (_exception is SecurityTokenException securityTokenException)
{
securityTokenException.ExceptionDetail = ExceptionDetail;
}

return _exception;
}
}
}
#nullable restore
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ private class AudienceValidationFailure : ValidationFailureType { internal Audie
public static readonly ValidationFailureType TokenTypeValidationFailed = new TokenTypeValidationFailure("TokenTypeValidationFailed");
private class TokenTypeValidationFailure : ValidationFailureType { internal TokenTypeValidationFailure(string name) : base(name) { } }

/// <summary>
/// Defines a type that represents that the token's signature validation failed.
/// </summary>
public static readonly ValidationFailureType SignatureValidationFailed = new SignatureValidationFailure("SignatureValidationFailed");
private class SignatureValidationFailure : ValidationFailureType { internal SignatureValidationFailure(string name) : base(name) { } }

/// <summary>
/// Defines a type that represents that signing key validation failed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal class ValidationParameters
private string _nameClaimType = ClaimsIdentity.DefaultNameClaimType;
private string _roleClaimType = ClaimsIdentity.DefaultRoleClaimType;
private Dictionary<string, object> _instancePropertyBag;

private IList<SecurityKey> _issuerSigningKeys;
private IList<string> _validIssuers;
private IList<string> _validTokenTypes;
private IList<string> _validAudiences;
Expand All @@ -30,6 +30,7 @@ internal class ValidationParameters
private AudienceValidatorDelegate _audienceValidator = Validators.ValidateAudience;
private IssuerValidationDelegateAsync _issuerValidatorAsync = Validators.ValidateIssuerAsync;
private LifetimeValidatorDelegate _lifetimeValidator = Validators.ValidateLifetime;
private SignatureValidatorDelegate _signatureValidator;
private TokenReplayValidatorDelegate _tokenReplayValidator = Validators.ValidateTokenReplay;
private TypeValidatorDelegate _typeValidator = Validators.ValidateTokenType;

Expand Down Expand Up @@ -69,7 +70,7 @@ protected ValidationParameters(ValidationParameters other)
IncludeTokenOnFailedValidation = other.IncludeTokenOnFailedValidation;
IgnoreTrailingSlashWhenValidatingAudience = other.IgnoreTrailingSlashWhenValidatingAudience;
IssuerSigningKeyResolver = other.IssuerSigningKeyResolver;
IssuerSigningKeys = other.IssuerSigningKeys;
_issuerSigningKeys = other.IssuerSigningKeys;
IssuerSigningKeyValidator = other.IssuerSigningKeyValidator;
IssuerValidatorAsync = other.IssuerValidatorAsync;
LifetimeValidator = other.LifetimeValidator;
Expand Down Expand Up @@ -204,7 +205,7 @@ public virtual ValidationParameters Clone()
/// <returns>A <see cref="ClaimsIdentity"/> with Authentication, NameClaimType and RoleClaimType set.</returns>
public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken, string issuer)
{
string nameClaimType = null;
string nameClaimType;
if (NameClaimTypeRetriever != null)
{
nameClaimType = NameClaimTypeRetriever(securityToken, issuer);
Expand All @@ -214,7 +215,7 @@ public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken,
nameClaimType = NameClaimType;
}

string roleClaimType = null;
string roleClaimType;
if (RoleClaimTypeRetriever != null)
{
roleClaimType = RoleClaimTypeRetriever(securityToken, issuer);
Expand Down Expand Up @@ -293,12 +294,15 @@ public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken,
/// If both <see cref="IssuerSigningKeyResolverUsingConfiguration"/> and <see cref="IssuerSigningKeyResolver"/> are set, IssuerSigningKeyResolverUsingConfiguration takes
/// priority.
/// </remarks>
public IssuerSigningKeyResolver IssuerSigningKeyResolver { get; set; }
public IssuerSigningKeyResolverDelegate IssuerSigningKeyResolver { get; set; }

/// <summary>
/// Gets or sets an <see cref="IList{SecurityKey}"/> used for signature validation.
/// Gets the <see cref="IList{SecurityKey}"/> used for signature validation.
/// </summary>
public IList<SecurityKey> IssuerSigningKeys { get; }
public IList<SecurityKey> IssuerSigningKeys =>
_issuerSigningKeys ??
Interlocked.CompareExchange(ref _issuerSigningKeys, [], null) ??
_issuerSigningKeys;

/// <summary>
/// Allows overriding the delegate that will be used to validate the issuer of the token.
Expand Down Expand Up @@ -375,7 +379,7 @@ public string NameClaimType
public IDictionary<string, object> PropertyBag { get; }

/// <summary>
/// Gets or sets a boolean to control if configuration required to be refreshed before token validation.
/// A boolean to control whether configuration should be refreshed before validating a token.
/// </summary>
/// <remarks>
/// The default is <c>false</c>.
Expand Down Expand Up @@ -433,7 +437,10 @@ public string RoleClaimType
/// <remarks>
/// If set, this delegate will be called to validate the signature of the token, instead of default processing.
/// </remarks>
public SignatureValidator SignatureValidator { get; set; }
public SignatureValidatorDelegate SignatureValidator {
get { return _signatureValidator; }
set { _signatureValidator = value; }
}

/// <summary>
/// Gets or sets a delegate that will be called to retreive a <see cref="SecurityKey"/> used for decryption.
Expand Down Expand Up @@ -469,6 +476,13 @@ public TokenReplayValidatorDelegate TokenReplayValidator
set { _tokenReplayValidator = value ?? throw new ArgumentNullException(nameof(value), "TokenReplayValidator cannot be set as null."); }
}

/// <summary>
/// If the IssuerSigningKeyResolver is unable to resolve the key when validating the signature of the SecurityToken,
/// all available keys will be tried.
/// </summary>
/// <remarks>Default is false.</remarks>
public bool TryAllIssuerSigningKeys { get; set; }

/// <summary>
/// Allows overriding the delegate that will be used to validate the type of the token.
/// If the token type cannot be validated, a <see cref="TokenTypeValidationResult"/> MUST be returned by the delegate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected ValidationResult(ValidationFailureType validationFailureType)
/// </summary>
/// <param name="validationFailureType">The <see cref="ValidationFailureType"/> that occurred during validation.</param>
/// <param name="exceptionDetail"> The <see cref="ExceptionDetail"/> representing the <see cref="Exception"/> that occurred during validation.</param>
protected ValidationResult(ValidationFailureType validationFailureType, ExceptionDetail exceptionDetail)
protected ValidationResult(ValidationFailureType validationFailureType, ExceptionDetail? exceptionDetail)
{
ValidationFailureType = validationFailureType;
ExceptionDetail = exceptionDetail;
Expand Down
Loading