From d3d4c0a9115ba2119a1b3b7dc9677c97d7899431 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 6 Dec 2024 16:47:21 +0000 Subject: [PATCH 1/6] Added Microsoft.Extensions.Logging.Abstractions to Microsoft.IdentityModel.Tokens to access ILogger --- .../Microsoft.IdentityModel.Tokens.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj index 459a772334..a40ddd8e99 100644 --- a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj +++ b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj @@ -72,5 +72,9 @@ + + + + From e81380d7ea28762f4a331c20c203646e15b5190f Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 6 Dec 2024 16:47:53 +0000 Subject: [PATCH 2/6] Added LoggingEventIds to store event ids used by the logging methods in M.IM.Tokens --- .../LoggingEventId.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Microsoft.IdentityModel.Tokens/LoggingEventId.cs 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"); + } +} From ed27c1165b48bf1ceb682899ec551fe1f3701adc Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Fri, 6 Dec 2024 16:48:02 +0000 Subject: [PATCH 3/6] Added logging to ValidationError and ValidatedToken to log the results obtained from ValidateTokenAsync after the fact. --- .../InternalAPI.Unshipped.txt | 6 ++ .../Results/Details/ValidationError.cs | 27 +++++++ .../Validation/Results/ValidatedToken.cs | 78 ++++++++++++++++++- 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt index c81cb4212e..3a0ba31f56 100644 --- a/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt +++ b/src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt @@ -25,6 +25,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 @@ -41,13 +42,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 @@ -60,6 +64,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.IssuerSigningKeyValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType static readonly Microsoft.IdentityModel.Tokens.ValidationFailureType.IssuerValidatorThrew -> Microsoft.IdentityModel.Tokens.ValidationFailureType 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..68ccaefbee 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,69 @@ 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 From 6d12711be3dae436037c9ecc2e3758b805a022e6 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Mon, 9 Dec 2024 17:03:45 +0000 Subject: [PATCH 4/6] Moved dependency version to dependencies.props --- build/dependencies.props | 1 + .../Microsoft.IdentityModel.Tokens.csproj | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3acadea8e2..2bbdbc29cb 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -11,6 +11,7 @@ 4.5.5 4.5.0 8.0.5 + 8.0.2 diff --git a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj index a40ddd8e99..2e3b454bbf 100644 --- a/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj +++ b/src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj @@ -74,7 +74,7 @@ - + From 7aae9ac21d47b971f80b9e936acc63c6758cf8e4 Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Mon, 9 Dec 2024 19:52:08 +0000 Subject: [PATCH 5/6] Update src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs Co-authored-by: Westin Musser <127992899+westin-m@users.noreply.github.com> --- .../Validation/Results/ValidatedToken.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs index 68ccaefbee..7eccd96c75 100644 --- a/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs +++ b/src/Microsoft.IdentityModel.Tokens/Validation/Results/ValidatedToken.cs @@ -235,7 +235,6 @@ public static void TokenValidationSucceeded( validatedSigningKeyId, actorWasValidated, null); - } #endregion } From d54870585e78cb3c652ac6e30906cd772e4225cc Mon Sep 17 00:00:00 2001 From: Ignacio Inglese Date: Mon, 9 Dec 2024 19:54:59 +0000 Subject: [PATCH 6/6] Sorted dependency versions based on PR feedback --- build/dependencies.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies.props b/build/dependencies.props index 2bbdbc29cb..e7f8afdb8c 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,13 +5,13 @@ 3.3.4 8.0.1 4.5.0 + 8.0.2 1.0.0 2.0.3 13.0.3 4.5.5 4.5.0 8.0.5 - 8.0.2