Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ internal async ValueTask<TokenValidationResult> ValidateTokenPayloadAsync(
}

string tokenType = Validators.ValidateTokenType(jsonWebToken.Typ, jsonWebToken, validationParameters);
return new TokenValidationResult(jsonWebToken, this, validationParameters.Clone(), issuer, null)
return new TokenValidationResult(jsonWebToken, this, validationParameters.Clone(), issuer)
{
IsValid = true,
TokenType = tokenType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

using System;
using System.Text;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Experimental;
using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;

namespace Microsoft.IdentityModel.JsonWebTokens
{
Expand Down Expand Up @@ -127,5 +129,44 @@ internal static ValidationResult<string, ValidationError> DecryptJwtToken(
ex);
}
}

private static ValidationError GetDecryptionError(
JwtTokenDecryptionParameters decryptionParameters,
bool algorithmNotSupportedByCryptoProvider,
StringBuilder exceptionStrings,
StringBuilder keysAttempted,
#pragma warning disable CA1801 // Review unused parameters
CallContext callContext)
#pragma warning restore CA1801 // Review unused parameters
{
if (keysAttempted is not null)
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10603,
LogHelper.MarkAsNonPII(keysAttempted.ToString()),
exceptionStrings?.ToString() ?? string.Empty,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
else if (algorithmNotSupportedByCryptoProvider)
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10619,
LogHelper.MarkAsNonPII(decryptionParameters.Alg),
LogHelper.MarkAsNonPII(decryptionParameters.Enc)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
else
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10609,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
}

}
}
82 changes: 33 additions & 49 deletions src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Microsoft.IdentityModel.Abstractions;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Experimental;
using Microsoft.IdentityModel.Tokens.Json;

using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;
Expand Down Expand Up @@ -284,7 +283,10 @@ internal static string DecryptJwtToken(
if (!cryptoProviderFactory.IsSupportedAlgorithm(decryptionParameters.Enc, key))
{
if (LogHelper.IsEnabled(EventLogLevel.Warning))
LogHelper.LogWarning(TokenLogMessages.IDX10611, LogHelper.MarkAsNonPII(decryptionParameters.Enc), LogHelper.MarkAsNonPII(key.KeyId));
LogHelper.LogWarning(
TokenLogMessages.IDX10611,
LogHelper.MarkAsNonPII(decryptionParameters.Enc),
LogHelper.MarkAsNonPII(key.KeyId));

algorithmNotSupportedByCryptoProvider = true;
continue;
Expand Down Expand Up @@ -313,17 +315,7 @@ internal static string DecryptJwtToken(
(keysAttempted ??= new StringBuilder()).AppendLine(key.KeyId);
}

if (!decryptionSucceeded)
{
ValidationError validationError = GetDecryptionError(
decryptionParameters,
algorithmNotSupportedByCryptoProvider,
exceptionStrings,
keysAttempted,
null);

throw LogHelper.LogExceptionMessage(validationError.GetException());
}
ValidateDecryption(decryptionParameters, decryptionSucceeded, algorithmNotSupportedByCryptoProvider, exceptionStrings, keysAttempted);

try
{
Expand All @@ -334,46 +326,38 @@ internal static string DecryptJwtToken(
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenDecompressionFailedException(GetIDX10679LogMessage(zipAlgorithm), ex));
throw LogHelper.LogExceptionMessage(
new SecurityTokenDecompressionFailedException(
GetIDX10679LogMessage(zipAlgorithm),
ex));
}
}

private static ValidationError GetDecryptionError(
JwtTokenDecryptionParameters decryptionParameters,
bool algorithmNotSupportedByCryptoProvider,
StringBuilder exceptionStrings,
StringBuilder keysAttempted,
#pragma warning disable CA1801 // Review unused parameters
CallContext callContext)
#pragma warning restore CA1801 // Review unused parameters
private static void ValidateDecryption(JwtTokenDecryptionParameters decryptionParameters, bool decryptionSucceeded, bool algorithmNotSupportedByCryptoProvider, StringBuilder exceptionStrings, StringBuilder keysAttempted)
{
if (keysAttempted is not null)
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10603,
LogHelper.MarkAsNonPII(keysAttempted.ToString()),
exceptionStrings?.ToString() ?? string.Empty,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
else if (algorithmNotSupportedByCryptoProvider)
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10619,
LogHelper.MarkAsNonPII(decryptionParameters.Alg),
LogHelper.MarkAsNonPII(decryptionParameters.Enc)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
else
return new ValidationError(
new MessageDetail(
TokenLogMessages.IDX10609,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecryptionFailedException),
ValidationError.GetCurrentStackFrame());
if (!decryptionSucceeded && keysAttempted is not null)
throw LogHelper.LogExceptionMessage(
new SecurityTokenDecryptionFailedException(
LogHelper.FormatInvariant(
TokenLogMessages.IDX10603,
LogHelper.MarkAsNonPII(keysAttempted.ToString()),
(object)exceptionStrings ?? string.Empty,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken))));

if (!decryptionSucceeded && algorithmNotSupportedByCryptoProvider)
throw LogHelper.LogExceptionMessage(
new SecurityTokenDecryptionFailedException(
LogHelper.FormatInvariant(
TokenLogMessages.IDX10619,
LogHelper.MarkAsNonPII(decryptionParameters.Alg),
LogHelper.MarkAsNonPII(decryptionParameters.Enc))));

if (!decryptionSucceeded)
throw LogHelper.LogExceptionMessage(
new SecurityTokenDecryptionFailedException(
LogHelper.FormatInvariant(
TokenLogMessages.IDX10609,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken))));
}

private static byte[] DecryptToken(CryptoProviderFactory cryptoProviderFactory, SecurityKey key, string encAlg, byte[] ciphertext, byte[] headerAscii, byte[] initializationVector, byte[] authenticationTag)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens.Experimental;
using Microsoft.IdentityModel.Xml;

namespace Microsoft.IdentityModel.Tokens.Saml
{
/// <summary>
/// A class which contains useful methods for processing saml tokens.
/// </summary>
internal partial class SamlTokenUtilities
{
/// <summary>
/// Returns a <see cref="SecurityKey"/> to use when validating the signature of a token.
/// </summary>
/// <param name="tokenKeyInfo">The <see cref="KeyInfo"/> field of the token being validated</param>
/// <param name="validationParameters">The <see cref="ValidationParameters"/> to be used for validating the token.</param>
/// <returns>Returns a <see cref="SecurityKey"/> to use for signature validation.</returns>
/// <remarks>If key fails to resolve, then null is returned</remarks>
internal static SecurityKey ResolveTokenSigningKey(KeyInfo tokenKeyInfo, ValidationParameters validationParameters)
{
if (tokenKeyInfo is null || validationParameters.IssuerSigningKeys is null)
return null;

for (int i = 0; i < validationParameters.IssuerSigningKeys.Count; i++)
{
if (tokenKeyInfo.MatchesKey(validationParameters.IssuerSigningKeys[i]))
return validationParameters.IssuerSigningKeys[i];
}

return null;
}

/// <summary>
/// Fetches current configuration from the ConfigurationManager of <paramref name="validationParameters"/>
/// and populates ValidIssuers and IssuerSigningKeys.
/// </summary>
/// <param name="validationParameters"> the token validation parameters to update.</param>
/// <param name="cancellationToken"></param>
/// <returns> New ValidationParameters with ValidIssuers and IssuerSigningKeys updated.</returns>
internal static async Task<ValidationParameters> PopulateValidationParametersWithCurrentConfigurationAsync(
ValidationParameters validationParameters,
CancellationToken cancellationToken)
{
if (validationParameters.ConfigurationManager == null)
{
return validationParameters;
}

var currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(cancellationToken).ConfigureAwait(false);
var validationParametersCloned = validationParameters.Clone();

validationParametersCloned.ValidIssuers.Add(currentConfiguration.Issuer);

foreach (SecurityKey key in currentConfiguration.SigningKeys)
{
validationParametersCloned.IssuerSigningKeys.Add(key);
}

return validationParametersCloned;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
using System.Threading.Tasks;
using Microsoft.IdentityModel.Logging;
using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;
using Microsoft.IdentityModel.Tokens.Experimental;

namespace Microsoft.IdentityModel.Tokens.Saml
{
/// <summary>
/// A class which contains useful methods for processing saml tokens.
/// </summary>
internal class SamlTokenUtilities
internal partial class SamlTokenUtilities
{
/// <summary>
/// Returns a <see cref="SecurityKey"/> to use when validating the signature of a token.
Expand Down Expand Up @@ -48,29 +47,6 @@ internal static SecurityKey ResolveTokenSigningKey(KeyInfo tokenKeyInfo, TokenVa
return null;
}

/// <summary>
/// Returns a <see cref="SecurityKey"/> to use when validating the signature of a token.
/// </summary>
/// <param name="tokenKeyInfo">The <see cref="KeyInfo"/> field of the token being validated</param>
/// <param name="validationParameters">The <see cref="ValidationParameters"/> to be used for validating the token.</param>
/// <returns>Returns a <see cref="SecurityKey"/> to use for signature validation.</returns>
/// <remarks>If key fails to resolve, then null is returned</remarks>
internal static SecurityKey ResolveTokenSigningKey(KeyInfo tokenKeyInfo, ValidationParameters validationParameters)
{
if (tokenKeyInfo is null || validationParameters.IssuerSigningKeys is null)
return null;

for (int i = 0; i < validationParameters.IssuerSigningKeys.Count; i++)
{
if (tokenKeyInfo.MatchesKey(validationParameters.IssuerSigningKeys[i]))
return validationParameters.IssuerSigningKeys[i];
}

return null;
}



/// <summary>
/// Creates <see cref="Claim"/>'s from <paramref name="claimsCollection"/>.
/// </summary>
Expand Down Expand Up @@ -176,36 +152,6 @@ internal static async Task<TokenValidationParameters> PopulateValidationParamete
validationParametersCloned.ValidIssuers = (validationParametersCloned.ValidIssuers == null ? issuers : validationParametersCloned.ValidIssuers.Concat(issuers));
validationParametersCloned.IssuerSigningKeys = (validationParametersCloned.IssuerSigningKeys == null ? currentConfiguration.SigningKeys : validationParametersCloned.IssuerSigningKeys.Concat(currentConfiguration.SigningKeys));
return validationParametersCloned;

}

/// <summary>
/// Fetches current configuration from the ConfigurationManager of <paramref name="validationParameters"/>
/// and populates ValidIssuers and IssuerSigningKeys.
/// </summary>
/// <param name="validationParameters"> the token validation parameters to update.</param>
/// <param name="cancellationToken"></param>
/// <returns> New ValidationParameters with ValidIssuers and IssuerSigningKeys updated.</returns>
internal static async Task<ValidationParameters> PopulateValidationParametersWithCurrentConfigurationAsync(
ValidationParameters validationParameters,
CancellationToken cancellationToken)
{
if (validationParameters.ConfigurationManager == null)
{
return validationParameters;
}

var currentConfiguration = await validationParameters.ConfigurationManager.GetBaseConfigurationAsync(cancellationToken).ConfigureAwait(false);
var validationParametersCloned = validationParameters.Clone();

validationParametersCloned.ValidIssuers.Add(currentConfiguration.Issuer);

foreach (SecurityKey key in currentConfiguration.SigningKeys)
{
validationParametersCloned.IssuerSigningKeys.Add(key);
}

return validationParametersCloned;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using Microsoft.IdentityModel.Tokens.Experimental;

#if !NET8_0_OR_GREATER
using System.Text;
#endif

namespace Microsoft.IdentityModel.Tokens
{
/// <summary>
/// Represents a security token exception.
/// </summary>
public partial class SecurityTokenException : Exception
{
[NonSerialized]
private string _stackTrace;

[NonSerialized]
private ValidationError _validationError;

/// <summary>
/// Sets the <see cref="ValidationError"/> that caused the exception.
/// </summary>
/// <param name="validationError"></param>
internal void SetValidationError(ValidationError validationError)
{
_validationError = validationError;
}

/// <summary>
/// Gets the stack trace that is captured when the exception is created.
/// </summary>
public override string StackTrace
{
get
{
if (_stackTrace == null)
{
if (_validationError == null)
return base.StackTrace;
#if NET8_0_OR_GREATER
_stackTrace = new StackTrace(_validationError.StackFrames).ToString();
#else
StringBuilder sb = new();
foreach (StackFrame frame in _validationError.StackFrames)
{
sb.Append(frame.ToString());
sb.Append(Environment.NewLine);
}

_stackTrace = sb.ToString();
#endif
}

return _stackTrace;
}
}
}
}
Loading
Loading