diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs
index 3132ad2863..4f413738c6 100644
--- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs
+++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs
@@ -527,6 +527,28 @@ public virtual TokenValidationResult ValidateToken(string token, TokenValidation
/// if the validationParameters.TokenReader delegate is not able to parse/read the token as a valid ,
///
public override async Task ValidateTokenAsync(string token, TokenValidationParameters validationParameters)
+ {
+ return await ValidateTokenAsync(token, validationParameters, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Validates a token.
+ /// On a validation failure, no exception will be thrown; instead, the exception will be set in the returned TokenValidationResult.Exception property.
+ /// Callers should always check the TokenValidationResult.IsValid property to verify the validity of the result.
+ ///
+ /// The token to be validated.
+ /// A required for validation.
+ /// Propagates notification that operations should be canceled.
+ /// A
+ ///
+ /// TokenValidationResult.Exception will be set to one of the following exceptions if the is invalid.
+ /// if is null or empty.
+ /// if is null.
+ /// 'token.Length' is greater than .
+ /// if is not a valid ,
+ /// if the validationParameters.TokenReader delegate is not able to parse/read the token as a valid ,
+ ///
+ internal override async Task ValidateTokenAsync(string token, TokenValidationParameters validationParameters, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(token))
return new TokenValidationResult { Exception = LogHelper.LogArgumentNullException(nameof(token)), IsValid = false };
@@ -537,11 +559,12 @@ public override async Task ValidateTokenAsync(string toke
if (token.Length > MaximumTokenSizeInBytes)
return new TokenValidationResult { Exception = LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(TokenLogMessages.IDX10209, LogHelper.MarkAsNonPII(token.Length), LogHelper.MarkAsNonPII(MaximumTokenSizeInBytes)))), IsValid = false };
+#pragma warning disable CA1031
try
{
TokenValidationResult result = ReadToken(token, validationParameters);
if (result.IsValid)
- return await ValidateTokenAsync(result.SecurityToken, validationParameters).ConfigureAwait(false);
+ return await ValidateTokenAsync(result.SecurityToken, validationParameters, cancellationToken).ConfigureAwait(false);
return result;
}
@@ -553,10 +576,17 @@ public override async Task ValidateTokenAsync(string toke
IsValid = false
};
}
+#pragma warning restore CA1031
}
///
public override async Task ValidateTokenAsync(SecurityToken token, TokenValidationParameters validationParameters)
+ {
+ return await ValidateTokenAsync(token, validationParameters, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ internal override async Task ValidateTokenAsync(SecurityToken token, TokenValidationParameters validationParameters, CancellationToken cancellationToken)
{
if (token == null)
throw LogHelper.LogArgumentNullException(nameof(token));
@@ -570,8 +600,9 @@ public override async Task ValidateTokenAsync(SecurityTok
try
{
- return await ValidateTokenAsync(jwt, validationParameters).ConfigureAwait(false);
+ return await ValidateTokenAsync(jwt, validationParameters, cancellationToken).ConfigureAwait(false);
}
+#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
{
return new TokenValidationResult
@@ -580,6 +611,7 @@ public override async Task ValidateTokenAsync(SecurityTok
IsValid = false
};
}
+#pragma warning restore CA1031 // Do not catch general exception types
}
///
@@ -635,15 +667,16 @@ private static TokenValidationResult ReadToken(string token, TokenValidationPara
///
/// The JWT token
/// The to be used for validation.
+ /// Propagates notification that operations should be canceled.
///
- private async ValueTask ValidateTokenAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters)
+ private async ValueTask ValidateTokenAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, CancellationToken cancellationToken)
{
BaseConfiguration currentConfiguration = null;
if (validationParameters.ConfigurationManager != null)
{
try
{
- currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(CancellationToken.None).ConfigureAwait(false);
+ currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(cancellationToken).ConfigureAwait(false);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception ex)
@@ -656,7 +689,7 @@ private async ValueTask ValidateTokenAsync(JsonWebToken j
}
}
- TokenValidationResult tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, currentConfiguration).ConfigureAwait(false);
+ TokenValidationResult tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, currentConfiguration, cancellationToken).ConfigureAwait(false);
if (validationParameters.ConfigurationManager != null)
{
if (tokenValidationResult.IsValid)
@@ -678,12 +711,12 @@ private async ValueTask ValidateTokenAsync(JsonWebToken j
validationParameters.ConfigurationManager.RequestRefresh();
validationParameters.RefreshBeforeValidation = true;
var lastConfig = currentConfiguration;
- currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(CancellationToken.None).ConfigureAwait(false);
+ currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(cancellationToken).ConfigureAwait(false);
// Only try to re-validate using the newly obtained config if it doesn't reference equal the previously used configuration.
if (lastConfig != currentConfiguration)
{
- tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, currentConfiguration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, currentConfiguration, cancellationToken).ConfigureAwait(false);
if (tokenValidationResult.IsValid)
{
@@ -703,7 +736,7 @@ private async ValueTask ValidateTokenAsync(JsonWebToken j
{
if (!lkgConfiguration.Equals(currentConfiguration) && TokenUtilities.IsRecoverableConfiguration(jsonWebToken.Kid, currentConfiguration, lkgConfiguration, recoverableException))
{
- tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, lkgConfiguration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateTokenAsync(jsonWebToken, validationParameters, lkgConfiguration, cancellationToken).ConfigureAwait(false);
if (tokenValidationResult.IsValid)
return tokenValidationResult;
@@ -716,14 +749,14 @@ private async ValueTask ValidateTokenAsync(JsonWebToken j
return tokenValidationResult;
}
- private ValueTask ValidateTokenAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
+ private ValueTask ValidateTokenAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration, CancellationToken cancellationToken)
{
return jsonWebToken.IsEncrypted ?
- ValidateJWEAsync(jsonWebToken, validationParameters, configuration) :
- ValidateJWSAsync(jsonWebToken, validationParameters, configuration);
+ ValidateJWEAsync(jsonWebToken, validationParameters, configuration, cancellationToken) :
+ ValidateJWSAsync(jsonWebToken, validationParameters, configuration, cancellationToken);
}
- private async ValueTask ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
+ private async ValueTask ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration, CancellationToken cancellationToken)
{
try
{
@@ -734,21 +767,21 @@ private async ValueTask ValidateJWSAsync(JsonWebToken jso
if (validationParameters.SignatureValidator != null || validationParameters.SignatureValidatorUsingConfiguration != null)
{
var validatedToken = ValidateSignatureUsingDelegates(jsonWebToken, validationParameters, configuration);
- tokenValidationResult = await ValidateTokenPayloadAsync(validatedToken, validationParameters, configuration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateTokenPayloadAsync(validatedToken, validationParameters, configuration, cancellationToken).ConfigureAwait(false);
Validators.ValidateIssuerSecurityKey(validatedToken.SigningKey, validatedToken, validationParameters, configuration);
}
else
{
if (validationParameters.ValidateSignatureLast)
{
- tokenValidationResult = await ValidateTokenPayloadAsync(jsonWebToken, validationParameters, configuration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateTokenPayloadAsync(jsonWebToken, validationParameters, configuration, cancellationToken).ConfigureAwait(false);
if (tokenValidationResult.IsValid)
tokenValidationResult.SecurityToken = ValidateSignatureAndIssuerSecurityKey(jsonWebToken, validationParameters, configuration);
}
else
{
var validatedToken = ValidateSignatureAndIssuerSecurityKey(jsonWebToken, validationParameters, configuration);
- tokenValidationResult = await ValidateTokenPayloadAsync(validatedToken, validationParameters, configuration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateTokenPayloadAsync(validatedToken, validationParameters, configuration, cancellationToken).ConfigureAwait(false);
}
}
@@ -767,7 +800,7 @@ private async ValueTask ValidateJWSAsync(JsonWebToken jso
}
}
- private async ValueTask ValidateJWEAsync(JsonWebToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
+ private async ValueTask ValidateJWEAsync(JsonWebToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration, CancellationToken cancellationToken)
{
try
{
@@ -775,7 +808,7 @@ private async ValueTask ValidateJWEAsync(JsonWebToken jwt
if (!tokenValidationResult.IsValid)
return tokenValidationResult;
- tokenValidationResult = await ValidateJWSAsync(tokenValidationResult.SecurityToken as JsonWebToken, validationParameters, configuration).ConfigureAwait(false);
+ tokenValidationResult = await ValidateJWSAsync(tokenValidationResult.SecurityToken as JsonWebToken, validationParameters, configuration, cancellationToken).ConfigureAwait(false);
if (!tokenValidationResult.IsValid)
return tokenValidationResult;
@@ -838,7 +871,7 @@ private static JsonWebToken ValidateSignatureAndIssuerSecurityKey(JsonWebToken j
return validatedToken;
}
- private async ValueTask ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
+ private async ValueTask ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration, CancellationToken cancellationToken)
{
var expires = jsonWebToken.HasPayloadClaim(JwtRegisteredClaimNames.Exp) ? (DateTime?)jsonWebToken.ValidTo : null;
var notBefore = jsonWebToken.HasPayloadClaim(JwtRegisteredClaimNames.Nbf) ? (DateTime?)jsonWebToken.ValidFrom : null;
@@ -857,7 +890,7 @@ private async ValueTask ValidateTokenPayloadAsync(JsonWeb
// NOTE: More than one nested actor token should not be considered a valid token, but if we somehow encounter one,
// this code will still work properly.
TokenValidationResult tokenValidationResult =
- await ValidateTokenAsync(jsonWebToken.Actor, validationParameters.ActorValidationParameters ?? validationParameters).ConfigureAwait(false);
+ await ValidateTokenAsync(jsonWebToken.Actor, validationParameters.ActorValidationParameters ?? validationParameters, cancellationToken).ConfigureAwait(false);
if (!tokenValidationResult.IsValid)
return tokenValidationResult;
diff --git a/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs b/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs
index bba4f7c69b..633e8b3fd9 100644
--- a/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs
+++ b/src/Microsoft.IdentityModel.Tokens/TokenHandler.cs
@@ -5,6 +5,7 @@
using System;
using System.ComponentModel;
using System.Security.Claims;
+using System.Threading;
using System.Threading.Tasks;
using static Microsoft.IdentityModel.Logging.LogHelper;
@@ -65,6 +66,17 @@ public int TokenLifetimeInMinutes
/// A
public virtual Task ValidateTokenAsync(string token, TokenValidationParameters validationParameters) => throw new NotImplementedException();
+ ///
+ /// Validates a token.
+ /// On a validation failure, no exception will be thrown; instead, the exception will be set in the returned TokenValidationResult.Exception property.
+ /// Callers should always check the TokenValidationResult.IsValid property to verify the validity of the result.
+ ///
+ /// The token to be validated.
+ /// A required for validation.
+ /// Propagates notification that operations should be canceled.
+ /// A
+ internal virtual Task ValidateTokenAsync(string token, TokenValidationParameters validationParameters, CancellationToken cancellationToken) => throw new NotImplementedException();
+
///
/// Validates a token.
/// On a validation failure, no exception will be thrown; instead, the exception will be set in the returned TokenValidationResult.Exception property.
@@ -75,6 +87,17 @@ public int TokenLifetimeInMinutes
/// A
public virtual Task ValidateTokenAsync(SecurityToken token, TokenValidationParameters validationParameters) => throw new NotImplementedException();
+ ///
+ /// Validates a token.
+ /// On a validation failure, no exception will be thrown; instead, the exception will be set in the returned TokenValidationResult.Exception property.
+ /// Callers should always check the TokenValidationResult.IsValid property to verify the validity of the result.
+ ///
+ /// The to be validated.
+ /// A required for validation.
+ /// Propagates notification that operations should be canceled.
+ /// A
+ internal virtual Task ValidateTokenAsync(SecurityToken token, TokenValidationParameters validationParameters, CancellationToken cancellationToken) => throw new NotImplementedException();
+
///
/// Converts a string into an instance of .
///