Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logging to the new validation model #3054

Merged
merged 7 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<SystemMemoryVersion>4.5.5</SystemMemoryVersion>
<SystemSecurityCryptographyCngVersion>4.5.0</SystemSecurityCryptographyCngVersion>
<SystemTextJson>8.0.5</SystemTextJson>
<MicrosoftExtensionsLoggingAbstractionsVersion>8.0.2</MicrosoftExtensionsLoggingAbstractionsVersion>
iNinja marked this conversation as resolved.
Show resolved Hide resolved
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<TResult>.Error.get -> Microsoft.IdentityModel.Tokens.ValidationError
Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.IsValid.get -> bool
Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.Log(Microsoft.Extensions.Logging.ILogger logger) -> void
Microsoft.IdentityModel.Tokens.ValidationResult<TResult>.Result.get -> TResult
override Microsoft.IdentityModel.Tokens.AlgorithmValidationError.GetException() -> System.Exception
override Microsoft.IdentityModel.Tokens.IssuerSigningKeyValidationError.GetException() -> System.Exception
Expand All @@ -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<string> 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
Expand Down
14 changes: 14 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/LoggingEventId.cs
Original file line number Diff line number Diff line change
@@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,9 @@
<AdditionalFiles Include="PublicAPI/$(TargetFramework)/InternalAPI.Shipped.txt" />
<AdditionalFiles Include="PublicAPI/$(TargetFramework)/InternalAPI.Unshipped.txt" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsVersion)" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -261,6 +267,27 @@ internal static StackFrame GetCurrentStackFrame(

// ConcurrentDictionary is thread-safe and only locks when adding a new item.
private static ConcurrentDictionary<string, StackFrame> CachedStackFrames { get; } = new();

private static class Logger
{
private static readonly Action<ILogger, string, string, Exception?> s_tokenValidationFailed =
LoggerMessage.Define<string, string>(
LogLevel.Information,
LoggingEventId.TokenValidationFailed,
"[MsIdentityModel] The token validation was unsuccessful due to: {ValidationFailureType} " +
"Error message provided: {ValidationErrorMessage}");

/// <summary>
/// Logger for handling failures in token validation.
/// </summary>
/// <param name="logger">ILogger.</param>
/// <param name="validationFailureType">The cause of the failure.</param>
/// <param name="messageDetail">The message provided as part of the failure.</param>
public static void TokenValidationFailed(
ILogger logger,
string validationFailureType,
string messageDetail) => s_tokenValidationFailed(logger, validationFailureType, messageDetail, null);
}
}
}
#nullable restore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Security.Claims;
using System.Threading;
using Microsoft.Extensions.Logging;

#nullable enable
namespace Microsoft.IdentityModel.Tokens
Expand Down Expand Up @@ -34,11 +35,17 @@ internal ValidatedToken(
/// <summary>
/// Logs the validation result.
/// </summary>
#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; }
Expand Down Expand Up @@ -168,6 +175,69 @@ private object ClaimsIdentitySyncObj
}
}
#endregion

#region Logging
private static class Logger
{
private static readonly Action<ILogger, string, string, Exception?> s_tokenValidationFailed =
LoggerMessage.Define<string, string>(
LogLevel.Information,
LoggingEventId.TokenValidationFailed,
"[MsIdentityModel] The token validation was unsuccessful due to: {ValidationFailureType} " +
"Error message provided: {ValidationErrorMessage}");

/// <summary>
/// Logger for handling failures in token validation.
/// </summary>
/// <param name="logger">ILogger.</param>
/// <param name="validationFailureType">The cause of the failure.</param>
/// <param name="messageDetail">The message provided as part of the failure.</param>
public static void TokenValidationFailed(
ILogger logger,
ValidationFailureType validationFailureType,
MessageDetail messageDetail) => s_tokenValidationFailed(logger, validationFailureType.Name, messageDetail.Message, null);

private static readonly Action<ILogger, string, ValidatedLifetime?, ValidatedIssuer?, ValidatedTokenType?, string, bool, Exception?> s_tokenValidationSucceeded =
LoggerMessage.Define<string, ValidatedLifetime?, ValidatedIssuer?, ValidatedTokenType?, string, bool>(
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}");

/// <summary>
/// Logger for handling successful token validation.
/// </summary>
/// <param name="logger">The instance to be used to log.</param>
/// <param name="validatedAudience">The audience that was validated.</param>
/// <param name="validatedLifetime">The lifetime that was validated.</param>
/// <param name="validatedIssuer">The issuer that was validated.</param>
/// <param name="validatedTokenType">The token type that was validated.</param>
/// <param name="validatedSigningKeyId">The signing key id that was validated.</param>
/// <param name="actorWasValidated">Whether the actor was validated.</param>
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);

iNinja marked this conversation as resolved.
Show resolved Hide resolved
}
#endregion
}
}
#nullable disable
Loading