diff --git a/build/dependencies.props b/build/dependencies.props index 3acadea8e2..e7f8afdb8c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,6 +5,7 @@ 3.3.4 8.0.1 4.5.0 + 8.0.2 1.0.0 2.0.3 13.0.3 diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index 5a8febaf08..c05846e38a 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -27,6 +27,7 @@ Microsoft.IdentityModel.Tokens.IssuerValidationSource.IssuerMatchedValidationPar 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? +Microsoft.IdentityModel.Tokens.LoggingEventId Microsoft.IdentityModel.Tokens.SecurityTokenInvalidOperationException Microsoft.IdentityModel.Tokens.SecurityTokenInvalidOperationException.SecurityTokenInvalidOperationException() -> void Microsoft.IdentityModel.Tokens.SecurityTokenInvalidOperationException.SecurityTokenInvalidOperationException(string message) -> void @@ -43,13 +44,16 @@ Microsoft.IdentityModel.Tokens.TokenTypeValidationError.InvalidTokenType.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationError.TokenTypeValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, Microsoft.IdentityModel.Tokens.ValidationFailureType validationFailureType, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidTokenType, System.Exception innerException = null) -> void 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.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 Microsoft.IdentityModel.Tokens.ValidationError.ValidationError(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.ValidationParameters.TokenTypeValidator.get -> Microsoft.IdentityModel.Tokens.TokenTypeValidationDelegate Microsoft.IdentityModel.Tokens.ValidationParameters.TokenTypeValidator.set -> void Microsoft.IdentityModel.Tokens.ValidationResult.Error.get -> Microsoft.IdentityModel.Tokens.ValidationError Microsoft.IdentityModel.Tokens.ValidationResult.IsValid.get -> bool +Microsoft.IdentityModel.Tokens.ValidationResult.Log(Microsoft.Extensions.Logging.ILogger logger) -> void Microsoft.IdentityModel.Tokens.ValidationResult.Result.get -> TResult override Microsoft.IdentityModel.Tokens.AlgorithmValidationError.GetException() -> System.Exception override Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.GetException() -> System.Exception @@ -62,6 +66,8 @@ static Microsoft.IdentityModel.Tokens.TokenReplayValidationError.NullParameter(s static Microsoft.IdentityModel.Tokens.TokenTypeValidationError.NullParameter(string parameterName, System.Diagnostics.StackFrame stackFrame) -> Microsoft.IdentityModel.Tokens.TokenTypeValidationError static Microsoft.IdentityModel.Tokens.Utility.SerializeAsSingleCommaDelimitedString(System.Collections.Generic.IList strings) -> string static Microsoft.IdentityModel.Tokens.ValidationError.GetCurrentStackFrame(string filePath = "", int lineNumber = 0, int skipFrames = 1) -> System.Diagnostics.StackFrame +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.Tokens.ValidationFailureType.AlgorithmValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.AudienceValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.IssuerSigningKeyValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType diff --git a/src/Microsoft.IdentityModel.Tokens/LoggingEventId.cs b/src/Microsoft.IdentityModel.Tokens/LoggingEventId.cs new file mode 100644 index 0000000000..aa682a3dd5 --- /dev/null +++ b/src/Microsoft.IdentityModel.Tokens/LoggingEventId.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Extensions.Logging; + +namespace Microsoft.IdentityModel.Tokens +{ + internal static class LoggingEventId + { + // TokenValidation EventIds 100+ + internal static readonly EventId TokenValidationFailed = new(100, "TokenValidationFailed"); + internal static readonly EventId TokenValidationSucceeded = new(101, "TokenValidationSucceeded"); + } +} diff --git a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj index 459a772334..2e3b454bbf 100644 --- a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj +++ b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj @@ -72,5 +72,9 @@ + + + + diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs index fb8481d1ac..b4e0a6714f 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/Details/ValidationError.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Logging; #nullable enable @@ -183,6 +184,11 @@ internal Exception GetException(Type exceptionType, Exception? innerException) return exception; } + internal void Log(ILogger logger) + { + Logger.TokenValidationFailed(logger, FailureType.Name, MessageDetail.Message); + } + internal static ValidationError NullParameter(string parameterName, StackFrame stackFrame) => new( MessageDetail.NullParameter(parameterName), ValidationFailureType.NullArgument, @@ -261,6 +267,27 @@ internal static StackFrame GetCurrentStackFrame( // ConcurrentDictionary is thread-safe and only locks when adding a new item. private static ConcurrentDictionary CachedStackFrames { get; } = new(); + + private static class Logger + { + private static readonly Action s_tokenValidationFailed = + LoggerMessage.Define( + LogLevel.Information, + LoggingEventId.TokenValidationFailed, + "[MsIdentityModel] The token validation was unsuccessful due to: {ValidationFailureType} " + + "Error message provided: {ValidationErrorMessage}"); + + /// + /// Logger for handling failures in token validation. + /// + /// ILogger. + /// The cause of the failure. + /// The message provided as part of the failure. + public static void TokenValidationFailed( + ILogger logger, + string validationFailureType, + string messageDetail) => s_tokenValidationFailed(logger, validationFailureType, messageDetail, null); + } } } #nullable restore diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs index 3722fc4e8e..7eccd96c75 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Security.Claims; using System.Threading; +using Microsoft.Extensions.Logging; #nullable enable namespace Microsoft.IdentityModel.Tokens @@ -34,11 +35,17 @@ internal ValidatedToken( /// /// Logs the validation result. /// -#pragma warning disable CA1822 // Mark members as static - public void Log() -#pragma warning restore CA1822 // Mark members as static + public void Log(ILogger logger) { - // TODO - Do we need this, how will it work? + Logger.TokenValidationSucceeded( + logger, + ValidatedAudience ?? "none", + ValidatedLifetime, + ValidatedIssuer, + ValidatedTokenType, + ValidatedSigningKey?.KeyId ?? "none", + ActorValidationResult is not null + ); } public SecurityToken SecurityToken { get; private set; } @@ -168,6 +175,68 @@ private object ClaimsIdentitySyncObj } } #endregion + + #region Logging + private static class Logger + { + private static readonly Action s_tokenValidationFailed = + LoggerMessage.Define( + LogLevel.Information, + LoggingEventId.TokenValidationFailed, + "[MsIdentityModel] The token validation was unsuccessful due to: {ValidationFailureType} " + + "Error message provided: {ValidationErrorMessage}"); + + /// + /// Logger for handling failures in token validation. + /// + /// ILogger. + /// The cause of the failure. + /// The message provided as part of the failure. + public static void TokenValidationFailed( + ILogger logger, + ValidationFailureType validationFailureType, + MessageDetail messageDetail) => s_tokenValidationFailed(logger, validationFailureType.Name, messageDetail.Message, null); + + private static readonly Action s_tokenValidationSucceeded = + LoggerMessage.Define( + LogLevel.Debug, + LoggingEventId.TokenValidationSucceeded, + "[MsIdentityModel] The token validation was successful. " + + "Validated audience: {ValidatedAudience} " + + "Validated lifetime: {ValidatedLifetime} " + + "Validated issuer: {ValidatedIssuer} " + + "Validated token type: {ValidatedTokenType} " + + "Validated signing key id: {ValidatedSigningKeyId} " + + "Actor was validated: {ActorWasValidated}"); + + /// + /// Logger for handling successful token validation. + /// + /// The instance to be used to log. + /// The audience that was validated. + /// The lifetime that was validated. + /// The issuer that was validated. + /// The token type that was validated. + /// The signing key id that was validated. + /// Whether the actor was validated. + public static void TokenValidationSucceeded( + ILogger logger, + string validatedAudience, + ValidatedLifetime? validatedLifetime, + ValidatedIssuer? validatedIssuer, + ValidatedTokenType? validatedTokenType, + string validatedSigningKeyId, + bool actorWasValidated) => s_tokenValidationSucceeded( + logger, + validatedAudience, + validatedLifetime, + validatedIssuer, + validatedTokenType, + validatedSigningKeyId, + actorWasValidated, + null); + } + #endregion } } #nullable disable