Skip to content

Commit

Permalink
Restore AOT compatibility for IdentityModel (#2773)
Browse files Browse the repository at this point in the history
* Enabled AOT compatibility checks at build time. Refactored ExceptionDetail to not rely on reflection.
* Added tests
  • Loading branch information
iNinja committed Aug 8, 2024
1 parent 15e26cf commit d2632a7
Show file tree
Hide file tree
Showing 26 changed files with 398 additions and 125 deletions.
4 changes: 4 additions & 0 deletions build/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,8 @@
</PackageReference>
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0'">
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ internal TokenDecryptionResult DecryptToken(
ValidationFailureType.TokenDecryptionFailed,
new ExceptionDetail(
new MessageDetail(TokenLogMessages.IDX10612),
typeof(SecurityTokenException),
ExceptionDetail.ExceptionType.SecurityToken,
new System.Diagnostics.StackFrame()));

var keysOrExceptionDetail = GetContentEncryptionKeys(jwtToken, validationParameters, configuration, callContext);
Expand All @@ -66,7 +66,7 @@ internal TokenDecryptionResult DecryptToken(
new MessageDetail(
TokenLogMessages.IDX10609,
LogHelper.MarkAsSecurityArtifact(jwtToken, JwtTokenUtilities.SafeLogJwtToken)),
typeof(SecurityTokenDecryptionFailedException),
ExceptionDetail.ExceptionType.SecurityTokenDecryptionFailed,
new System.Diagnostics.StackFrame()));

return JwtTokenUtilities.DecryptJwtToken(
Expand Down Expand Up @@ -202,7 +202,7 @@ internal TokenDecryptionResult DecryptToken(
keysAttempted?.ToString() ?? "",
exceptionStrings?.ToString() ?? "",
LogHelper.MarkAsSecurityArtifact(jwtToken, JwtTokenUtilities.SafeLogJwtToken)),
typeof(SecurityTokenKeyWrapException),
ExceptionDetail.ExceptionType.SecurityTokenKeyWrap,
new System.Diagnostics.StackFrame());
return (null, exceptionDetail);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal static TokenReadingResult ReadToken(
new MessageDetail(
TokenLogMessages.IDX10000,
LogHelper.MarkAsNonPII(nameof(token))),
typeof(ArgumentNullException),
ExceptionDetail.ExceptionType.ArgumentNull,
new System.Diagnostics.StackFrame()));
}

Expand All @@ -54,7 +54,7 @@ internal static TokenReadingResult ReadToken(
ValidationFailureType.TokenReadingFailed,
new ExceptionDetail(
new MessageDetail(LogMessages.IDX14107),
ex.GetType(),
ExceptionDetail.ExceptionType.SecurityTokenMalformed,
new System.Diagnostics.StackFrame(),
ex));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal static SignatureValidationResult ValidateSignature(
jwtToken.EncodedToken,
JwtTokenUtilities.SafeLogJwtToken)
),
typeof(SecurityTokenInvalidSignatureException),
ExceptionDetail.ExceptionType.SecurityTokenInvalidSignature,
new StackFrame()));

SecurityKey? key = null;
Expand Down Expand Up @@ -93,7 +93,7 @@ internal static SignatureValidationResult ValidateSignature(
ValidationFailureType.SignatureValidationFailed,
new ExceptionDetail(
new MessageDetail(TokenLogMessages.IDX10500),
typeof(SecurityTokenSignatureKeyNotFoundException),
ExceptionDetail.ExceptionType.SecurityTokenSignatureKeyNotFound,
new StackFrame()));
}

Expand Down Expand Up @@ -130,7 +130,7 @@ private static SignatureValidationResult ValidateSignatureUsingAllKeys(
ValidationFailureType.SignatureValidationFailed,
new ExceptionDetail(
new MessageDetail(TokenLogMessages.IDX10500),
typeof(SecurityTokenSignatureKeyNotFoundException),
ExceptionDetail.ExceptionType.SecurityTokenSignatureKeyNotFound,
new StackFrame()));

StringBuilder exceptionStrings = new();
Expand Down Expand Up @@ -215,7 +215,7 @@ private static SignatureValidationResult ValidateSignatureWithKey(
LogMessages.IDX14000,
LogHelper.MarkAsNonPII(jsonWebToken.Alg),
key),
typeof(SecurityTokenInvalidAlgorithmException),
ExceptionDetail.ExceptionType.SecurityTokenInvalidAlgorithm,
new StackFrame()));
}

Expand All @@ -240,7 +240,7 @@ private static SignatureValidationResult ValidateSignatureWithKey(
new MessageDetail(TokenLogMessages.IDX10636,
key?.ToString() ?? "Null",
LogHelper.MarkAsNonPII(jsonWebToken.Alg)),
typeof(InvalidOperationException),
ExceptionDetail.ExceptionType.InvalidOperation,
new StackFrame()));

bool valid = EncodingUtils.PerformEncodingDependentOperation<bool, string, int, SignatureProvider>(
Expand All @@ -260,7 +260,7 @@ private static SignatureValidationResult ValidateSignatureWithKey(
ValidationFailureType.SignatureValidationFailed,
new ExceptionDetail(
new MessageDetail(TokenLogMessages.IDX10504),
typeof(SecurityTokenInvalidSignatureException),
ExceptionDetail.ExceptionType.SecurityTokenInvalidSignature,
new StackFrame()));
}
#pragma warning disable CA1031 // Do not catch general exception types
Expand All @@ -271,7 +271,7 @@ private static SignatureValidationResult ValidateSignatureWithKey(
ValidationFailureType.SignatureValidationFailed,
new ExceptionDetail(
new MessageDetail(TokenLogMessages.IDX10504, ex.ToString()),
ex.GetType(),
ExceptionDetail.ExceptionType.SecurityTokenInvalidSignature,
new StackFrame(),
ex));
}
Expand Down Expand Up @@ -311,7 +311,7 @@ private static ExceptionDetail GetSignatureValidationFailureExceptionDetails(
LogHelper.MarkAsNonPII(jwtToken.Kid),
exceptionStrings.ToString(),
LogHelper.MarkAsSecurityArtifact(jwtToken.EncodedToken, JwtTokenUtilities.SafeLogJwtToken)),
typeof(SecurityTokenSignatureKeyNotFoundException),
ExceptionDetail.ExceptionType.SecurityTokenSignatureKeyNotFound,
new StackFrame());
}

Expand All @@ -325,7 +325,7 @@ private static ExceptionDetail GetSignatureValidationFailureExceptionDetails(
LogHelper.MarkAsNonPII(numKeysInConfiguration),
exceptionStrings.ToString(),
LogHelper.MarkAsSecurityArtifact(jwtToken.EncodedToken, JwtTokenUtilities.SafeLogJwtToken)),
typeof(SecurityTokenSignatureKeyNotFoundException),
ExceptionDetail.ExceptionType.SecurityTokenSignatureKeyNotFound,
new StackFrame());

return new ExceptionDetail(
Expand All @@ -336,7 +336,7 @@ private static ExceptionDetail GetSignatureValidationFailureExceptionDetails(
LogHelper.MarkAsNonPII(numKeysInConfiguration),
exceptionStrings.ToString(),
LogHelper.MarkAsSecurityArtifact(jwtToken.EncodedToken, JwtTokenUtilities.SafeLogJwtToken)),
typeof(SecurityTokenSignatureKeyNotFoundException),
ExceptionDetail.ExceptionType.SecurityTokenSignatureKeyNotFound,
new StackFrame());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal static TokenDecryptionResult DecryptJwtToken(
new MessageDetail(
TokenLogMessages.IDX10000,
nameof(validationParameters)),
typeof(ArgumentNullException),
ExceptionDetail.ExceptionType.ArgumentNull,
new System.Diagnostics.StackFrame()));

if (decryptionParameters == null)
Expand All @@ -46,7 +46,7 @@ internal static TokenDecryptionResult DecryptJwtToken(
new MessageDetail(
TokenLogMessages.IDX10000,
nameof(decryptionParameters)),
typeof(ArgumentNullException),
ExceptionDetail.ExceptionType.ArgumentNull,
new System.Diagnostics.StackFrame()));

bool decryptionSucceeded = false;
Expand Down Expand Up @@ -142,7 +142,7 @@ internal static TokenDecryptionResult DecryptJwtToken(
new MessageDetail(
TokenLogMessages.IDX10679,
zipAlgorithm),
typeof(SecurityTokenDecompressionFailedException),
ExceptionDetail.ExceptionType.SecurityTokenDecompressionFailed,
new StackFrame(),
ex));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ private static ExceptionDetail GetDecryptionExceptionDetail(
keysAttempted.ToString(),
exceptionStrings?.ToString() ?? string.Empty,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
typeof(SecurityTokenDecryptionFailedException),
ExceptionDetail.ExceptionType.SecurityTokenDecryptionFailed,
new StackFrame(true),
null);
else if (algorithmNotSupportedByCryptoProvider)
Expand All @@ -376,15 +376,15 @@ private static ExceptionDetail GetDecryptionExceptionDetail(
TokenLogMessages.IDX10619,
LogHelper.MarkAsNonPII(decryptionParameters.Alg),
LogHelper.MarkAsNonPII(decryptionParameters.Enc)),
typeof(SecurityTokenDecryptionFailedException),
ExceptionDetail.ExceptionType.SecurityTokenDecryptionFailed,
new StackFrame(true),
null);
else
return new ExceptionDetail(
new MessageDetail(
TokenLogMessages.IDX10609,
LogHelper.MarkAsSecurityArtifact(decryptionParameters.EncodedToken, SafeLogJwtToken)),
typeof(SecurityTokenDecryptionFailedException),
ExceptionDetail.ExceptionType.SecurityTokenDecryptionFailed,
new StackFrame(true),
null);
}
Expand Down
93 changes: 81 additions & 12 deletions src/Microsoft.IdentityModel.Tokens/Validation/ExceptionDetail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal class ExceptionDetail
/// <paramref name="messageDetail"/> contains information about the exception that is used to generate the exception message.
/// <paramref name="exceptionType"/> is the type of exception that occurred.
/// <paramref name="stackFrame"/> contains information about the stack frame where the exception occurred.
public ExceptionDetail(MessageDetail messageDetail, Type exceptionType, StackFrame stackFrame)
public ExceptionDetail(MessageDetail messageDetail, ExceptionType exceptionType, StackFrame stackFrame)
: this(messageDetail, exceptionType, stackFrame, null)
{
}
Expand All @@ -31,9 +31,9 @@ public ExceptionDetail(MessageDetail messageDetail, Type exceptionType, StackFra
/// <paramref name="exceptionType"/> is the type of exception that occurred.
/// <paramref name="stackFrame"/> contains information about the stack frame where the exception occurred.
/// <paramref name="innerException"/> is the inner exception that occurred.
public ExceptionDetail(MessageDetail messageDetail, Type exceptionType, StackFrame stackFrame, Exception innerException)
public ExceptionDetail(MessageDetail messageDetail, ExceptionType exceptionType, StackFrame stackFrame, Exception innerException)
{
ExceptionType = exceptionType;
Type = exceptionType;
InnerException = innerException;
MessageDetail = messageDetail;
StackFrames.Add(stackFrame);
Expand All @@ -43,25 +43,19 @@ public ExceptionDetail(MessageDetail messageDetail, Type exceptionType, StackFra
/// Creates an instance of an <see cref="Exception"/> using <see cref="ExceptionDetail"/>
/// </summary>
/// <returns>An instantance of an Exception.</returns>
public Exception GetException()
{
if (InnerException != null)
return Activator.CreateInstance(ExceptionType, MessageDetail.Message, InnerException) as Exception;

return Activator.CreateInstance(ExceptionType, MessageDetail.Message) as Exception;
}
public Exception GetException() => ExceptionFromType(Type, InnerException);

internal static ExceptionDetail NullParameter(string parameterName) => new ExceptionDetail(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII(parameterName)),
typeof(ArgumentNullException),
ExceptionType.ArgumentNull,
new StackFrame());

/// <summary>
/// Gets the type of exception that occurred.
/// </summary>
public Type ExceptionType { get; }
public ExceptionType Type { get; }

/// <summary>
/// Gets the inner exception that occurred.
Expand All @@ -77,5 +71,80 @@ public Exception GetException()
/// Gets the stack frames where the exception occurred.
/// </summary>
public IList<StackFrame> StackFrames { get; } = [];

public enum ExceptionType
{
Unknown = -1,
ArgumentNull,
InvalidOperation,
SecurityToken,
SecurityTokenDecompressionFailed,
SecurityTokenDecryptionFailed,
SecurityTokenExpired,
SecurityTokenInvalidAudience,
SecurityTokenInvalidAlgorithm,
SecurityTokenInvalidIssuer,
SecurityTokenInvalidLifetime,
SecurityTokenInvalidSigningKey,
SecurityTokenInvalidSignature,
SecurityTokenInvalidType,
SecurityTokenKeyWrap,
SecurityTokenMalformed,
SecurityTokenNoExpiration,
SecurityTokenNotYetValid,
SecurityTokenReplayDetected,
SecurityTokenReplayAddFailed,
SecurityTokenSignatureKeyNotFound,
ExceptionTypeCount
}

private Exception ExceptionFromType(ExceptionType exceptionType, Exception innerException)
{
switch (exceptionType)
{
case ExceptionType.ArgumentNull:
return new ArgumentNullException(MessageDetail.Message, innerException);
case ExceptionType.InvalidOperation:
return new InvalidOperationException(MessageDetail.Message, innerException);
case ExceptionType.SecurityToken:
return new SecurityTokenException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenDecompressionFailed:
return new SecurityTokenDecompressionFailedException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenDecryptionFailed:
return new SecurityTokenDecryptionFailedException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenExpired:
return new SecurityTokenExpiredException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidAudience:
return new SecurityTokenInvalidAudienceException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidAlgorithm:
return new SecurityTokenInvalidAlgorithmException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidIssuer:
return new SecurityTokenInvalidIssuerException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidLifetime:
return new SecurityTokenInvalidLifetimeException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidSignature:
return new SecurityTokenInvalidSignatureException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidSigningKey:
return new SecurityTokenInvalidSigningKeyException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenInvalidType:
return new SecurityTokenInvalidTypeException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenKeyWrap:
return new SecurityTokenKeyWrapException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenMalformed:
return new SecurityTokenMalformedException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenNoExpiration:
return new SecurityTokenNoExpirationException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenNotYetValid:
return new SecurityTokenNotYetValidException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenReplayDetected:
return new SecurityTokenReplayDetectedException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenReplayAddFailed:
return new SecurityTokenReplayAddFailedException(MessageDetail.Message, innerException);
case ExceptionType.SecurityTokenSignatureKeyNotFound:
return new SecurityTokenSignatureKeyNotFoundException(MessageDetail.Message, innerException);
default:
throw new ArgumentException("Invalid ExceptionType.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal static AlgorithmValidationResult ValidateAlgorithm(
new MessageDetail(
LogMessages.IDX10000,
LogHelper.MarkAsNonPII(nameof(validationParameters))),
typeof(ArgumentNullException),
ExceptionDetail.ExceptionType.ArgumentNull,
new StackFrame(true)));
}

Expand All @@ -67,7 +67,7 @@ internal static AlgorithmValidationResult ValidateAlgorithm(
new MessageDetail(
LogMessages.IDX10696,
LogHelper.MarkAsNonPII(algorithm)),
typeof(SecurityTokenInvalidAlgorithmException),
ExceptionDetail.ExceptionType.SecurityTokenInvalidAlgorithm,
new StackFrame(true)));
}

Expand Down
Loading

0 comments on commit d2632a7

Please sign in to comment.