diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs index 781c0d5d3e..206c9175d6 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs @@ -961,7 +961,7 @@ private static JsonWebToken ValidateSignature(JsonWebToken jwtToken, TokenValida var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(localJwtToken.Kid)); var keyLocation = isKidInTVP ? "TokenValidationParameters" : "Configuration"; throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10511, - (object)keysAttempted ?? "", + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), LogHelper.MarkAsNonPII(numKeysInConfiguration), LogHelper.MarkAsNonPII(keyLocation), @@ -983,12 +983,27 @@ private static JsonWebToken ValidateSignature(JsonWebToken jwtToken, TokenValida } if (keysAttempted is not null) - throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10503, - keysAttempted, - LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), - LogHelper.MarkAsNonPII(numKeysInConfiguration), - (object)exceptionStrings ?? "", - jwtToken))); + { + if (kidExists) + { + throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10503, + LogHelper.MarkAsNonPII(jwtToken.Kid), + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), + LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), + LogHelper.MarkAsNonPII(numKeysInConfiguration), + (object)exceptionStrings ?? "", + jwtToken))); + } + else + { + throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10517, + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), + LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), + LogHelper.MarkAsNonPII(numKeysInConfiguration), + (object)exceptionStrings ?? "", + jwtToken))); + } + } throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(TokenLogMessages.IDX10500)); } diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index a0e413bcff..a3e00cef2e 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -83,7 +83,7 @@ internal static class LogMessages // 10500 - SignatureValidation public const string IDX10500 = "IDX10500: Signature validation failed. No security keys were provided to validate the signature."; //public const string IDX10501 = "IDX10501: Signature validation failed. Unable to match key: \nkid: '{0}'. \nNumber of keys in TokenValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'. \nExceptions caught:\n '{3}'. \ntoken: '{4}'."; - public const string IDX10503 = "IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '{0}'. Number of keys in TokenValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'. \nExceptions caught:\n '{3}'.\ntoken: '{4}'. See https://aka.ms/IDX10503 for details."; + public const string IDX10503 = "IDX10503: Signature validation failed. The token's kid is: '{0}', but did not match any keys in TokenValidationParameters or Configuration. Keys tried: '{1}'. Number of keys in TokenValidationParameters: '{2}'. \nNumber of keys in Configuration: '{3}'. \nExceptions caught:\n '{4}'.\ntoken: '{5}'. See https://aka.ms/IDX10503 for details."; public const string IDX10504 = "IDX10504: Unable to validate signature, token does not have a signature: '{0}'."; public const string IDX10505 = "IDX10505: Signature validation failed. The user defined 'Delegate' specified on TokenValidationParameters returned null when validating token: '{0}'."; public const string IDX10506 = "IDX10506: Signature validation failed. The user defined 'Delegate' specified on TokenValidationParameters did not return a '{0}', but returned a '{1}' when validating token: '{2}'."; @@ -97,6 +97,7 @@ internal static class LogMessages public const string IDX10514 = "IDX10514: Signature validation failed. Keys tried: '{0}'. \nKeyInfo: '{1}'. \nExceptions caught:\n '{2}'.\ntoken: '{3}'."; //public const string IDX10515 = "IDX10515: Signature validation failed. Unable to match key: \nKeyInfo: '{0}'.\nExceptions caught:\n '{1}'. \ntoken: '{2}'. Valid Lifetime: '{3}'. Valid Issuer: '{4}'"; //public const string IDX10516 = "IDX10516: Signature validation failed. Unable to match key: \nkid: '{0}'. \nNumber of keys in TokenValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'. \nExceptions caught:\n '{3}'. \ntoken: '{4}'. Valid Lifetime: '{5}'. Valid Issuer: '{6}'"; + public const string IDX10517 = "IDX10517: Signature validation failed. The token's kid is missing. Keys tried: '{0}'. Number of keys in TokenValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'. \nExceptions caught:\n '{3}'.\ntoken: '{4}'. See https://aka.ms/IDX10503 for details."; // encryption / decryption // public const string IDX10600 = "IDX10600:"; diff --git a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs index 0185050c47..22e12d346b 100644 --- a/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs +++ b/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs @@ -1358,8 +1358,8 @@ private JwtSecurityToken ValidateSignature(string token, JwtSecurityToken jwtTok } // keep track of exceptions thrown, keys that were tried - var exceptionStrings = new StringBuilder(); - var keysAttempted = new StringBuilder(); + StringBuilder exceptionStrings = null; + StringBuilder keysAttempted = null; bool kidExists = !string.IsNullOrEmpty(jwtToken.Header.Kid); byte[] signatureBytes; @@ -1389,12 +1389,12 @@ private JwtSecurityToken ValidateSignature(string token, JwtSecurityToken jwtTok } catch (Exception ex) { - exceptionStrings.AppendLine(ex.ToString()); + (exceptionStrings ??= new StringBuilder()).AppendLine(ex.ToString()); } if (key != null) { - keysAttempted.Append(key.ToString()).Append(" , KeyId: ").AppendLine(key.KeyId); + (keysAttempted ??= new StringBuilder()).Append(key.ToString()).Append(" , KeyId: ").AppendLine(key.KeyId); if (kidExists && !kidMatched && key.KeyId != null) kidMatched = jwtToken.Header.Kid.Equals(key.KeyId, key is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); } @@ -1412,15 +1412,16 @@ private JwtSecurityToken ValidateSignature(string token, JwtSecurityToken jwtTok { if (kidMatched) { - var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(jwtToken.Header.Kid)); + JwtSecurityToken localJwtToken = jwtToken; // avoid closure on non-exceptional path + var isKidInTVP = keysInTokenValidationParameters.Any(x => x.KeyId.Equals(localJwtToken.Header.Kid)); var keyLocation = isKidInTVP ? "TokenValidationParameters" : "Configuration"; throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10511, - keysAttempted, + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), LogHelper.MarkAsNonPII(numKeysInConfiguration), LogHelper.MarkAsNonPII(keyLocation), LogHelper.MarkAsNonPII(jwtToken.Header.Kid), - exceptionStrings, + (object)exceptionStrings ?? "", jwtToken))); } @@ -1439,13 +1440,28 @@ private JwtSecurityToken ValidateSignature(string token, JwtSecurityToken jwtTok } } - if (keysAttempted.Length > 0) - throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10503, - keysAttempted, - LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), - LogHelper.MarkAsNonPII(numKeysInConfiguration), - exceptionStrings, - jwtToken))); + if (keysAttempted is not null) + { + if (kidExists) + { + throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10503, + LogHelper.MarkAsNonPII(jwtToken.Header.Kid), + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), + LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), + LogHelper.MarkAsNonPII(numKeysInConfiguration), + (object)exceptionStrings ?? "", + jwtToken))); + } + else + { + throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10517, + LogHelper.MarkAsNonPII((object)keysAttempted ?? ""), + LogHelper.MarkAsNonPII(numKeysInTokenValidationParameters), + LogHelper.MarkAsNonPII(numKeysInConfiguration), + (object)exceptionStrings ?? "", + jwtToken))); + } + } throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(TokenLogMessages.IDX10500)); } diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs index 4ff9df2f80..c1723c3a62 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/CreateAndValidateTokens.cs @@ -139,7 +139,7 @@ public void MatchX5t() validateKey = KeyingMaterial.X509SecurityKeySelfSigned2048_SHA384_Public; validationParameters.IssuerSigningKey = validateKey; - ExpectedException expectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException("IDX10503:"); + ExpectedException expectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException("IDX10517:"); try { cp = handler.ValidateToken(jwt, validationParameters, out validatedSecurityToken); diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs index ccf3f752e3..24aab34fbb 100644 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs +++ b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.cs @@ -1891,7 +1891,7 @@ public static TheoryData ValidateSignatureTheoryData { new JwtTheoryData { - ExpectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException(substringExpected: "IDX10503:"), + ExpectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException(substringExpected: "IDX10517:"), TestId = "Security Key Identifier not found", Token = JwtTestUtilities.GetJwtParts(EncodedJwts.Asymmetric_2048, "ALLParts"), ValidationParameters = ValidateSignatureValidationParameters(KeyingMaterial.X509SecurityKey_LocalSts, null) @@ -2012,7 +2012,7 @@ public static TheoryData ValidateSignatureTheoryData }, new JwtTheoryData { - ExpectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException(substringExpected: "IDX10503:"), + ExpectedException = ExpectedException.SecurityTokenSignatureKeyNotFoundException(substringExpected: "IDX10517:"), TestId = "BinaryKey 56Bits", Token = JwtTestUtilities.GetJwtParts(EncodedJwts.Symmetric_256, "ALLParts"), ValidationParameters = ValidateSignatureValidationParameters(KeyingMaterial.DefaultSymmetricSecurityKey_56, null),