Skip to content

Commit 876def8

Browse files
iNinjakllysng
andauthored
Regression tests: Issuer (#2868)
* Renamed CreateToken methods in audience and lifetime regression tests * Added custom ValidationError class for issuer errors. Updated IssuerValidationDelegateAsync to use it. * Added JWT issuer regression tests * Update test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Issuer.cs Co-authored-by: kellyyangsong <[email protected]> * Added IssuerValidationError to InternalAPI.Unshipped. Made constructor internal for the time being * Updated exception creation in IssuerValidationError * Adjusted unshipped API contents with the IDE suggestions --------- Co-authored-by: kellyyangsong <[email protected]>
1 parent 3dab668 commit 876def8

File tree

11 files changed

+219
-19
lines changed

11 files changed

+219
-19
lines changed

src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10001 = "IDX10001: Invalid argument '{0}'. Argument must be of type '{1}'." -> string
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError
2+
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10001 = "IDX10001: Invalid argument '{0}'. Argument must be of type '{1}'." -> string
23
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10502 = "IDX10502: Signature validation failed. The token's kid is: '{0}', but did not match any keys in ValidationParameters or Configuration and TryAllIssuerSigningKeys is false. Number of keys in ValidationParameters: '{1}'. \nNumber of keys in Configuration: '{2}'.\ntoken: '{3}'." -> string
34
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10518 = "IDX10518: Signature validation failed. Algorithm validation failed with error: '{0}'." -> string
45
Microsoft.IdentityModel.Tokens.AlgorithmValidationDelegate

src/Microsoft.IdentityModel.Tokens/PublicAPI/net462/InternalAPI.Unshipped.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.DecryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
2+
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
3+
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.DecryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
24
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.EncryptWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
35
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignWithRsaCryptoServiceProviderProxy(byte[] bytes) -> byte[]
46
Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignWithRsaCryptoServiceProviderProxyUsingOffset(byte[] bytes, int offset, int length) -> byte[]
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
2+
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
3+
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
24
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
35
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
2+
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
3+
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
24
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
35
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
2+
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
3+
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Frozen.FrozenSet<string>
24
Microsoft.IdentityModel.Tokens.EcdhKeyExchangeProvider.GetEncryptionAlgorithm() -> string
35
Microsoft.IdentityModel.Tokens.SignUsingSpanDelegate
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
1+
Microsoft.IdentityModel.Tokens.IssuerValidationError.IssuerValidationError(Microsoft.IdentityModel.Tokens.MessageDetail messageDetail, System.Type exceptionType, System.Diagnostics.StackFrame stackFrame, string invalidIssuer) -> void
2+
override Microsoft.IdentityModel.Tokens.IssuerValidationError.GetException() -> System.Exception
3+
static readonly Microsoft.IdentityModel.Tokens.Json.JsonWebKeySerializer.JsonWebKeyParameterNamesUpperCase -> System.Collections.Generic.HashSet<string>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Diagnostics;
6+
7+
#nullable enable
8+
namespace Microsoft.IdentityModel.Tokens
9+
{
10+
internal class IssuerValidationError : ValidationError
11+
{
12+
private string? _invalidIssuer;
13+
14+
internal IssuerValidationError(
15+
MessageDetail messageDetail,
16+
Type exceptionType,
17+
StackFrame stackFrame,
18+
string? invalidIssuer)
19+
: base(messageDetail, ValidationFailureType.IssuerValidationFailed, exceptionType, stackFrame)
20+
{
21+
_invalidIssuer = invalidIssuer;
22+
}
23+
24+
public override Exception GetException()
25+
{
26+
if (ExceptionType == typeof(SecurityTokenInvalidIssuerException))
27+
{
28+
SecurityTokenInvalidIssuerException exception = new(MessageDetail.Message, InnerException)
29+
{
30+
InvalidIssuer = _invalidIssuer
31+
};
32+
33+
return exception;
34+
}
35+
36+
return base.GetException();
37+
}
38+
}
39+
}
40+
#nullable restore

src/Microsoft.IdentityModel.Tokens/Validation/Validators.Issuer.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn
6161
{
6262
if (string.IsNullOrWhiteSpace(issuer))
6363
{
64-
return new ValidationError(
64+
return new IssuerValidationError(
6565
new MessageDetail(LogMessages.IDX10211),
66-
ValidationFailureType.IssuerValidationFailed,
6766
typeof(SecurityTokenInvalidIssuerException),
68-
new StackFrame(true));
67+
new StackFrame(true),
68+
issuer);
6969
}
7070

7171
if (validationParameters == null)
@@ -84,11 +84,11 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn
8484

8585
// Return failed IssuerValidationResult if all possible places to validate against are null or empty.
8686
if (validationParameters.ValidIssuers.Count == 0 && string.IsNullOrWhiteSpace(configuration?.Issuer))
87-
return new ValidationError(
87+
return new IssuerValidationError(
8888
new MessageDetail(LogMessages.IDX10211),
89-
ValidationFailureType.IssuerValidationFailed,
9089
typeof(SecurityTokenInvalidIssuerException),
91-
new StackFrame(true));
90+
new StackFrame(true),
91+
issuer);
9292

9393
if (configuration != null)
9494
{
@@ -130,15 +130,15 @@ internal static async Task<ValidationResult<ValidatedIssuer>> ValidateIssuerAsyn
130130
}
131131
}
132132

133-
return new ValidationError(
133+
return new IssuerValidationError(
134134
new MessageDetail(
135135
LogMessages.IDX10212,
136136
LogHelper.MarkAsNonPII(issuer),
137137
LogHelper.MarkAsNonPII(Utility.SerializeAsSingleCommaDelimitedString(validationParameters.ValidIssuers)),
138138
LogHelper.MarkAsNonPII(configuration?.Issuer)),
139-
ValidationFailureType.IssuerValidationFailed,
140139
typeof(SecurityTokenInvalidIssuerException),
141-
new StackFrame(true));
140+
new StackFrame(true),
141+
issuer);
142142
}
143143
}
144144
}

test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandler.ValidateTokenAsyncTests.Audience.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public async Task ValidateTokenAsync_Audience(ValidateTokenAsyncAudienceTheoryDa
1717
{
1818
var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_Audience", theoryData);
1919

20-
string jwtString = CreateToken(theoryData.Audience);
20+
string jwtString = CreateTokenWithAudience(theoryData.Audience);
2121

2222
await ValidateAndCompareResults(jwtString, theoryData, context);
2323

@@ -155,7 +155,7 @@ public ValidateTokenAsyncAudienceTheoryData(string testId) : base(testId) { }
155155
public string? Audience { get; internal set; } = Default.Audience;
156156
}
157157

158-
private static string CreateToken(string? audience)
158+
private static string CreateTokenWithAudience(string? audience)
159159
{
160160
JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler();
161161

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#nullable enable
5+
using System.Threading.Tasks;
6+
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
7+
using Microsoft.IdentityModel.TestUtils;
8+
using Microsoft.IdentityModel.Tokens;
9+
using Xunit;
10+
11+
namespace Microsoft.IdentityModel.JsonWebTokens.Tests
12+
{
13+
public partial class JsonWebTokenHandlerValidateTokenAsyncTests
14+
{
15+
[Theory, MemberData(nameof(ValidateTokenAsync_IssuerTestCases), DisableDiscoveryEnumeration = true)]
16+
public async Task ValidateTokenAsync_Issuer(ValidateTokenAsyncIssuerTheoryData theoryData)
17+
{
18+
var context = TestUtilities.WriteHeader($"{this}.ValidateTokenAsync_Issuer", theoryData);
19+
20+
string jwtString = CreateTokenWithIssuer(theoryData.TokenIssuer);
21+
22+
await ValidateAndCompareResults(jwtString, theoryData, context);
23+
24+
TestUtilities.AssertFailIfErrors(context);
25+
}
26+
27+
public static TheoryData<ValidateTokenAsyncIssuerTheoryData> ValidateTokenAsync_IssuerTestCases
28+
{
29+
get
30+
{
31+
return new TheoryData<ValidateTokenAsyncIssuerTheoryData>
32+
{
33+
new ValidateTokenAsyncIssuerTheoryData("Valid_IssuerIsValidIssuer")
34+
{
35+
TokenIssuer = Default.Issuer,
36+
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
37+
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
38+
},
39+
new ValidateTokenAsyncIssuerTheoryData("Valid_IssuerIsConfigurationIssuer")
40+
{
41+
TokenIssuer = Default.Issuer,
42+
TokenValidationParameters = CreateTokenValidationParameters(configurationIssuer: Default.Issuer),
43+
ValidationParameters = CreateValidationParameters(configurationIssuer: Default.Issuer),
44+
},
45+
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsNotValid")
46+
{
47+
TokenIssuer = "InvalidIssuer",
48+
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
49+
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
50+
ExpectedIsValid = false,
51+
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10205:"),
52+
ExpectedExceptionValidationParameters = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10212:"),
53+
},
54+
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsNull")
55+
{
56+
TokenIssuer = null,
57+
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
58+
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
59+
ExpectedIsValid = false,
60+
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
61+
},
62+
new ValidateTokenAsyncIssuerTheoryData("Invalid_IssuerIsEmpty")
63+
{
64+
TokenIssuer = string.Empty,
65+
TokenValidationParameters = CreateTokenValidationParameters(validIssuer: Default.Issuer),
66+
ValidationParameters = CreateValidationParameters(validIssuer: Default.Issuer),
67+
ExpectedIsValid = false,
68+
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
69+
},
70+
new ValidateTokenAsyncIssuerTheoryData("Invalid_NoValidIssuersProvided")
71+
{
72+
TokenIssuer = Default.Issuer,
73+
TokenValidationParameters = CreateTokenValidationParameters(),
74+
ValidationParameters = CreateValidationParameters(),
75+
ExpectedIsValid = false,
76+
ExpectedException = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10204:"),
77+
ExpectedExceptionValidationParameters = new ExpectedException(typeof(SecurityTokenInvalidIssuerException), "IDX10211:"),
78+
},
79+
};
80+
81+
static TokenValidationParameters CreateTokenValidationParameters(
82+
string? validIssuer = null, string? configurationIssuer = null)
83+
{
84+
var tokenValidationParameters = new TokenValidationParameters
85+
{
86+
ValidateAudience = true,
87+
ValidateIssuer = true,
88+
ValidateLifetime = true,
89+
ValidateTokenReplay = true,
90+
ValidateIssuerSigningKey = true,
91+
IssuerSigningKey = Default.AsymmetricSigningKey,
92+
ValidAudiences = [Default.Audience],
93+
ValidIssuer = validIssuer
94+
};
95+
96+
if (configurationIssuer is not null)
97+
{
98+
var validConfig = new OpenIdConnectConfiguration() { Issuer = configurationIssuer };
99+
tokenValidationParameters.ConfigurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(validConfig);
100+
}
101+
102+
return tokenValidationParameters;
103+
}
104+
105+
static ValidationParameters CreateValidationParameters(
106+
string? validIssuer = null, string? configurationIssuer = null)
107+
{
108+
ValidationParameters validationParameters = new ValidationParameters();
109+
validationParameters.ValidAudiences.Add(Default.Audience);
110+
validationParameters.IssuerSigningKeys.Add(Default.AsymmetricSigningKey);
111+
112+
if (configurationIssuer is not null)
113+
{
114+
var validConfig = new OpenIdConnectConfiguration() { Issuer = configurationIssuer };
115+
validationParameters.ConfigurationManager = new MockConfigurationManager<OpenIdConnectConfiguration>(validConfig);
116+
}
117+
118+
if (validIssuer is not null)
119+
validationParameters.ValidIssuers.Add(validIssuer);
120+
121+
return validationParameters;
122+
}
123+
}
124+
}
125+
126+
public class ValidateTokenAsyncIssuerTheoryData : ValidateTokenAsyncBaseTheoryData
127+
{
128+
public ValidateTokenAsyncIssuerTheoryData(string testId) : base(testId) { }
129+
130+
public string? TokenIssuer { get; set; }
131+
}
132+
133+
private static string CreateTokenWithIssuer(string? issuer)
134+
{
135+
JsonWebTokenHandler jsonWebTokenHandler = new JsonWebTokenHandler();
136+
137+
SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor
138+
{
139+
Subject = Default.ClaimsIdentity,
140+
SigningCredentials = Default.AsymmetricSigningCredentials,
141+
Audience = Default.Audience,
142+
Issuer = issuer,
143+
};
144+
145+
return jsonWebTokenHandler.CreateToken(securityTokenDescriptor);
146+
}
147+
}
148+
}
149+
#nullable restore

0 commit comments

Comments
 (0)