diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.JsonWebTokens/InternalAPI.Unshipped.txt index 7537e1ca98..ba5736133f 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.JsonWebTokens/InternalAPI.Unshipped.txt @@ -1,3 +1,5 @@ +Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.SecurityToken token, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> +Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenAsync(string token, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler._telemetryClient -> Microsoft.IdentityModel.Telemetry.ITelemetryClient static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateToken(string payload, Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor tokenDescriptor) -> string static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.EncryptToken(byte[] innerTokenUtf8Bytes, Microsoft.IdentityModel.Tokens.EncryptingCredentials encryptingCredentials, string compressionAlgorithm, System.Collections.Generic.IDictionary additionalHeaderClaims, string tokenType, bool includeKeyIdInHeader) -> string @@ -6,4 +8,3 @@ static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.WriteJweHeader( static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.WriteJweHeader(Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor tokenDescriptor) -> byte[] static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.WriteJwsHeader(ref System.Text.Json.Utf8JsonWriter writer, Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor tokenDescriptor) -> void static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.WriteJwsHeader(ref System.Text.Json.Utf8JsonWriter writer, Microsoft.IdentityModel.Tokens.SigningCredentials signingCredentials, Microsoft.IdentityModel.Tokens.EncryptingCredentials encryptingCredentials, System.Collections.Generic.IDictionary jweHeaderClaims, System.Collections.Generic.IDictionary jwsHeaderClaims, string tokenType, bool includeKeyIdInHeader) -> void -static Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.StackFrames.IssuerValidatorThrew -> System.Diagnostics.StackFrame diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.DecryptToken.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.DecryptToken.cs index 7b7a641cb2..4ca9467379 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.DecryptToken.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.DecryptToken.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text; using Microsoft.IdentityModel.Logging; @@ -31,49 +30,42 @@ internal ValidationResult DecryptToken( { if (jwtToken == null) { - StackFrame tokenNullStackFrame = StackFrames.DecryptionTokenNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(jwtToken), - tokenNullStackFrame); + ValidationError.GetCurrentStackFrame()); } if (validationParameters == null) { - StackFrame validationParametersNullStackFrame = StackFrames.DecryptionValidationParametersNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(validationParameters), - validationParametersNullStackFrame); + ValidationError.GetCurrentStackFrame()); } if (string.IsNullOrEmpty(jwtToken.Enc)) { - StackFrame headerMissingStackFrame = StackFrames.DecryptionHeaderMissing ??= new StackFrame(true); return new ValidationError( new MessageDetail(TokenLogMessages.IDX10612), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenException), - headerMissingStackFrame); + ValidationError.GetCurrentStackFrame()); } (IList? contentEncryptionKeys, ValidationError? validationError) result = GetContentEncryptionKeys(jwtToken, validationParameters, configuration, callContext); if (result.validationError != null) - { - StackFrame decryptionGetKeysStackFrame = StackFrames.DecryptionGetEncryptionKeys ??= new StackFrame(true); - return result.validationError.AddStackFrame(decryptionGetKeysStackFrame); - } + return result.validationError.AddCurrentStackFrame(); if (result.contentEncryptionKeys == null || result.contentEncryptionKeys.Count == 0) { - StackFrame noKeysTriedStackFrame = StackFrames.DecryptionNoKeysTried ??= new StackFrame(true); return new ValidationError( new MessageDetail( TokenLogMessages.IDX10609, LogHelper.MarkAsSecurityArtifact(jwtToken, JwtTokenUtilities.SafeLogJwtToken)), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenDecryptionFailedException), - noKeysTriedStackFrame); + ValidationError.GetCurrentStackFrame()); } return JwtTokenUtilities.DecryptJwtToken( @@ -211,7 +203,6 @@ internal ValidationResult DecryptToken( return (unwrappedKeys, null); else { - StackFrame decryptionKeyUnwrapFailedStackFrame = StackFrames.DecryptionKeyUnwrapFailed ??= new StackFrame(true); ValidationError validationError = new( new MessageDetail( TokenLogMessages.IDX10618, @@ -220,7 +211,7 @@ internal ValidationResult DecryptToken( LogHelper.MarkAsSecurityArtifact(jwtToken, JwtTokenUtilities.SafeLogJwtToken)), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenKeyWrapException), - decryptionKeyUnwrapFailedStackFrame); + ValidationError.GetCurrentStackFrame()); return (null, validationError); } diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ReadToken.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ReadToken.cs index 44929e628b..8ea160e10a 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ReadToken.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ReadToken.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; using Microsoft.IdentityModel.Tokens; #nullable enable @@ -28,10 +27,9 @@ internal static ValidationResult ReadToken( { if (string.IsNullOrEmpty(token)) { - StackFrame nullTokenStackFrame = StackFrames.ReadTokenNullOrEmpty ?? new StackFrame(true); return ValidationError.NullParameter( nameof(token), - nullTokenStackFrame); + ValidationError.GetCurrentStackFrame()); } try @@ -43,12 +41,11 @@ internal static ValidationResult ReadToken( catch (Exception ex) #pragma warning restore CA1031 // Do not catch general exception types { - StackFrame malformedTokenStackFrame = StackFrames.ReadTokenMalformed ?? new StackFrame(true); return new ValidationError( new MessageDetail(LogMessages.IDX14107), ValidationFailureType.TokenReadingFailed, typeof(SecurityTokenMalformedException), - malformedTokenStackFrame, + ValidationError.GetCurrentStackFrame(), ex); } } diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs index 1bb3e578ca..b807bdf291 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.Internal.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -18,47 +17,35 @@ public partial class JsonWebTokenHandler : TokenHandler { /// /// 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. + /// On validation failure no exception will be thrown. 'see cref="ValidationError"' will contain information pertaining to the error. /// /// The token to be validated. /// The to be used for validating the token. - /// A that contains useful information for logging. + /// A that contains call information. /// A that can be used to request cancellation of the asynchronous operation. /// A with either a if the token was validated or an with the failure information and exception otherwise. - /// - /// ValidationError.GetException() will return one of the following exceptions if the is invalid. - /// - /// Returned if is null or empty. - /// Returned if is null. - /// Returned if 'token.Length' is greater than . - /// Returned if is not a valid , - /// Returned if the validationParameters.TokenReader delegate is not able to parse/read the token as a valid , internal async Task> ValidateTokenAsync( string token, ValidationParameters validationParameters, CallContext callContext, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(token)) { - StackFrame nullTokenStackFrame = StackFrames.TokenStringNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(token), - nullTokenStackFrame); + ValidationError.GetCurrentStackFrame()); } if (validationParameters is null) { - StackFrame nullValidationParametersStackFrame = StackFrames.TokenStringValidationParametersNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(validationParameters), - nullValidationParametersStackFrame); + ValidationError.GetCurrentStackFrame()); } if (token.Length > MaximumTokenSizeInBytes) { - StackFrame invalidTokenLengthStackFrame = StackFrames.InvalidTokenLength ??= new StackFrame(true); return new ValidationError( new MessageDetail( TokenLogMessages.IDX10209, @@ -66,7 +53,7 @@ internal async Task> ValidateTokenAsync( LogHelper.MarkAsNonPII(MaximumTokenSizeInBytes)), ValidationFailureType.InvalidSecurityToken, typeof(ArgumentException), - invalidTokenLengthStackFrame); + ValidationError.GetCurrentStackFrame()); } ValidationResult readResult = ReadToken(token, callContext); @@ -82,12 +69,10 @@ internal async Task> ValidateTokenAsync( if (validationResult.IsValid) return validationResult; // No need to unwrap and re-wrap the result. - StackFrame validationFailureStackFrame = StackFrames.TokenStringValidationFailed ??= new StackFrame(true); - return validationResult.UnwrapError().AddStackFrame(validationFailureStackFrame); + return validationResult.UnwrapError().AddCurrentStackFrame(); } - StackFrame readFailureStackFrame = StackFrames.TokenStringReadFailed ??= new StackFrame(true); - return readResult.UnwrapError().AddStackFrame(readFailureStackFrame); + return readResult.UnwrapError().AddCurrentStackFrame(); } /// @@ -95,32 +80,29 @@ internal async Task> ValidateTokenAsync( SecurityToken token, ValidationParameters validationParameters, CallContext callContext, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (token is null) { - StackFrame nullTokenStackFrame = StackFrames.TokenNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(token), - nullTokenStackFrame); + ValidationError.GetCurrentStackFrame()); } if (validationParameters is null) { - StackFrame nullValidationParametersStackFrame = StackFrames.TokenValidationParametersNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(validationParameters), - nullValidationParametersStackFrame); + ValidationError.GetCurrentStackFrame()); } if (token is not JsonWebToken jsonWebToken) { - StackFrame notJwtStackFrame = StackFrames.TokenNotJWT ??= new StackFrame(true); return new ValidationError( new MessageDetail(TokenLogMessages.IDX10001, nameof(token), nameof(JsonWebToken)), ValidationFailureType.InvalidSecurityToken, typeof(ArgumentException), - notJwtStackFrame); + ValidationError.GetCurrentStackFrame()); } BaseConfiguration? currentConfiguration = @@ -200,8 +182,7 @@ await ValidateJWEAsync(jsonWebToken, validationParameters, lkgConfiguration, cal } // If we reach this point, the token validation failed and we should return the error. - StackFrame stackFrame = StackFrames.TokenValidationFailed ??= new StackFrame(true); - return result.UnwrapError().AddStackFrame(stackFrame); + return result.UnwrapError().AddCurrentStackFrame(); } private async ValueTask> ValidateJWEAsync( @@ -215,15 +196,13 @@ private async ValueTask> ValidateJWEAsync( jwtToken, validationParameters, configuration, callContext); if (!decryptionResult.IsValid) { - StackFrame decryptionFailureStackFrame = StackFrames.DecryptionFailed ??= new StackFrame(true); - return decryptionResult.UnwrapError().AddStackFrame(decryptionFailureStackFrame); + return decryptionResult.UnwrapError().AddCurrentStackFrame(); } ValidationResult readResult = ReadToken(decryptionResult.UnwrapResult(), callContext); if (!readResult.IsValid) { - StackFrame readFailureStackFrame = StackFrames.DecryptedReadFailed ??= new StackFrame(true); - return readResult.UnwrapError().AddStackFrame(readFailureStackFrame); + return readResult.UnwrapError().AddCurrentStackFrame(); } JsonWebToken decryptedToken = (readResult.UnwrapResult() as JsonWebToken)!; @@ -233,8 +212,7 @@ await ValidateJWSAsync(decryptedToken!, validationParameters, configuration, cal if (!validationResult.IsValid) { - StackFrame validationFailureStackFrame = StackFrames.JWEValidationFailed ??= new StackFrame(true); - return validationResult.UnwrapError().AddStackFrame(validationFailureStackFrame); + return validationResult.UnwrapError().AddCurrentStackFrame(); } JsonWebToken jsonWebToken = (validationResult.UnwrapResult().SecurityToken as JsonWebToken)!; @@ -289,10 +267,7 @@ private async ValueTask> ValidateJWSAsync( tokenAudiences, jsonWebToken, validationParameters, callContext); if (!audienceValidationResult.IsValid) - { - StackFrame audienceValidationFailureStackFrame = StackFrames.AudienceValidationFailed ??= new StackFrame(true); - return audienceValidationResult.UnwrapError().AddStackFrame(audienceValidationFailureStackFrame); - } + return audienceValidationResult.UnwrapError().AddCurrentStackFrame(); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) @@ -362,10 +337,12 @@ private async ValueTask> ValidateJWSAsync( { ValidationResult actorReadingResult = ReadToken(jsonWebToken.Actor, callContext); if (!actorReadingResult.IsValid) - { - StackFrame actorReadingFailureStackFrame = StackFrames.ActorReadFailed ??= new StackFrame(true); - return actorReadingResult.UnwrapError().AddStackFrame(actorReadingFailureStackFrame); - } + return actorReadingResult.UnwrapError().AddCurrentStackFrame(); + + if (validationParameters.ActorValidationParameters is null) + return ValidationError.NullParameter( + nameof(validationParameters.ActorValidationParameters), + ValidationError.GetCurrentStackFrame()); JsonWebToken actorToken = (actorReadingResult.UnwrapResult() as JsonWebToken)!; ValidationParameters actorParameters = validationParameters.ActorValidationParameters; @@ -374,10 +351,7 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext, .ConfigureAwait(false); if (!innerActorValidationResult.IsValid) - { - StackFrame actorValidationFailureStackFrame = StackFrames.ActorValidationFailed ??= new StackFrame(true); - return innerActorValidationResult.UnwrapError().AddStackFrame(actorValidationFailureStackFrame); - } + return innerActorValidationResult.UnwrapError().AddCurrentStackFrame(); actorValidationResult = innerActorValidationResult; } @@ -410,10 +384,7 @@ await ValidateJWSAsync(actorToken, actorParameters, configuration, callContext, ValidationResult signatureValidationResult = ValidateSignature( jsonWebToken, validationParameters, configuration, callContext); if (!signatureValidationResult.IsValid) - { - StackFrame signatureValidationFailureStackFrame = StackFrames.SignatureValidationFailed ??= new StackFrame(true); - return signatureValidationResult.UnwrapError().AddStackFrame(signatureValidationFailureStackFrame); - } + return signatureValidationResult.UnwrapError().AddCurrentStackFrame(); ValidationResult issuerSigningKeyValidationResult; diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.StackFrames.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.StackFrames.cs deleted file mode 100644 index 69a02ccacb..0000000000 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.StackFrames.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Diagnostics; -using Microsoft.IdentityModel.Tokens; - -#nullable enable -namespace Microsoft.IdentityModel.JsonWebTokens -{ - public partial class JsonWebTokenHandler : TokenHandler - { - // Cached stack frames to build exceptions from validation errors - internal static class StackFrames - { - // ValidateTokenAsync from string - internal static StackFrame? TokenStringNull; - internal static StackFrame? TokenStringValidationParametersNull; - internal static StackFrame? InvalidTokenLength; - internal static StackFrame? TokenStringValidationFailed; - internal static StackFrame? TokenStringReadFailed; - // ValidateTokenAsync from SecurityToken - internal static StackFrame? TokenNull; - internal static StackFrame? TokenValidationParametersNull; - internal static StackFrame? TokenNotJWT; - internal static StackFrame? TokenValidationFailed; - // ValidateJWEAsync - internal static StackFrame? DecryptionFailed; - internal static StackFrame? DecryptedReadFailed; - internal static StackFrame? JWEValidationFailed; - // ValidateJWSAsync - internal static StackFrame? LifetimeValidationFailed; - internal static StackFrame? AudienceValidationFailed; - internal static StackFrame? IssuerValidationFailed; - internal static StackFrame? ReplayValidationFailed; - internal static StackFrame? ActorReadFailed; - internal static StackFrame? ActorValidationFailed; - internal static StackFrame? TypeValidationFailed; - internal static StackFrame? SignatureValidationFailed; - internal static StackFrame? IssuerSigningKeyValidationFailed; - // DecryptToken - internal static StackFrame? DecryptionTokenNull; - internal static StackFrame? DecryptionValidationParametersNull; - internal static StackFrame? DecryptionHeaderMissing; - internal static StackFrame? DecryptionGetEncryptionKeys; - internal static StackFrame? DecryptionNoKeysTried; - internal static StackFrame? DecryptionKeyUnwrapFailed; - // ReadToken - internal static StackFrame? ReadTokenNullOrEmpty; - internal static StackFrame? ReadTokenMalformed; - // ValidateSignature - internal static StackFrame? KidNotMatchedNoTryAll; - internal static StackFrame? NoKeysProvided; - } - } -} -#nullable restore diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.DecryptTokenResult.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.DecryptTokenResult.cs index a4a242cd90..82a416b751 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.DecryptTokenResult.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.DecryptTokenResult.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; using System.Text; using Microsoft.IdentityModel.Tokens; using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages; @@ -28,12 +27,12 @@ internal static ValidationResult DecryptJwtToken( if (validationParameters == null) return ValidationError.NullParameter( nameof(validationParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); if (decryptionParameters == null) return ValidationError.NullParameter( nameof(decryptionParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); bool decryptionSucceeded = false; bool algorithmNotSupportedByCryptoProvider = false; @@ -124,7 +123,7 @@ internal static ValidationResult DecryptJwtToken( new MessageDetail(TokenLogMessages.IDX10679, zipAlgorithm), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenDecompressionFailedException), - new StackFrame(true), + ValidationError.GetCurrentStackFrame(), ex); } } diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs index 2794ff2d8d..02eb40bce4 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Globalization; using System.Security.Claims; using System.Security.Cryptography; @@ -373,7 +372,7 @@ private static ValidationError GetDecryptionError( LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenDecryptionFailedException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); else if (algorithmNotSupportedByCryptoProvider) return new ValidationError( new MessageDetail( @@ -382,7 +381,7 @@ private static ValidationError GetDecryptionError( LogHelper.MarkAsNonPII(decryptionParameters.Enc)), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenDecryptionFailedException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); else return new ValidationError( new MessageDetail( @@ -390,7 +389,7 @@ private static ValidationError GetDecryptionError( LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)), ValidationFailureType.TokenDecryptionFailed, typeof(SecurityTokenDecryptionFailedException), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); } private static byte[] DecryptToken(CryptoProviderFactory cryptoProviderFactory, SecurityKey key, string encAlg, byte[] ciphertext, byte[] headerAscii, byte[] initializationVector, byte[] authenticationTag) diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens.Saml/InternalAPI.Unshipped.txt index 55944f8e39..a5130b6d3f 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens.Saml/InternalAPI.Unshipped.txt @@ -1,6 +1,5 @@ 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 @@ -9,44 +8,22 @@ Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidatedConditions 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.SecurityToken securityToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> -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.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.SecurityToken securityToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> +Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(string token, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> 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.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.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(Microsoft.IdentityModel.Tokens.SecurityToken securityToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> +Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(string token, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> 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.Saml.SamlValidationError.CreateException() -> 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 +override Microsoft.IdentityModel.Tokens.Saml2.Saml2ValidationError.CreateException() -> System.Exception static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateSignature(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult static Microsoft.IdentityModel.Tokens.Saml.SamlTokenUtilities.PopulateValidationParametersWithCurrentConfigurationAsync(Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task -static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.AssertionConditionsNull -> System.Diagnostics.StackFrame -static Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.StackFrames.AssertionConditionsValidationFailed -> 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.Saml.SamlTokenUtilities.ResolveTokenSigningKey(Microsoft.IdentityModel.Xml.KeyInfo tokenKeyInfo, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters) -> Microsoft.IdentityModel.Tokens.SecurityKey -static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.AssertionConditionsNull -> System.Diagnostics.StackFrame -static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.AssertionConditionsValidationFailed -> 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.IssuerSigningKeyValidationFailed -> System.Diagnostics.StackFrame -static Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.StackFrames.IssuerValidationFailed -> 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.SignatureValidationFailed -> 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 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 virtual Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ProcessStatements(Microsoft.IdentityModel.Tokens.Saml.SamlSecurityToken samlToken, string issuer, Microsoft.IdentityModel.Tokens.ValidationParameters validationParameters) -> System.Collections.Generic.IEnumerable virtual Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ReadSamlToken(string token, Microsoft.IdentityModel.Tokens.CallContext callContext) -> Microsoft.IdentityModel.Tokens.ValidationResult diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/Exceptions/SamlValidationError.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/Exceptions/SamlValidationError.cs index d7f39f8cc4..8883c110ce 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/Exceptions/SamlValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/Exceptions/SamlValidationError.cs @@ -7,9 +7,20 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens.Saml { + /// + /// Represents a SAML validation error. + /// internal class SamlValidationError : ValidationError { - internal SamlValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the inner exception that occurred. + public SamlValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -19,7 +30,11 @@ internal SamlValidationError( { } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an Exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SamlSecurityTokenReadException)) { @@ -27,7 +42,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs index 2e073084f8..bdf1cdff34 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.Internal.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,11 +14,21 @@ namespace Microsoft.IdentityModel.Tokens.Saml /// public partial class SamlSecurityTokenHandler : SecurityTokenHandler { + /// + /// Validates a token. + /// On a validation failure, no exception will be thrown; instead, the will contain the information about the error that occurred. + /// Callers should always check the ValidationResult.IsValid property to verify the validity of the result. + /// + /// The token to be validated. + /// The to be used for validating the token. + /// A that contains call information. + /// A that can be used to request cancellation of the asynchronous operation. + /// A with either a if the token was validated or an with the failure information and exception otherwise. internal async Task> ValidateTokenAsync( string token, ValidationParameters validationParameters, CallContext callContext, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (token is null) return ValidationError.NullParameter(nameof(token), ValidationError.GetCurrentStackFrame()); @@ -38,16 +47,13 @@ internal async Task> ValidateTokenAsync( SecurityToken securityToken, ValidationParameters validationParameters, CallContext callContext, -#pragma warning disable CA1801 // Review unused parameters - CancellationToken cancellationToken) -#pragma warning restore CA1801 // Review unused parameters + CancellationToken cancellationToken = default) { if (securityToken is null) { - StackFrames.TokenNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(securityToken), - StackFrames.TokenNull); + ValidationError.GetCurrentStackFrame()); } if (securityToken is not SamlSecurityToken samlToken) @@ -65,10 +71,9 @@ internal async Task> ValidateTokenAsync( if (validationParameters is null) { - StackFrames.TokenValidationParametersNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(validationParameters), - StackFrames.TokenValidationParametersNull); + ValidationError.GetCurrentStackFrame()); } ValidationResult conditionsResult = ValidateConditions(samlToken, validationParameters, callContext); @@ -135,10 +140,7 @@ internal async Task> ValidateTokenAsync( ValidationResult signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext); if (!signatureValidationResult.IsValid) - { - StackFrames.SignatureValidationFailed ??= new StackFrame(true); - return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed); - } + return signatureValidationResult.UnwrapError().AddCurrentStackFrame(); ValidationResult issuerSigningKeyValidationResult; @@ -188,18 +190,16 @@ internal virtual ValidationResult ValidateConditions( { if (samlToken.Assertion is null) { - StackFrames.AssertionNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(samlToken.Assertion), - StackFrames.AssertionNull); + ValidationError.GetCurrentStackFrame()); } if (samlToken.Assertion.Conditions is null) { - StackFrames.AssertionConditionsNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(samlToken.Assertion.Conditions), - StackFrames.AssertionConditionsNull); + ValidationError.GetCurrentStackFrame()); } ValidationResult lifetimeValidationResult; diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.StackFrames.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.StackFrames.cs deleted file mode 100644 index c7a05acfc0..0000000000 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlSecurityTokenHandler.ValidateToken.StackFrames.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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; - internal static StackFrame? IssuerValidationFailed; - internal static StackFrame? SignatureValidationFailed; - - // Stack frames from ValidateConditions - internal static StackFrame? AudienceValidationFailed; - internal static StackFrame? AssertionNull; - internal static StackFrame? AssertionConditionsNull; - internal static StackFrame? AssertionConditionsValidationFailed; - internal static StackFrame? LifetimeValidationFailed; - internal static StackFrame? OneTimeUseValidationFailed; - } - } -} -#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Exceptions/Saml2ValidationError.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Exceptions/Saml2ValidationError.cs index 7425f50679..260f562096 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Exceptions/Saml2ValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Exceptions/Saml2ValidationError.cs @@ -7,9 +7,20 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens.Saml2 { + /// + /// Represents a SAML2 validation error. + /// internal class Saml2ValidationError : ValidationError { - internal Saml2ValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the inner exception that occurred. + public Saml2ValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -19,7 +30,11 @@ internal Saml2ValidationError( { } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an Exception. + protected override Exception CreateException() { if (ExceptionType == typeof(Saml2SecurityTokenReadException)) { @@ -27,7 +42,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } } diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs index 4b9f18d590..fbc070a505 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.Internal.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.IdentityModel.Tokens.Saml; @@ -16,11 +15,21 @@ namespace Microsoft.IdentityModel.Tokens.Saml2 /// public partial class Saml2SecurityTokenHandler : SecurityTokenHandler { + /// + /// Validates a token. + /// On a validation failure, no exception will be thrown; instead, the will contain the information about the error that occurred. + /// Callers should always check the ValidationResult.IsValid property to verify the validity of the result. + /// + /// The token to be validated. + /// The to be used for validating the token. + /// A that contains call information. + /// A that can be used to request cancellation of the asynchronous operation. + /// A with either a if the token was validated or an with the failure information and exception otherwise. internal async Task> ValidateTokenAsync( string token, ValidationParameters validationParameters, CallContext callContext, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (token is null) return ValidationError.NullParameter(nameof(token), ValidationError.GetCurrentStackFrame()); @@ -39,14 +48,13 @@ internal async Task> ValidateTokenAsync( SecurityToken securityToken, ValidationParameters validationParameters, CallContext callContext, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { if (securityToken is null) { - StackFrames.TokenNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(securityToken), - StackFrames.TokenNull); + ValidationError.GetCurrentStackFrame()); } if (securityToken is not Saml2SecurityToken samlToken) @@ -64,10 +72,9 @@ internal async Task> ValidateTokenAsync( if (validationParameters is null) { - StackFrames.TokenValidationParametersNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(validationParameters), - StackFrames.TokenValidationParametersNull); + ValidationError.GetCurrentStackFrame()); } validationParameters = await SamlTokenUtilities.PopulateValidationParametersWithCurrentConfigurationAsync(validationParameters, cancellationToken).ConfigureAwait(false); @@ -138,10 +145,7 @@ internal async Task> ValidateTokenAsync( var signatureValidationResult = ValidateSignature(samlToken, validationParameters, callContext); if (!signatureValidationResult.IsValid) - { - StackFrames.SignatureValidationFailed ??= new StackFrame(true); - return signatureValidationResult.UnwrapError().AddStackFrame(StackFrames.SignatureValidationFailed); - } + return signatureValidationResult.UnwrapError().AddCurrentStackFrame(); ValidationResult issuerSigningKeyValidationResult; @@ -191,18 +195,16 @@ internal virtual ValidationResult ValidateConditions( { if (samlToken.Assertion is null) { - StackFrames.AssertionNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(samlToken.Assertion), - StackFrames.AssertionNull); + ValidationError.GetCurrentStackFrame()); } if (samlToken.Assertion.Conditions is null) { - StackFrames.AssertionConditionsNull ??= new StackFrame(true); return ValidationError.NullParameter( nameof(samlToken.Assertion.Conditions), - StackFrames.AssertionConditionsNull); + ValidationError.GetCurrentStackFrame()); } ValidationResult lifetimeValidationResult; diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.StackFrames.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.StackFrames.cs deleted file mode 100644 index 42c3ee2832..0000000000 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2SecurityTokenHandler.ValidateToken.StackFrames.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Diagnostics; - -#nullable enable -namespace Microsoft.IdentityModel.Tokens.Saml2 -{ - public partial class Saml2SecurityTokenHandler : 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; - internal static StackFrame? IssuerSigningKeyValidationFailed; - internal static StackFrame? IssuerValidationFailed; - internal static StackFrame? SignatureValidationFailed; - - // Stack frames from ValidateConditions - internal static StackFrame? AudienceValidationFailed; - internal static StackFrame? AssertionNull; - internal static StackFrame? AssertionConditionsNull; - internal static StackFrame? AssertionConditionsValidationFailed; - internal static StackFrame? LifetimeValidationFailed; - internal static StackFrame? OneTimeUseValidationFailed; - } - } -} -#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 58044612f2..aa2b04cc0f 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -65,8 +65,8 @@ Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.InvalidSigningKey Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.IssuerSigningKeyValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, Microsoft.IdentityModel.Tokens.SecurityKey invalidSigningKey, System.Exception innerException = null) -> 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 = null) -> void -Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration = 1 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource -Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationParameters = 2 -> Microsoft.IdentityModel.Tokens.IssuerValidationSource +Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerValidationSource(string name) -> void +Microsoft.IdentityModel.Tokens.IssuerValidationSource.Name.get -> string Microsoft.IdentityModel.Tokens.LifetimeValidationError.Expires.get -> System.DateTime? Microsoft.IdentityModel.Tokens.LifetimeValidationError.LifetimeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, System.DateTime? notBefore, System.DateTime? expires, System.Exception innerException = null) -> void Microsoft.IdentityModel.Tokens.LifetimeValidationError.NotBefore.get -> System.DateTime? @@ -104,6 +104,16 @@ Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.get -> System.TimeProvider Microsoft.IdentityModel.Tokens.TokenValidationParameters.TimeProvider.set -> void Microsoft.IdentityModel.Tokens.ValidatedToken.Log(Microsoft.Extensions.Logging.ILogger logger) -> void +Microsoft.IdentityModel.Tokens.IssuerValidationSource +Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerValidationSource(string name) -> void +Microsoft.IdentityModel.Tokens.IssuerValidationSource.Name.get -> string +Microsoft.IdentityModel.Tokens.ValidatedIssuer +Microsoft.IdentityModel.Tokens.ValidatedIssuer.Issuer.get -> string +Microsoft.IdentityModel.Tokens.ValidatedIssuer.Issuer.init -> void +Microsoft.IdentityModel.Tokens.ValidatedIssuer.ValidatedIssuer() -> void +Microsoft.IdentityModel.Tokens.ValidatedIssuer.ValidatedIssuer(string Issuer, Microsoft.IdentityModel.Tokens.IssuerValidationSource ValidationSource) -> void +Microsoft.IdentityModel.Tokens.ValidatedIssuer.ValidationSource.get -> Microsoft.IdentityModel.Tokens.IssuerValidationSource +Microsoft.IdentityModel.Tokens.ValidatedIssuer.ValidationSource.init -> 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.Log(Microsoft.Extensions.Logging.ILogger logger) -> void @@ -132,6 +142,9 @@ static Microsoft.IdentityModel.Tokens.Utility.SerializeAsSingleCommaDelimitedStr static Microsoft.IdentityModel.Tokens.ValidationError.GetCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> System.Diagnostics.StackFrame static readonly Microsoft.IdentityModel.Telemetry.TelemetryDataRecorder.ConfigurationManagerCounter -> System.Diagnostics.Metrics.Counter static readonly Microsoft.IdentityModel.Telemetry.TelemetryDataRecorder.TotalDurationHistogram -> System.Diagnostics.Metrics.Histogram +static readonly Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedConfiguration -> Microsoft.IdentityModel.Tokens.IssuerValidationSource +static readonly Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationParameters -> Microsoft.IdentityModel.Tokens.IssuerValidationSource +static readonly Microsoft.IdentityModel.Tokens.IssuerValidationSource.NotValidated -> Microsoft.IdentityModel.Tokens.IssuerValidationSource static readonly Microsoft.IdentityModel.Tokens.LoggingEventId.TokenValidationFailed -> Microsoft.Extensions.Logging.EventId static readonly Microsoft.IdentityModel.Tokens.LoggingEventId.TokenValidationSucceeded -> Microsoft.Extensions.Logging.EventId static readonly Microsoft.IdentityModel.Telemetry.TelemetryDataRecorder.ConfigurationManagerCounter -> System.Diagnostics.Metrics.Counter diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AlgorithmValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AlgorithmValidationError.cs index de0dd174d5..d07e05a3fd 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AlgorithmValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AlgorithmValidationError.cs @@ -7,8 +7,21 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents a validation error that occurs when a token's algorithm cannot be validated. + /// If available, the invalid algorithm is stored in . + /// internal class AlgorithmValidationError : ValidationError { + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the algorithm that could not be validated. Can be null if the algorithm is missing from the token. + /// if present, represents the exception that occurred during validation. public AlgorithmValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, @@ -21,7 +34,11 @@ public AlgorithmValidationError( InvalidAlgorithm = invalidAlgorithm; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an Exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenInvalidAlgorithmException)) { @@ -34,10 +51,13 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } - protected string? InvalidAlgorithm { get; } + /// + /// The algorithm that could not be validated. + /// + public string? InvalidAlgorithm { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AudienceValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AudienceValidationError.cs index 4c6dbd42c3..0dd9ab9515 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AudienceValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/AudienceValidationError.cs @@ -8,8 +8,23 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when the token's audience cannot be validated. + /// If available, the invalid audiences from the token are stored in + /// and the allowed audiences are stored in . + /// internal class AudienceValidationError : ValidationError { + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// are the audiences that were in the token. Can be null if no audiences were found in the token. + /// are the audiences that were expected. Can be null if no valid audiences were provided in the validation parameters. + /// if present, represents the exception that occurred during validation. public AudienceValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, @@ -28,7 +43,7 @@ public AudienceValidationError( /// Creates an instance of an using /// /// An instance of an Exception. - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenInvalidAudienceException)) { @@ -38,11 +53,18 @@ internal override Exception GetException() return exception; } - return base.GetException(ExceptionType, null); + return base.CreateException(ExceptionType, null); } - protected IList? TokenAudiences { get; } - protected IList? ValidAudiences { get; } + /// + /// The audiences that were in the token. + /// + public IList? TokenAudiences { get; } + + /// + /// The audiences that were expected. + /// + public IList? ValidAudiences { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs index 8f380847ae..2251c43eb0 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerSigningKeyValidationError.cs @@ -7,9 +7,22 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents a validation error that occurs when the issuer signing key cannot be validated. + /// If available, the invalid signing key is stored in . + /// internal class IssuerSigningKeyValidationError : ValidationError { - internal IssuerSigningKeyValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the signing key that could not be validated. Can be null if the signing key for the token is missing. + /// if present, represents the exception that occurred during validation. + public IssuerSigningKeyValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -21,7 +34,11 @@ internal IssuerSigningKeyValidationError( InvalidSigningKey = invalidSigningKey; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an Exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenInvalidSigningKeyException)) { @@ -34,16 +51,25 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } - internal static new IssuerSigningKeyValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + /// + /// Creates a new instance of representing a null parameter. + /// + /// The name of the parameter. + /// The stack frame where the error occurred. + /// A new . + public static new IssuerSigningKeyValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, typeof(SecurityTokenArgumentNullException), stackFrame, null); // InvalidSigningKey + /// + /// The signing key that was found invalid. + /// protected SecurityKey? InvalidSigningKey { get; } } } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerValidationError.cs index 438681b973..8b384c763a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/IssuerValidationError.cs @@ -7,9 +7,22 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when the issuer of a token cannot be validated. + /// If available, the invalid issuer is stored in . + /// internal class IssuerValidationError : ValidationError { - internal IssuerValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the issuer that could not be validated. Can be null if the issuer is missing from the token. + /// if present, represents the exception that occurred during validation. + public IssuerValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -21,9 +34,16 @@ internal IssuerValidationError( InvalidIssuer = invalidIssuer; } - internal string? InvalidIssuer { get; } + /// + /// The issuer that could not be validated. + /// + public string? InvalidIssuer { get; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenInvalidIssuerException)) { @@ -36,7 +56,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/LifetimeValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/LifetimeValidationError.cs index f193985d81..38762280ad 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/LifetimeValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/LifetimeValidationError.cs @@ -7,8 +7,22 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when a token's lifetime cannot be validated. + /// If available, the not before and expires values are stored in and . + /// internal class LifetimeValidationError : ValidationError { + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the date from which the token is valid. Can be null if the token does not contain a not before claim. + /// is the date at which the token expires. Can be null if the token does not contain an expires claim. + /// if present, represents the exception that occurred during validation. public LifetimeValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, @@ -28,7 +42,7 @@ public LifetimeValidationError( /// Creates an instance of an using /// /// An instance of an Exception. - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenNoExpirationException)) { @@ -65,12 +79,18 @@ internal override Exception GetException() return exception; } else - return base.GetException(ExceptionType, null); + return base.CreateException(ExceptionType, null); } - protected DateTime? NotBefore { get; } + /// + /// The date from which the token is valid. + /// + public DateTime? NotBefore { get; } - protected DateTime? Expires { get; } + /// + /// The date at which the token expires. + /// + public DateTime? Expires { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/MessageDetail.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/MessageDetail.cs index 188e3a51b8..b0b71fd296 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/MessageDetail.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/MessageDetail.cs @@ -26,6 +26,11 @@ public MessageDetail(string formatString, params object[] parameters) Parameters = parameters; } + /// + /// Creates a message detail for a null parameter. + /// + /// The name of the parameter. + /// A new . public static MessageDetail NullParameter(string parameterName) => new MessageDetail(LogMessages.IDX10000, LogHelper.MarkAsNonPII(parameterName)); diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/SignatureValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/SignatureValidationError.cs index 78c51069d8..9d024a074f 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/SignatureValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/SignatureValidationError.cs @@ -7,8 +7,20 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when the token's signature cannot be validated. + /// internal class SignatureValidationError : ValidationError { + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// if present, is the inner validation error that caused this signature validation error. + /// if present, represents the exception that occurred during validation. public SignatureValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, @@ -21,7 +33,11 @@ public SignatureValidationError( InnerValidationError = innerValidationError; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an exception. + protected override Exception CreateException() { var inner = InnerException ?? InnerValidationError?.GetException(); @@ -40,10 +56,16 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } - internal static new SignatureValidationError NullParameter( + /// + /// Creates a new instance of representing a null parameter. + /// + /// The name of the parameter. + /// The stack frame where the error occurred. + /// A new . + public static new SignatureValidationError NullParameter( string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, @@ -51,7 +73,10 @@ internal override Exception GetException() stackFrame, null); // innerValidationError - protected internal ValidationError? InnerValidationError { get; } + /// + /// The inner validation error that caused this signature validation error. + /// + public ValidationError? InnerValidationError { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs index 02d2c53d4a..125df5e6a7 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenReplayValidationError.cs @@ -7,9 +7,22 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when a token cannot be validated against being re-used or replay is detected. + /// If available, the expiration time of the token that failed the validation is included. + /// internal class TokenReplayValidationError : ValidationError { - internal TokenReplayValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the expiration time of the token that failed the validation. Can be null if the token does not have an expiration time. + /// if present, represents the exception that occurred during validation. + public TokenReplayValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -21,7 +34,11 @@ internal TokenReplayValidationError( ExpirationTime = expirationTime; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenReplayDetectedException)) { @@ -38,17 +55,26 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } - internal static new TokenReplayValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + /// + /// Creates a new instance of representing a null parameter. + /// + /// The name of the parameter. + /// The stack frame where the error occurred. + /// A new . + public static new TokenReplayValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, typeof(SecurityTokenArgumentNullException), stackFrame, null); - protected DateTime? ExpirationTime { get; } + /// + /// The expiration time of the token that failed the validation. + /// + public DateTime? ExpirationTime { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs index 298abeefce..1dd7d5f68a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/TokenTypeValidationError.cs @@ -7,9 +7,22 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { + /// + /// Represents an error that occurs when a token type cannot be validated. + /// If available, the invalid token type is stored in . + /// internal class TokenTypeValidationError : ValidationError { - internal TokenTypeValidationError( + /// + /// Initializes a new instance of the class. + /// + /// contains information about the exception that is used to generate the exception message. + /// is the type of validation failure that occurred. + /// is the type of exception that occurred. + /// is the stack frame where the exception occurred. + /// is the token type that could not be validated. Can be null if the token type is missing from the token. + /// if present, represents the exception that occurred during validation. + public TokenTypeValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -21,7 +34,11 @@ internal TokenTypeValidationError( InvalidTokenType = invalidTokenType; } - internal override Exception GetException() + /// + /// Creates an instance of an using + /// + /// An instance of an exception. + protected override Exception CreateException() { if (ExceptionType == typeof(SecurityTokenInvalidTypeException)) { @@ -34,17 +51,26 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } - internal static new TokenTypeValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + /// + /// Creates a new instance of representing a null parameter. + /// + /// The name of the parameter. + /// The stack frame where the error occurred. + /// A new . + public static new TokenTypeValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, typeof(SecurityTokenArgumentNullException), stackFrame, null); // invalidTokenType - protected string? InvalidTokenType { get; } + /// + /// The token type that could not be validated. + /// + public string? InvalidTokenType { get; } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs index b4e0a6714f..2405a1e802 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs @@ -13,12 +13,15 @@ namespace Microsoft.IdentityModel.Tokens { /// - /// Contains information so that Exceptions can be logged or thrown written as required. + /// Represents an error that occurred during token validation. + /// If necessary, it can be used to create an instance of . /// internal class ValidationError { private Type _exceptionType; + private Exception? _exception; + /// /// Creates an instance of /// @@ -26,8 +29,8 @@ internal class ValidationError /// is the type of validation failure that occurred. /// is the type of exception that occurred. /// is the stack frame where the exception occurred. - /// is the inner exception that occurred. - internal ValidationError( + /// if present, represents the exception that occurred during validation. + internal protected ValidationError( MessageDetail messageDetail, ValidationFailureType validationFailureType, Type exceptionType, @@ -44,16 +47,24 @@ internal ValidationError( }; } + public Exception GetException() + { + if (_exception is null) + _exception = CreateException(); + + return _exception; + } + /// /// Creates an instance of an using /// /// An instance of an Exception. - internal virtual Exception GetException() + protected virtual Exception CreateException() { - return GetException(ExceptionType, InnerException); + return CreateException(ExceptionType, InnerException); } - internal Exception GetException(Type exceptionType, Exception? innerException) + internal Exception CreateException(Type exceptionType, Exception? innerException) { Exception? exception = null; @@ -184,12 +195,22 @@ internal Exception GetException(Type exceptionType, Exception? innerException) return exception; } - internal void Log(ILogger logger) + /// + /// Logs the validation error. + /// + /// The to be used for logging. + public void Log(ILogger logger) { Logger.TokenValidationFailed(logger, FailureType.Name, MessageDetail.Message); } - internal static ValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( + /// + /// Creates a new instance of representing a null parameter. + /// + /// The name of the parameter. + /// The stack frame where the error occurred. + /// A new . + public static ValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, typeof(SecurityTokenArgumentNullException), @@ -211,6 +232,11 @@ internal void Log(ILogger logger) /// public Exception? InnerException { get; } + /// + /// Gets the message that explains the error. + /// + public string Message => MessageDetail.Message; + /// /// Gets the message details that are used to generate the exception message. /// @@ -240,7 +266,7 @@ public ValidationError AddStackFrame(StackFrame stackFrame) /// The line number from which this method is called. CAptured automatically by default. /// The number of stack frames to skip when capturing. Used to avoid capturing this method and get the caller instead. /// The updated object. - internal ValidationError AddCurrentStackFrame([CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, int skipFrames = 1) + public ValidationError AddCurrentStackFrame([CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, int skipFrames = 1) { // We add 1 to the skipped frames to skip the current method StackFrames.Add(GetCurrentStackFrame(filePath, lineNumber, skipFrames + 1)); @@ -256,7 +282,7 @@ internal ValidationError AddCurrentStackFrame([CallerFilePath] string filePath = /// The number of stack frames to skip when capturing. Used to avoid capturing this method and get the caller instead. /// The captured stack frame. /// If this is called from a helper method, consider adding an extra skip frame to avoid capturing the helper instead. - internal static StackFrame GetCurrentStackFrame( + public static StackFrame GetCurrentStackFrame( [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, int skipFrames = 1) { // String is allocated, but it goes out of scope immediately after the call @@ -286,7 +312,13 @@ private static class Logger public static void TokenValidationFailed( ILogger logger, string validationFailureType, - string messageDetail) => s_tokenValidationFailed(logger, validationFailureType, messageDetail, null); + string messageDetail) + { + if (logger.IsEnabled(LogLevel.Information)) + { + s_tokenValidationFailed(logger, validationFailureType, messageDetail, null); + } + } } } } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/IssuerValidationSource.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/IssuerValidationSource.cs new file mode 100644 index 0000000000..7d066dd15a --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/IssuerValidationSource.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Represents the source from which the token issuer was validated. + /// i.e. whether the issuer was matched with the configuration provided or the validation parameters provided. + /// If a custom issuer validation delegate is used, a custom validation source can be instantiated and used. + /// + internal class IssuerValidationSource + { + /// + /// Initializes a new instance of . + /// + /// The name of the issuer validation source. + public IssuerValidationSource(string name) => Name = name; + + /// + /// The name of the issuer validation source. + /// + public string Name { get; } + + /// + /// Represents the issuer validation source that has not been validated. + /// + public static readonly IssuerValidationSource NotValidated = new("NotValidated"); + + /// + /// Represents the issuer validation source that has been matched with the configuration provided. + /// + public static readonly IssuerValidationSource IssuerMatchedConfiguration = new("IssuerMatchedConfiguration"); + + /// + /// Represents the issuer validation source that has been matched with the validation parameters provided. + /// + public static readonly IssuerValidationSource IssuerMatchedValidationParameters = new("IssuerMatchedValidationParameters"); + + /// + /// The issuer validation source's string representation. + /// + /// The name of the issuer validation source. + public override string ToString() => Name; + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedIssuer.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedIssuer.cs new file mode 100644 index 0000000000..d797da269a --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedIssuer.cs @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Represents a validated issuer, including the source of the validation. + /// + internal readonly struct ValidatedIssuer : IEquatable + { + /// + /// Initializes a new instance of . + /// + /// The issuer that was validated. + /// The source of the validation, i.e. configuration, validation parameters. + public ValidatedIssuer(string issuer, IssuerValidationSource validationSource) + { + Issuer = issuer; + ValidationSource = validationSource; + } + + /// + /// The issuer that was validated. + /// + public string Issuer { get; } + + /// + /// The source of the validation, i.e. configuration, validation parameters. + /// + public IssuerValidationSource ValidationSource { get; } + + /// + /// Determines whether the specified object is equal to the current instance of . + /// + /// The object to compare with the current instance. + /// true if the specified object is equal to the current instance; otherwise, false. + public override bool Equals(object? obj) + { + if (obj is ValidatedIssuer other) + { + return Equals(other); + } + + return false; + } + + /// + /// Returns the hash code for this instance of . + /// + /// + public override int GetHashCode() + { + return Issuer.GetHashCode() ^ ValidationSource.GetHashCode(); + } + + /// + /// Equality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is equal to the right one. + public static bool operator ==(ValidatedIssuer left, ValidatedIssuer right) + { + return left.Equals(right); + } + + /// + /// Inequality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is not equal to the right one. + public static bool operator !=(ValidatedIssuer left, ValidatedIssuer right) + { + return !(left == right); + } + + /// + /// Determines whether the specified is equal to the current instance. + /// + /// The to compare with the current instance. + /// true if the specified is equal to the current instance; otherwise, false. + public bool Equals(ValidatedIssuer other) + { + if (other.Issuer != Issuer || other.ValidationSource != ValidationSource) + { + return false; + } + + return true; + } + + /// + /// The validated issuer's string representation. + /// + /// A string representing the issuer and where it was validated from. + public override string ToString() => $"{Issuer} (from {ValidationSource})"; + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedLifetime.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedLifetime.cs new file mode 100644 index 0000000000..7ad05123a3 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedLifetime.cs @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Represents a validated lifetime, including the NotBefore and Expires values. + /// + internal readonly struct ValidatedLifetime : IEquatable + { + /// + /// Initializes a new instance of . + /// + /// The representing the time from which the token is considered valid. + /// The representing the token's expiration time. + public ValidatedLifetime(DateTime? notBefore, DateTime? expires) + { + NotBefore = notBefore; + Expires = expires; + } + + /// + /// The representing the time from which the token is considered valid. + /// + public DateTime? NotBefore { get; } + + /// + /// The representing the token's expiration time. + /// + public DateTime? Expires { get; } + + /// + /// Determines whether the specified object is equal to the current instance of . + /// + /// The object to compare with the current instance. + /// true if the specified object is equal to the current instance; otherwise, false. + public override bool Equals(object? obj) + { + if (obj is ValidatedLifetime other) + { + return Equals(other); + } + + return false; + } + + /// + /// Returns the hash code for this instance of . + /// + /// + public override int GetHashCode() + { + return NotBefore.GetHashCode() ^ Expires.GetHashCode(); + } + + /// + /// Equality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is equal to the right one. + public static bool operator ==(ValidatedLifetime left, ValidatedLifetime right) + { + return left.Equals(right); + } + + /// + /// Inequality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is not equal to the right one. + public static bool operator !=(ValidatedLifetime left, ValidatedLifetime right) + { + return !(left == right); + } + + /// + /// Determines whether the specified is equal to the current instance. + /// + /// The to compare with the current instance. + /// true if the specified is equal to the current instance; otherwise, false. + public bool Equals(ValidatedLifetime other) + { + if (other.NotBefore != NotBefore || other.Expires != Expires) + { + return false; + } + + return true; + } + + /// + /// The validated lifetime's string representation. + /// + /// A string representing the validated lifetime. + public override string ToString() => $"[{NotBefore}, {Expires}]"; + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedSigningKeyLifetime.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedSigningKeyLifetime.cs new file mode 100644 index 0000000000..646ba63e97 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedSigningKeyLifetime.cs @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Represents a validated signing key lifetime. + /// + internal readonly struct ValidatedSigningKeyLifetime : IEquatable + { + /// + /// Initializes a new instance of . + /// + /// The date from which the signing key is considered valid. + /// The date until which the signing key is considered valid. + /// The time the validation occurred. + internal ValidatedSigningKeyLifetime(DateTime? validFrom, DateTime? validTo, DateTime? validationTime) + { + ValidFrom = validFrom; + ValidTo = validTo; + ValidationTime = validationTime; + } + + /// + /// The date from which the signing key is considered valid. + /// + public DateTime? ValidFrom { get; } + + /// + /// The date until which the signing key is considered valid. + /// + public DateTime? ValidTo { get; } + + /// + /// The time the validation occurred. + /// + public DateTime? ValidationTime { get; } + + /// + /// Determines whether the specified object is equal to the current instance of . + /// + /// The object to compare with the current instance. + /// true if the specified object is equal to the current instance; otherwise, false. + public override bool Equals(object? obj) + { + if (obj is ValidatedSigningKeyLifetime other) + { + return Equals(other); + } + + return false; + } + + /// + /// Returns the hash code for this instance of . + /// + /// + public override int GetHashCode() + { + return ValidFrom.GetHashCode() ^ ValidTo.GetHashCode() ^ ValidationTime.GetHashCode(); + } + + /// + /// Equality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is equal to the right one. + public static bool operator ==(ValidatedSigningKeyLifetime left, ValidatedSigningKeyLifetime right) + { + return left.Equals(right); + } + + /// + /// Inequality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is not equal to the right one. + public static bool operator !=(ValidatedSigningKeyLifetime left, ValidatedSigningKeyLifetime right) + { + return !(left == right); + } + + /// + /// Determines whether the specified is equal to the current instance. + /// + /// The to compare with the current instance. + /// true if the specified is equal to the current instance; otherwise, false. + public bool Equals(ValidatedSigningKeyLifetime other) + { + if (other.ValidFrom != ValidFrom || other.ValidTo != ValidTo || other.ValidationTime != ValidationTime) + { + return false; + } + + return true; + } + + /// + /// The validated signing key lifetime's string representation. + /// + /// A string that represents the validated signing key lifetime and the validation time. + public override string ToString() => $"{ValidationTime} ∊ [{ValidFrom}, {ValidTo}]"; + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs index 7eccd96c75..f2e87c33ef 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs @@ -17,27 +17,26 @@ namespace Microsoft.IdentityModel.Tokens internal class ValidatedToken { /// - /// Creates an instance of + /// Initializes a new instance of . /// - /// The that is being validated. - /// The that is being used to validate the token. - /// The to be used for validating the token. - internal ValidatedToken( + /// The that was validated. + /// The that was used to validate the token. + /// The used to validate the token. + /// If , , or is null. + public ValidatedToken( SecurityToken securityToken, TokenHandler tokenHandler, ValidationParameters validationParameters) { - TokenHandler = tokenHandler ?? throw new ArgumentNullException(nameof(tokenHandler)); SecurityToken = securityToken ?? throw new ArgumentNullException(nameof(securityToken)); + TokenHandler = tokenHandler ?? throw new ArgumentNullException(nameof(tokenHandler)); ValidationParameters = validationParameters ?? throw new ArgumentNullException(nameof(validationParameters)); } /// /// Logs the validation result. /// - public void Log(ILogger logger) - { - Logger.TokenValidationSucceeded( + public void Log(ILogger logger) => Logger.TokenValidationSucceeded( logger, ValidatedAudience ?? "none", ValidatedLifetime, @@ -46,29 +45,61 @@ public void Log(ILogger logger) ValidatedSigningKey?.KeyId ?? "none", ActorValidationResult is not null ); - } - public SecurityToken SecurityToken { get; private set; } + /// + /// The that was validated. + /// + public SecurityToken SecurityToken { get; } - public TokenHandler TokenHandler { get; private set; } + /// + /// The that was used to validate the token. + /// + public TokenHandler TokenHandler { get; } - public ValidationParameters ValidationParameters { get; private set; } + /// + /// The that were used to validate the token. + /// + public ValidationParameters ValidationParameters { get; } #region Validated Properties + /// + /// The result of validating the actor, if any. + /// public ValidatedToken? ActorValidationResult { get; internal set; } + /// + /// The audience that was validated, if any. + /// public string? ValidatedAudience { get; internal set; } + /// + /// The issuer that was validated. If present, it contains the source of the validation as well. + /// public ValidatedIssuer? ValidatedIssuer { get; internal set; } + /// + /// The lifetime that was validated, if any. + /// public ValidatedLifetime? ValidatedLifetime { get; internal set; } + /// + /// The expiration time of the token that was used to validate the token was not replayed, if any. + /// public DateTime? ValidatedTokenReplayExpirationTime { get; internal set; } + /// + /// The token type that was validated, if any. + /// public ValidatedTokenType? ValidatedTokenType { get; internal set; } + /// + /// The that was used to validate the token, if any. + /// public SecurityKey? ValidatedSigningKey { get; internal set; } + /// + /// The validated lifetime of the that was used to sign the token, if any. + /// public ValidatedSigningKeyLifetime? ValidatedSigningKeyLifetime { get; internal set; } #endregion @@ -177,6 +208,9 @@ private object ClaimsIdentitySyncObj #endregion #region Logging + /// + /// Internal class used for logging. + /// private static class Logger { private static readonly Action s_tokenValidationFailed = @@ -195,7 +229,13 @@ private static class Logger public static void TokenValidationFailed( ILogger logger, ValidationFailureType validationFailureType, - MessageDetail messageDetail) => s_tokenValidationFailed(logger, validationFailureType.Name, messageDetail.Message, null); + MessageDetail messageDetail) + { + if (logger.IsEnabled(LogLevel.Information)) + { + s_tokenValidationFailed(logger, validationFailureType.Name, messageDetail.Message, null); + } + } private static readonly Action s_tokenValidationSucceeded = LoggerMessage.Define( @@ -226,15 +266,21 @@ public static void TokenValidationSucceeded( ValidatedIssuer? validatedIssuer, ValidatedTokenType? validatedTokenType, string validatedSigningKeyId, - bool actorWasValidated) => s_tokenValidationSucceeded( - logger, - validatedAudience, - validatedLifetime, - validatedIssuer, - validatedTokenType, - validatedSigningKeyId, - actorWasValidated, - null); + bool actorWasValidated) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + s_tokenValidationSucceeded( + logger, + validatedAudience, + validatedLifetime, + validatedIssuer, + validatedTokenType, + validatedSigningKeyId, + actorWasValidated, + null); + } + } } #endregion } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedTokenType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedTokenType.cs new file mode 100644 index 0000000000..e94470c95e --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedTokenType.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +#nullable enable +namespace Microsoft.IdentityModel.Tokens +{ + /// + /// Represents a validated token type, including the number of valid types present in the validation parameters. + /// + internal readonly struct ValidatedTokenType : IEquatable + { + /// + /// Initializes a new instance of . + /// + /// The token type that was validated. + /// The number of valid types present in the validation parameters. + public ValidatedTokenType(string type, int validTypeCount) + { + Type = type; + ValidTypeCount = validTypeCount; + } + + /// + /// The token type that was validated. + /// + public string Type { get; } + + /// + /// The number of valid types present in the validation parameters. + /// + public int ValidTypeCount { get; } + + /// + /// Determines whether the specified object is equal to the current instance of . + /// + /// The object to compare with the current instance. + /// true if the specified object is equal to the current instance; otherwise, false. + public override bool Equals(object? obj) + { + if (obj is ValidatedTokenType other) + { + return Equals(other); + } + + return false; + } + + /// + /// Returns the hash code for this instance of . + /// + /// The hash code for the current instance. + public override int GetHashCode() + { + return Type.GetHashCode() ^ ValidTypeCount.GetHashCode(); + } + + /// + /// Equality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is equal to the right one. + public static bool operator ==(ValidatedTokenType left, ValidatedTokenType right) + { + return left.Equals(right); + } + + /// + /// Inequality comparison operator for . + /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is not equal to the right one. + public static bool operator !=(ValidatedTokenType left, ValidatedTokenType right) + { + return !(left == right); + } + + /// + /// Determines whether the specified is equal to the current instance. + /// + /// The to compare with the current instance. + /// true if the specified is equal to the current instance; otherwise, false. + public bool Equals(ValidatedTokenType other) + { + if (other.Type != Type || other.ValidTypeCount != ValidTypeCount) + return false; + + return true; + } + + /// + /// The validated token type's string representation. + /// + /// A string representing the validated token type and the amount of valid types. + public override string ToString() => $"{Type} ({ValidTypeCount} valid types)"; + } +} +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidationResult.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidationResult.cs index 1d5c475ba4..8bb3c9d5e0 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidationResult.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidationResult.cs @@ -17,7 +17,8 @@ namespace Microsoft.IdentityModel.Tokens readonly ValidationError? _error; /// - /// Creates a successful, valid validation result. + /// Creates a new instance of indicating a successful operation + /// and containing an object of the associated type. /// /// The value associated with the success. public ValidationResult(TResult result) @@ -28,7 +29,8 @@ public ValidationResult(TResult result) } /// - /// Creates an error, invalid validation result. + /// Creates a new instance of indicating a failed operation + /// and containing a with the error information. /// /// The error associated with the failure. public ValidationResult(ValidationError error) @@ -115,10 +117,10 @@ public TResult? Result } /// - /// + /// Determines whether the specified object is equal to the current instance of . /// - /// - /// + /// The object to compare with the current instance. + /// true if the specified object is equal to the current instance; otherwise, false. public override bool Equals(object? obj) { if (obj is ValidationResult other) @@ -130,10 +132,9 @@ public override bool Equals(object? obj) } /// - /// + /// Returns the hash code for this instance of . /// - /// - /// + /// The hash code for the current instance. public override int GetHashCode() { if (IsValid) @@ -143,32 +144,32 @@ public override int GetHashCode() } /// - /// + /// Equality comparison operator for . /// - /// - /// - /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is equal to the right one. public static bool operator ==(ValidationResult left, ValidationResult right) { return left.Equals(right); } /// - /// + /// Inequality comparison operator for . /// - /// - /// - /// + /// The left value to compare. + /// The right value to compare. + /// A boolean indicating whether the left value is not equal to the right one. public static bool operator !=(ValidationResult left, ValidationResult right) { return !(left == right); } /// - /// + /// Determines whether the specified is equal to the current instance. /// - /// - /// + /// The to compare with the current instance. + /// true if the specified is equal to the current instance; otherwise, false. public bool Equals(ValidationResult other) { if (other.IsValid != IsValid) @@ -185,7 +186,7 @@ public bool Equals(ValidationResult other) /// # /// Required for compatibility, see CA2225 for more information /// The existing instance. - public ValidationResult ToResult() + public ValidationResult ToValidationResult() { return this; } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs index 24fdaed4e5..6b0d151d0a 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/ValidationParameters.cs @@ -8,6 +8,7 @@ using System.Threading; using Microsoft.IdentityModel.Logging; +#nullable enable namespace Microsoft.IdentityModel.Tokens { /// @@ -15,21 +16,24 @@ namespace Microsoft.IdentityModel.Tokens /// internal class ValidationParameters { - private string _authenticationType; + private string? _authenticationType; private TimeSpan _clockSkew = DefaultClockSkew; private string _nameClaimType = ClaimsIdentity.DefaultNameClaimType; private string _roleClaimType = ClaimsIdentity.DefaultRoleClaimType; - private Dictionary _instancePropertyBag; - private IList _issuerSigningKeys; - private IList _validIssuers; - private IList _validTokenTypes; - private IList _validAudiences; + private Dictionary? _instancePropertyBag; + private IList? _issuerSigningKeys; + private IDictionary? _propertyBag; + private IList? _tokenDecryptionKeys; + private IList? _validIssuers; + private IList? _validTokenTypes; + private IList? _validAudiences; + private IList? _validAlgorithms; private AlgorithmValidationDelegate _algorithmValidator = Validators.ValidateAlgorithm; private AudienceValidationDelegate _audienceValidator = Validators.ValidateAudience; private IssuerValidationDelegateAsync _issuerValidatorAsync = Validators.ValidateIssuerAsync; private LifetimeValidationDelegate _lifetimeValidator = Validators.ValidateLifetime; - private SignatureValidationDelegate _signatureValidator; + private SignatureValidationDelegate? _signatureValidator; private TokenReplayValidationDelegate _tokenReplayValidator = Validators.ValidateTokenReplay; private TokenTypeValidationDelegate _tokenTypeValidator = Validators.ValidateTokenType; private IssuerSigningKeyValidationDelegate _issuerSigningKeyValidator = Validators.ValidateIssuerSigningKey; @@ -61,11 +65,13 @@ protected ValidationParameters(ValidationParameters other) if (other == null) throw LogHelper.LogExceptionMessage(new ArgumentNullException(nameof(other))); + ActorValidationParameters = other.ActorValidationParameters; AlgorithmValidator = other.AlgorithmValidator; AudienceValidator = other.AudienceValidator; _authenticationType = other._authenticationType; ClockSkew = other.ClockSkew; ConfigurationManager = other.ConfigurationManager; + CryptoProviderFactory = other.CryptoProviderFactory; DebugId = other.DebugId; IncludeTokenOnFailedValidation = other.IncludeTokenOnFailedValidation; IgnoreTrailingSlashWhenValidatingAudience = other.IgnoreTrailingSlashWhenValidatingAudience; @@ -77,24 +83,23 @@ protected ValidationParameters(ValidationParameters other) LogTokenId = other.LogTokenId; NameClaimType = other.NameClaimType; NameClaimTypeRetriever = other.NameClaimTypeRetriever; - PropertyBag = other.PropertyBag; + _propertyBag = other.PropertyBag; RefreshBeforeValidation = other.RefreshBeforeValidation; RoleClaimType = other.RoleClaimType; RoleClaimTypeRetriever = other.RoleClaimTypeRetriever; SaveSigninToken = other.SaveSigninToken; - SignatureValidator = other.SignatureValidator; + _signatureValidator = other.SignatureValidator; TimeProvider = other.TimeProvider; TokenDecryptionKeyResolver = other.TokenDecryptionKeyResolver; - TokenDecryptionKeys = other.TokenDecryptionKeys; + _tokenDecryptionKeys = other.TokenDecryptionKeys; TokenReplayCache = other.TokenReplayCache; TokenReplayValidator = other.TokenReplayValidator; TokenTypeValidator = other.TokenTypeValidator; ValidateActor = other.ValidateActor; - ValidateSignatureLast = other.ValidateSignatureLast; ValidateWithLKG = other.ValidateWithLKG; - ValidAlgorithms = other.ValidAlgorithms; _validIssuers = other.ValidIssuers; _validAudiences = other.ValidAudiences; + _validAlgorithms = other.ValidAlgorithms; _validTokenTypes = other.ValidTypes; } @@ -111,7 +116,7 @@ public ValidationParameters() /// /// Gets or sets . /// - public ValidationParameters ActorValidationParameters { get; set; } + public ValidationParameters? ActorValidationParameters { get; set; } /// /// Allows overriding the delegate used to validate the cryptographic algorithm used. @@ -145,7 +150,7 @@ public AudienceValidationDelegate AudienceValidator /// Gets or sets the AuthenticationType when creating a . /// /// If 'value' is null or whitespace. - public string AuthenticationType + public string? AuthenticationType { get { @@ -158,7 +163,7 @@ public string AuthenticationType throw LogHelper.LogExceptionMessage(new ArgumentNullException("AuthenticationType")); } - _authenticationType = value; + _authenticationType = value!; } } @@ -230,26 +235,28 @@ public virtual ClaimsIdentity CreateClaimsIdentity(SecurityToken securityToken, //if (LogHelper.IsEnabled(EventLogLevel.Informational)) // LogHelper.LogInformation(LogMessages.IDX10245, securityToken); -#pragma warning disable RS0030 // Do not use banned APIs - return new ClaimsIdentity(authenticationType: AuthenticationType ?? DefaultAuthenticationType, nameType: nameClaimType ?? ClaimsIdentity.DefaultNameClaimType, roleType: roleClaimType ?? ClaimsIdentity.DefaultRoleClaimType); -#pragma warning disable RS0030 // Do not use banned APIs + return ClaimsIdentityFactory.Create( + authenticationType: AuthenticationType ?? DefaultAuthenticationType, + nameType: nameClaimType ?? ClaimsIdentity.DefaultNameClaimType, + roleType: roleClaimType ?? ClaimsIdentity.DefaultRoleClaimType, + securityToken); } /// /// If set, this property will be used to obtain the issuer and signing keys associated with the metadata endpoint of . /// The obtained issuer and signing keys will then be used along with those present on the ValidationParameters for validation of the incoming token. /// - public BaseConfigurationManager ConfigurationManager { get; set; } + public BaseConfigurationManager? ConfigurationManager { get; set; } /// /// Users can override the default with this property. This factory will be used for creating signature providers. /// - public CryptoProviderFactory CryptoProviderFactory { get; set; } + public CryptoProviderFactory? CryptoProviderFactory { get; set; } /// /// Gets or sets a string that helps with setting breakpoints when debugging. /// - public string DebugId { get; set; } + public string? DebugId { get; set; } /// /// Gets or sets a boolean that controls if a '/' is significant at the end of the audience. @@ -282,7 +289,8 @@ public IssuerSigningKeyValidationDelegate IssuerSigningKeyValidator /// Gets a that is unique to this instance. /// Calling will result in a new instance of this IDictionary. /// - public IDictionary InstancePropertyBag => _instancePropertyBag ??= new Dictionary(); + public IDictionary InstancePropertyBag => + _instancePropertyBag ??= new Dictionary(); /// /// Gets a value indicating if was called to obtain this instance. @@ -294,18 +302,25 @@ public IssuerSigningKeyValidationDelegate IssuerSigningKeyValidator /// /// /// This will be used to check the signature. This can be helpful when the does not contain a key identifier. - /// If both and are set, IssuerSigningKeyResolverUsingConfiguration takes - /// priority. /// - public IssuerSigningKeyResolverDelegate IssuerSigningKeyResolver { get; set; } + public IssuerSigningKeyResolverDelegate? IssuerSigningKeyResolver { get; set; } /// /// Gets the used for signature validation. /// - public IList IssuerSigningKeys => - _issuerSigningKeys ?? - Interlocked.CompareExchange(ref _issuerSigningKeys, [], null) ?? - _issuerSigningKeys; + public IList IssuerSigningKeys + { + get + { + return _issuerSigningKeys ?? + Interlocked.CompareExchange(ref _issuerSigningKeys, [], null) ?? + _issuerSigningKeys; + } + internal set + { + _issuerSigningKeys = value; + } + } /// /// Allows overriding the delegate that will be used to validate the issuer of the token. @@ -368,13 +383,13 @@ public string NameClaimType /// The issuer associated with the token. /// Returns the value that will set the property . /// - public Func NameClaimTypeRetriever { get; set; } + public Func? NameClaimTypeRetriever { get; set; } /// /// Gets or sets the that contains a collection of custom key/value pairs. /// This allows addition of parameters that could be used in custom token validation scenarios. /// - public IDictionary PropertyBag { get; } + public IDictionary PropertyBag => _propertyBag ??= new Dictionary(); /// /// A boolean to control whether configuration should be refreshed before validating a token. @@ -418,7 +433,7 @@ public string RoleClaimType /// The issuer associated with the token. /// Returns the value that will set the property . /// - public Func RoleClaimTypeRetriever { get; set; } + public Func? RoleClaimTypeRetriever { get; set; } /// /// Gets or sets a boolean to control if the original token should be saved after the security token is validated. @@ -435,7 +450,7 @@ public string RoleClaimType /// /// If set, this delegate will be called to validate the signature of the token, instead of default processing. /// - public SignatureValidationDelegate SignatureValidator + public SignatureValidationDelegate? SignatureValidator { get { return _signatureValidator; } set { _signatureValidator = value; } @@ -452,18 +467,30 @@ public SignatureValidationDelegate SignatureValidator /// /// This will be used to decrypt the token. This can be helpful when the does not contain a key identifier. /// - internal DecryptionKeyResolverDelegate TokenDecryptionKeyResolver { get; set; } + internal DecryptionKeyResolverDelegate? TokenDecryptionKeyResolver { get; set; } /// /// Gets the that is to be used for decrypting inbound tokens. /// - public IList TokenDecryptionKeys { get; internal set; } + public IList TokenDecryptionKeys + { + get + { + return _tokenDecryptionKeys ?? + Interlocked.CompareExchange(ref _tokenDecryptionKeys, [], null) ?? + _tokenDecryptionKeys; + } + internal set + { + _tokenDecryptionKeys = value; + } + } /// /// Gets or set the that store tokens that can be checked to help detect token replay. /// /// If set, then tokens must have an expiration time or the runtime will fault. - public ITokenReplayCache TokenReplayCache { get; set; } + public ITokenReplayCache? TokenReplayCache { get; set; } /// /// Allows overriding the delegate that will be used to validate the token replay of the token. @@ -514,15 +541,6 @@ public TokenTypeValidationDelegate TokenTypeValidator [DefaultValue(false)] public bool ValidateWithLKG { get; set; } - /// - /// Gets or sets a boolean that controls the validation order of the payload and signature during token validation. - /// - /// If is set to true, it will validate payload ahead of signature. - /// The default is false. - /// - [DefaultValue(false)] - public bool ValidateSignatureLast { get; set; } - /// /// Gets or sets the valid algorithms for cryptographic operations. /// @@ -530,26 +548,56 @@ public TokenTypeValidationDelegate TokenTypeValidator /// If set to a non-empty collection, only the algorithms listed will be considered valid. /// The default is null. /// - public IList ValidAlgorithms { get; set; } + public IList ValidAlgorithms + { + get + { + return _validAlgorithms ?? + Interlocked.CompareExchange(ref _validAlgorithms, [], null) ?? + _validAlgorithms; + } + internal set + { + _validAlgorithms = value; + } + } /// /// Gets the that contains valid audiences that will be used to check against the token's audience. /// The default is an empty collection. /// - public IList ValidAudiences => - _validAudiences ?? - Interlocked.CompareExchange(ref _validAudiences, [], null) ?? - _validAudiences; + public IList ValidAudiences + { + get + { + return _validAudiences ?? + Interlocked.CompareExchange(ref _validAudiences, [], null) ?? + _validAudiences; + } + internal set + { + _validAudiences = value; + } + } /// /// Gets the that contains valid issuers that will be used to check against the token's issuer. /// The default is an empty collection. /// /// The that contains valid issuers that will be used to check against the token's 'iss' claim. - public IList ValidIssuers => - _validIssuers ?? - Interlocked.CompareExchange(ref _validIssuers, [], null) ?? - _validIssuers; + public IList ValidIssuers + { + get + { + return _validIssuers ?? + Interlocked.CompareExchange(ref _validIssuers, [], null) ?? + _validIssuers; + } + internal set + { + _validIssuers = value; + } + } /// /// Gets the that contains valid types that will be used to check against the JWT header's 'typ' claim. @@ -558,11 +606,25 @@ public TokenTypeValidationDelegate TokenTypeValidator /// The default is an empty collection. /// /// The that contains valid token types that will be used to check against the token's 'typ' claim. - public IList ValidTypes => - _validTokenTypes ?? - Interlocked.CompareExchange(ref _validTokenTypes, [], null) ?? - _validTokenTypes; + public IList ValidTypes + { + get + { + return _validTokenTypes ?? + Interlocked.CompareExchange(ref _validTokenTypes, [], null) ?? + _validTokenTypes; + } + internal set + { + _validTokenTypes = value; + } + } + /// + /// Gets or sets a boolean that controls if the actor claim should be validated. + /// + /// Default value is false. public bool ValidateActor { get; set; } } } +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Algorithm.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Algorithm.cs index 4950042e26..1ed23b224b 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Algorithm.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Algorithm.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Diagnostics; using System.Linq; using Microsoft.IdentityModel.Logging; @@ -26,6 +25,9 @@ internal delegate ValidationResult AlgorithmValidationDelegate( ValidationParameters validationParameters, CallContext callContext); + /// + /// Partial class for Algorithm Validation. + /// public static partial class Validators { /// @@ -35,20 +37,20 @@ public static partial class Validators /// The that signed the . /// The being validated. /// required for validation. - /// -#pragma warning disable CA1801 // TODO: remove pragma disable once callContext is used for logging + /// The that contains call information. internal static ValidationResult ValidateAlgorithm( string algorithm, +#pragma warning disable CA1801 SecurityKey securityKey, SecurityToken securityToken, ValidationParameters validationParameters, CallContext callContext) -#pragma warning restore CA1801 // TODO: remove pragma disable once callContext is used for logging +#pragma warning restore CA1801 { if (validationParameters == null) return ValidationError.NullParameter( nameof(validationParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); if (validationParameters.ValidAlgorithms != null && validationParameters.ValidAlgorithms.Count > 0 && @@ -59,7 +61,7 @@ internal static ValidationResult ValidateAlgorithm( LogHelper.MarkAsNonPII(algorithm)), ValidationFailureType.AlgorithmValidationFailed, typeof(SecurityTokenInvalidAlgorithmException), - new StackFrame(true), + ValidationError.GetCurrentStackFrame(), algorithm); return algorithm; diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Audience.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Audience.cs index 8b0903d3dc..3c11cf948d 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Audience.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Audience.cs @@ -35,14 +35,14 @@ public static partial class Validators /// The audiences found in the . /// The being validated. /// The to be used for validating the token. - /// - /// If 'validationParameters' is null. - /// If 'audiences' is null and is true. - /// If is null or whitespace and is null. - /// If none of the 'audiences' matched either or one of . + /// The that contains call information. /// An EXACT match is required. -#pragma warning disable CA1801 // TODO: remove pragma disable once callContext is used for logging - internal static ValidationResult ValidateAudience(IList tokenAudiences, SecurityToken? securityToken, ValidationParameters validationParameters, CallContext callContext) + internal static ValidationResult ValidateAudience( + IList tokenAudiences, +#pragma warning disable CA1801 + SecurityToken? securityToken, + ValidationParameters validationParameters, + CallContext callContext) #pragma warning restore CA1801 { if (validationParameters == null) diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Issuer.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Issuer.cs index 3bae752f35..4772b31fc4 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Issuer.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Issuer.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.IdentityModel.Logging; @@ -9,16 +8,6 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { - // TODO how do we extend this? - internal enum IssuerValidationSource - { - NotValidated = 0, - IssuerMatchedConfiguration, - IssuerMatchedValidationParameters - } - - internal record struct ValidatedIssuer(string Issuer, IssuerValidationSource ValidationSource); - /// /// Definition for delegate that will validate the issuer value in a token. /// @@ -37,7 +26,7 @@ internal delegate Task> IssuerValidationDelega CancellationToken cancellationToken); /// - /// IssuerValidation + /// Partial class for Issuer Validation. /// public static partial class Validators { @@ -66,19 +55,19 @@ internal static async Task> ValidateIssuerAsyn new MessageDetail(LogMessages.IDX10211), ValidationFailureType.IssuerValidationFailed, typeof(SecurityTokenInvalidIssuerException), - new StackFrame(true), + ValidationError.GetCurrentStackFrame(), issuer); } if (validationParameters == null) return ValidationError.NullParameter( nameof(validationParameters), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); if (securityToken == null) return ValidationError.NullParameter( nameof(securityToken), - new StackFrame(true)); + ValidationError.GetCurrentStackFrame()); BaseConfiguration? configuration = null; if (validationParameters.ConfigurationManager != null) @@ -90,7 +79,7 @@ internal static async Task> ValidateIssuerAsyn new MessageDetail(LogMessages.IDX10211), ValidationFailureType.IssuerValidationFailed, typeof(SecurityTokenInvalidIssuerException), - new StackFrame(true), + ValidationError.GetCurrentStackFrame(), issuer); if (configuration != null) @@ -123,13 +112,7 @@ internal static async Task> ValidateIssuerAsyn } if (string.Equals(validationParameters.ValidIssuers[i], issuer)) - { - // TODO: Add to CallContext - //if (LogHelper.IsEnabled(EventLogLevel.Informational)) - // LogHelper.LogInformation(LogMessages.IDX10236, LogHelper.MarkAsNonPII(issuer)); - return new ValidatedIssuer(issuer!, IssuerValidationSource.IssuerMatchedValidationParameters); - } } } @@ -141,7 +124,7 @@ internal static async Task> ValidateIssuerAsyn LogHelper.MarkAsNonPII(configuration?.Issuer)), ValidationFailureType.IssuerValidationFailed, typeof(SecurityTokenInvalidIssuerException), - new StackFrame(true), + ValidationError.GetCurrentStackFrame(), issuer); } } diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs index 6e4ef95132..1c0cfec536 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.IssuerSigningKey.cs @@ -8,8 +8,6 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { - internal record struct ValidatedSigningKeyLifetime(DateTime? ValidFrom, DateTime? ValidTo, DateTime? ValidationTime); - /// /// Definition for delegate that will validate the that signed a . /// @@ -28,9 +26,8 @@ internal delegate ValidationResult IssuerSigningKey CallContext callContext); /// - /// SigningKeyValidation + /// Partial class for Issuer Signing Key Validation. /// - public static partial class Validators { /// @@ -40,10 +37,7 @@ public static partial class Validators /// The being validated. /// The to be used for validating the token. /// The to be used for validation. - /// The to be used for logging. - /// if 'securityKey' is null and ValidateIssuerSigningKey is true. - /// if 'securityToken' is null and ValidateIssuerSigningKey is true. - /// if 'validationParameters' is null. + /// The that contains call information. internal static ValidationResult ValidateIssuerSigningKey( SecurityKey securityKey, SecurityToken securityToken, @@ -51,7 +45,7 @@ internal static ValidationResult ValidateIssuerSign #pragma warning disable CA1801 // Review unused parameters BaseConfiguration? configuration, #pragma warning restore CA1801 // Review unused parameters - CallContext? callContext) + CallContext callContext) { if (validationParameters == null) return IssuerSigningKeyValidationError.NullParameter( @@ -79,12 +73,12 @@ internal static ValidationResult ValidateIssuerSign /// /// The that signed the . /// The to be used for validating the token. - /// + /// The that contains call information. #pragma warning disable CA1801 // Review unused parameters internal static ValidationResult ValidateIssuerSigningKeyLifeTime( SecurityKey securityKey, ValidationParameters validationParameters, - CallContext? callContext) + CallContext callContext) #pragma warning restore CA1801 // Review unused parameters { DateTime utcNow = validationParameters.TimeProvider.GetUtcNow().UtcDateTime; diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Lifetime.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Lifetime.cs index 6f7262e40f..7aa37577b3 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Lifetime.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.Lifetime.cs @@ -7,8 +7,6 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { - internal record struct ValidatedLifetime(DateTime? NotBefore, DateTime? Expires); - /// /// Definition for delegate that will validate the lifetime of a . /// @@ -16,7 +14,7 @@ internal record struct ValidatedLifetime(DateTime? NotBefore, DateTime? Expires) /// The 'expiration' time found in the . /// The that is being validated. /// The to be used for validating the token. - /// + /// The that contains call information. /// A that contains the results of validating the issuer. /// This delegate is not expected to throw. internal delegate ValidationResult LifetimeValidationDelegate( @@ -27,7 +25,7 @@ internal delegate ValidationResult LifetimeValidationDelegate CallContext callContext); /// - /// IssuerValidation + /// Partial class for Lifetime Validation. /// public static partial class Validators { @@ -38,15 +36,10 @@ public static partial class Validators /// The 'expiration' time found in the . /// The being validated. /// The to be used for validating the token. - /// + /// The that contains call information. /// A indicating whether validation was successful, and providing a if it was not. - /// If 'validationParameters' is null. - /// If 'expires.HasValue' is false. - /// If 'notBefore' is > 'expires'. - /// If 'notBefore' is > DateTime.UtcNow. - /// If 'expires' is < DateTime.UtcNow. /// All time comparisons apply . -#pragma warning disable CA1801 // TODO: remove pragma disable once callContext is used for logging +#pragma warning disable CA1801 internal static ValidationResult ValidateLifetime( DateTime? notBefore, DateTime? expires, diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs index 3e8de4ffd9..f25292e5cb 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenReplay.cs @@ -3,6 +3,7 @@ using System; +#nullable enable namespace Microsoft.IdentityModel.Tokens { /// @@ -11,7 +12,7 @@ namespace Microsoft.IdentityModel.Tokens /// When does the expire.. /// The security token that is being validated. /// The to be used for validating the token. - /// + /// The that contains call information. /// A that contains the results of validating the token. /// This delegate is not expected to throw. internal delegate ValidationResult TokenReplayValidationDelegate( @@ -31,14 +32,13 @@ public static partial class Validators /// When does the security token expire. /// The being validated. /// The to be used for validating the token. - /// - /// If 'securityToken' is null or whitespace. - /// If 'validationParameters' is null or whitespace. - /// If is not null and expirationTime.HasValue is false. When a TokenReplayCache is set, tokens require an expiration time. - /// If the 'securityToken' is found in the cache. - /// If the 'securityToken' could not be added to the . + /// The that contains call information. #pragma warning disable CA1801 // Review unused parameters - internal static ValidationResult ValidateTokenReplay(DateTime? expirationTime, string securityToken, ValidationParameters validationParameters, CallContext callContext) + internal static ValidationResult ValidateTokenReplay( + DateTime? expirationTime, + string securityToken, + ValidationParameters validationParameters, + CallContext callContext) #pragma warning restore CA1801 // Review unused parameters { if (string.IsNullOrWhiteSpace(securityToken)) @@ -92,3 +92,4 @@ public static partial class Validators } } } +#nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs index a95a60b363..2ccce42550 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Validators.TokenType.cs @@ -8,14 +8,13 @@ #nullable enable namespace Microsoft.IdentityModel.Tokens { - internal record struct ValidatedTokenType(string Type, int ValidTypeCount); /// /// Definition for delegate that will validate the token type of a token. /// /// The token type or null if it couldn't be resolved (e.g from the 'typ' header for a JWT). /// The that is being validated. /// required for validation. - /// + /// The that contains call information. /// A that contains the results of validating the token type. /// An EXACT match is required. (case sensitive) is used for comparing against . internal delegate ValidationResult TokenTypeValidationDelegate( @@ -24,6 +23,9 @@ internal delegate ValidationResult TokenTypeValidationDelega ValidationParameters validationParameters, CallContext callContext); + /// + /// Partial class for Token Type Validation. + /// public static partial class Validators { /// @@ -32,16 +34,16 @@ public static partial class Validators /// The token type or null if it couldn't be resolved (e.g from the 'typ' header for a JWT). /// The that is being validated. /// required for validation. - /// + /// The that contains call information. /// A that contains the results of validating the token type. /// An EXACT match is required. (case sensitive) is used for comparing against . -#pragma warning disable CA1801 // TODO: remove pragma disable once callContext is used for logging +#pragma warning disable CA1801 internal static ValidationResult ValidateTokenType( string? type, SecurityToken? securityToken, ValidationParameters validationParameters, CallContext callContext) -#pragma warning restore CA1801 // TODO: remove pragma disable once callContext is used for logging +#pragma warning restore CA1801 { if (securityToken == null) return TokenTypeValidationError.NullParameter( diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs index b26524130c..b6872c70e9 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Algorithm.cs @@ -103,13 +103,14 @@ static TokenValidationParameters CreateTokenValidationParameters( static ValidationParameters CreateValidationParameters( SecurityKey? signingKey = null, List? validAlgorithms = null) { - ValidationParameters validationParameters = new ValidationParameters(); + ValidationParameters validationParameters = new ValidationParameters + { + ValidAlgorithms = validAlgorithms ?? [] + }; if (signingKey is not null) validationParameters.IssuerSigningKeys.Add(signingKey); - validationParameters.ValidAlgorithms = validAlgorithms; - // Skip all validations except signature and algorithm validationParameters.AudienceValidator = SkipValidationDelegates.SkipAudienceValidation; validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; diff --git a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs index f3152b4d34..dc7f78345b 100644 --- a/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs +++ b/test/Microsoft.IdentityModel.TestUtils/IdentityComparer.cs @@ -1331,11 +1331,11 @@ internal static bool AreValidatedIssuersEqual(ValidatedIssuer validatedIssuer1, "validatedIssuer2.Issuer", localContext); - AreIntsEqual( - (int)validatedIssuer1.ValidationSource, - (int)validatedIssuer2.ValidationSource, - "validatedIssuer1.ValidationSource", - "validatedIssuer2.ValidationSource", + AreStringsEqual( + validatedIssuer1.ValidationSource.Name, + validatedIssuer2.ValidationSource.Name, + "validatedIssuer1.ValidationSource.Name", + "validatedIssuer2.ValidationSource.Name", localContext); return context.Merge(localContext); diff --git a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs index 7571d4f8aa..6989427b5c 100644 --- a/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs +++ b/test/Microsoft.IdentityModel.TestUtils/TokenValidationExtensibility/CustomValidationErrors.cs @@ -29,7 +29,7 @@ public CustomIssuerValidationError( { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidIssuerException)) { @@ -39,7 +39,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -76,7 +76,7 @@ public CustomAudienceValidationError( { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidAudienceException)) { @@ -86,7 +86,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -126,7 +126,7 @@ public CustomLifetimeValidationError( { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidLifetimeException)) { @@ -136,7 +136,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -176,7 +176,7 @@ public CustomIssuerSigningKeyValidationError( { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidSigningKeyException)) { @@ -184,7 +184,7 @@ internal override Exception GetException() exception.SetValidationError(this); return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -221,7 +221,7 @@ public CustomTokenTypeValidationError( : base(messageDetail, validationFailureType, exceptionType, stackFrame, invalidTokenType, innerException) { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidTypeException)) { @@ -229,7 +229,7 @@ internal override Exception GetException() exception.SetValidationError(this); return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -266,7 +266,7 @@ public CustomSignatureValidationError( base(messageDetail, validationFailureType, exceptionType, stackFrame, innerValidationError, innerException) { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidSignatureException)) { @@ -274,7 +274,7 @@ internal override Exception GetException() exception.SetValidationError(this); return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -312,7 +312,7 @@ public CustomAlgorithmValidationError( : base(messageDetail, validationFailureType, exceptionType, stackFrame, algorithm, innerException) { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenInvalidAlgorithmException)) { @@ -320,7 +320,7 @@ internal override Exception GetException() exception.SetValidationError(this); return exception; } - return base.GetException(); + return base.CreateException(); } } @@ -359,7 +359,7 @@ public CustomTokenReplayValidationError( { } - internal override Exception GetException() + protected override Exception CreateException() { if (ExceptionType == typeof(CustomSecurityTokenReplayDetectedException)) { @@ -369,7 +369,7 @@ internal override Exception GetException() return exception; } - return base.GetException(); + return base.CreateException(); } } diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs index 13581b3d01..17fdda1df1 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2SecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs @@ -143,12 +143,11 @@ public static TheoryData ValidateTokenAsy static ValidationParameters CreateValidationParameters( SecurityKey? signingKey = null, List? validAlgorithms = null, bool tryAllKeys = false) { - ValidationParameters validationParameters = new ValidationParameters(); - - if (signingKey is not null) - validationParameters.IssuerSigningKeys.Add(signingKey); - - validationParameters.ValidAlgorithms = validAlgorithms; + ValidationParameters validationParameters = new ValidationParameters() + { + ValidAlgorithms = validAlgorithms ?? [], + IssuerSigningKeys = signingKey is not null ? [signingKey] : [], + }; validationParameters.AudienceValidator = SkipValidationDelegates.SkipAudienceValidation; validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation; diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs index 5d1a77c4c6..258cda2eb4 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/SamlSecurityTokenHandlerTests.ValidateTokenAsyncTests.Algorithm.cs @@ -142,12 +142,11 @@ public static TheoryData ValidateTokenAsy static ValidationParameters CreateValidationParameters( SecurityKey? signingKey = null, List? validAlgorithms = null, bool tryAllKeys = false) { - ValidationParameters validationParameters = new ValidationParameters(); - - if (signingKey is not null) - validationParameters.IssuerSigningKeys.Add(signingKey); - - validationParameters.ValidAlgorithms = validAlgorithms; + ValidationParameters validationParameters = new ValidationParameters() + { + ValidAlgorithms = validAlgorithms ?? [], + IssuerSigningKeys = signingKey is not null ? [signingKey] : [], + }; validationParameters.AudienceValidator = SkipValidationDelegates.SkipAudienceValidation; validationParameters.IssuerSigningKeyValidator = SkipValidationDelegates.SkipIssuerSigningKeyValidation;