Skip to content

Commit afeb7e5

Browse files
MZOLNmarcinzo
andauthored
Marcinzo/issuervalidatorv11 (#2503)
* Add V11 support for the aad issuer validator. * Tests * Add v11 tests * Add PPE tests --------- Co-authored-by: marcinzo <[email protected]>
1 parent 782602b commit afeb7e5

File tree

5 files changed

+397
-79
lines changed

5 files changed

+397
-79
lines changed

src/Microsoft.IdentityModel.Validators/AadIssuerValidator/AadIssuerValidator.cs

Lines changed: 166 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.IdentityModel.Protocols;
1414
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
1515
using Microsoft.IdentityModel.Tokens;
16+
using static Microsoft.IdentityModel.Validators.AadIssuerValidator;
1617

1718
namespace Microsoft.IdentityModel.Validators
1819
{
@@ -23,8 +24,12 @@ public class AadIssuerValidator
2324
{
2425
private static readonly TimeSpan LastKnownGoodConfigurationLifetime = new TimeSpan(0, 24, 0, 0);
2526

27+
internal const string V11EndpointSuffix = "/v1.1";
28+
internal const string V11EndpointSuffixWithTrailingSlash = $"{V11EndpointSuffix}/";
29+
2630
internal const string V2EndpointSuffix = "/v2.0";
2731
internal const string V2EndpointSuffixWithTrailingSlash = $"{V2EndpointSuffix}/";
32+
2833
internal const string TenantIdTemplate = "{tenantid}";
2934

3035
private Func<string, BaseConfigurationManager> _configurationManagerProvider;
@@ -35,7 +40,8 @@ internal AadIssuerValidator(
3540
{
3641
HttpClient = httpClient;
3742
AadAuthority = aadAuthority.TrimEnd('/');
38-
IsV2Authority = aadAuthority.Contains(V2EndpointSuffix);
43+
AadAuthorityVersion = GetProtocolVersion(AadAuthority);
44+
SetupAuthorities(AadAuthority, AadAuthorityVersion);
3945
}
4046

4147
internal AadIssuerValidator(
@@ -51,11 +57,12 @@ internal AadIssuerValidator(
5157
}
5258

5359
private HttpClient HttpClient { get; }
54-
private string _aadAuthorityV1;
55-
private string _aadAuthorityV2;
60+
5661
private BaseConfigurationManager _configurationManagerV1;
62+
private BaseConfigurationManager _configurationManagerV11;
5763
private BaseConfigurationManager _configurationManagerV2;
5864
private IssuerLastKnownGood _issuerLKGV1;
65+
private IssuerLastKnownGood _issuerLKGV11;
5966
private IssuerLastKnownGood _issuerLKGV2;
6067

6168
internal BaseConfigurationManager ConfigurationManagerV1
@@ -74,6 +81,22 @@ internal BaseConfigurationManager ConfigurationManagerV1
7481
}
7582
}
7683

84+
internal BaseConfigurationManager ConfigurationManagerV11
85+
{
86+
get
87+
{
88+
if (_configurationManagerV11 == null)
89+
_configurationManagerV11 = CreateConfigManager(AadAuthorityV11);
90+
91+
return _configurationManagerV11;
92+
}
93+
94+
set
95+
{
96+
_configurationManagerV11 = value;
97+
}
98+
}
99+
77100
internal BaseConfigurationManager ConfigurationManagerV2
78101
{
79102
get
@@ -92,30 +115,54 @@ internal BaseConfigurationManager ConfigurationManagerV2
92115

93116
internal string AadAuthorityV1
94117
{
95-
get
96-
{
97-
if (_aadAuthorityV1 == null)
98-
_aadAuthorityV1 = IsV2Authority ? CreateV1Authority(AadAuthority) : AadAuthority;
118+
get;
119+
private set;
120+
}
99121

100-
return _aadAuthorityV1;
101-
}
122+
internal string AadAuthorityV11
123+
{
124+
get;
125+
private set;
102126
}
103127

104128
internal string AadAuthorityV2
105129
{
106-
get
107-
{
108-
if (_aadAuthorityV2 == null)
109-
_aadAuthorityV2 = IsV2Authority ? AadAuthority : AadAuthority + V2EndpointSuffix;
130+
get;
131+
private set;
132+
}
110133

111-
return _aadAuthorityV2;
134+
private void SetupAuthorities(string aadAuthority, ProtocolVersion version)
135+
{
136+
switch (version)
137+
{
138+
case ProtocolVersion.V1:
139+
AadAuthorityV1 = aadAuthority;
140+
AadAuthorityV11 = AadAuthorityV1 + V11EndpointSuffix;
141+
AadAuthorityV2 = AadAuthorityV1 + V2EndpointSuffix;
142+
break;
143+
144+
case ProtocolVersion.V11:
145+
AadAuthorityV1 = CreateV1Authority(AadAuthority, V11EndpointSuffix);
146+
AadAuthorityV11 = aadAuthority;
147+
AadAuthorityV2 = AadAuthorityV1 + V2EndpointSuffix;
148+
break;
149+
150+
case ProtocolVersion.V2:
151+
AadAuthorityV1 = CreateV1Authority(AadAuthority);
152+
AadAuthorityV11 = AadAuthorityV1 + V11EndpointSuffix;
153+
AadAuthorityV2 = aadAuthority;
154+
break;
155+
156+
default:
157+
throw new InvalidOperationException("Unsupported protocol version.");
112158
}
113159
}
114160

115161
internal string AadIssuerV1 { get; set; }
116162
internal string AadIssuerV2 { get; set; }
117163
internal string AadAuthority { get; set; }
118-
internal bool IsV2Authority { get; set; }
164+
internal ProtocolVersion AadAuthorityVersion { get; set; }
165+
119166
internal static readonly IDictionary<string, AadIssuerValidator> s_issuerValidators = new ConcurrentDictionary<string, AadIssuerValidator>();
120167

121168
/// <summary>
@@ -196,14 +243,14 @@ internal async ValueTask<string> ValidateAsync(
196243

197244
try
198245
{
199-
var isV2Issuer = IsV2Issuer(securityToken);
200-
var effectiveConfigurationManager = GetEffectiveConfigurationManager(isV2Issuer);
246+
var issuerVersion = GetTokenIssuerVersion(securityToken);
247+
var effectiveConfigurationManager = GetEffectiveConfigurationManager(issuerVersion);
201248

202249
string aadIssuer = null;
203250
if (validationParameters.ValidateWithLKG)
204251
{
205252
// returns null if LKG issuer expired
206-
aadIssuer = GetEffectiveLKGIssuer(isV2Issuer);
253+
aadIssuer = GetEffectiveLKGIssuer(issuerVersion);
207254
}
208255
else
209256
{
@@ -217,7 +264,7 @@ internal async ValueTask<string> ValidateAsync(
217264

218265
// The original LKG assignment behavior for previous self-state management.
219266
if (isIssuerValid && !validationParameters.ValidateWithLKG)
220-
SetEffectiveLKGIssuer(aadIssuer, isV2Issuer, effectiveConfigurationManager.LastKnownGoodLifetime);
267+
SetEffectiveLKGIssuer(aadIssuer, issuerVersion, effectiveConfigurationManager.LastKnownGoodLifetime);
221268

222269
if (isIssuerValid)
223270
return issuer;
@@ -305,12 +352,13 @@ internal static AadIssuerValidator GetAadIssuerValidator(string aadAuthority, Ht
305352
return s_issuerValidators[aadAuthority];
306353
}
307354

308-
private static string CreateV1Authority(string aadV2Authority)
355+
356+
private static string CreateV1Authority(string aadV2Authority, string suffixToReplace = V2EndpointSuffix)
309357
{
310-
if (aadV2Authority.Contains(AadIssuerValidatorConstants.Organizations))
311-
return aadV2Authority.Replace($"{AadIssuerValidatorConstants.Organizations}{V2EndpointSuffix}", AadIssuerValidatorConstants.Common);
358+
if (suffixToReplace == V2EndpointSuffix && aadV2Authority.Contains(AadIssuerValidatorConstants.Organizations))
359+
return aadV2Authority.Replace($"{AadIssuerValidatorConstants.Organizations}{suffixToReplace}", AadIssuerValidatorConstants.Common);
312360

313-
return aadV2Authority.Replace(V2EndpointSuffix, string.Empty);
361+
return aadV2Authority.Replace(suffixToReplace, string.Empty);
314362
}
315363

316364
private ConfigurationManager<OpenIdConnectConfiguration> CreateConfigManager(
@@ -350,23 +398,48 @@ private static bool IsValidIssuer(string validIssuerTemplate, string tenantId, s
350398
}
351399
}
352400

353-
private void SetEffectiveLKGIssuer(string aadIssuer, bool isV2Issuer, TimeSpan lastKnownGoodLifetime)
401+
private void SetEffectiveLKGIssuer(string aadIssuer, ProtocolVersion protocolVersion, TimeSpan lastKnownGoodLifetime)
354402
{
355403
var issuerLKG = new IssuerLastKnownGood
356404
{
357405
Issuer = aadIssuer,
358406
LastKnownGoodLifetime = lastKnownGoodLifetime
359407
};
360408

361-
if (isV2Issuer)
362-
_issuerLKGV2 = issuerLKG;
363-
else
364-
_issuerLKGV1 = issuerLKG;
409+
switch (protocolVersion)
410+
{
411+
case ProtocolVersion.V1:
412+
_issuerLKGV1 = issuerLKG;
413+
break;
414+
415+
case ProtocolVersion.V11:
416+
_issuerLKGV11 = issuerLKG;
417+
break;
418+
419+
case ProtocolVersion.V2:
420+
_issuerLKGV2 = issuerLKG;
421+
break;
422+
}
365423
}
366424

367-
private string GetEffectiveLKGIssuer(bool isV2Issuer)
425+
private string GetEffectiveLKGIssuer(ProtocolVersion protocolVersion)
368426
{
369-
var effectiveLKGIssuer = isV2Issuer ? _issuerLKGV2 : _issuerLKGV1;
427+
IssuerLastKnownGood effectiveLKGIssuer = null;
428+
switch (protocolVersion)
429+
{
430+
case ProtocolVersion.V1:
431+
effectiveLKGIssuer = _issuerLKGV1;
432+
break;
433+
434+
case ProtocolVersion.V11:
435+
effectiveLKGIssuer = _issuerLKGV11;
436+
break;
437+
438+
case ProtocolVersion.V2:
439+
effectiveLKGIssuer = _issuerLKGV2;
440+
break;
441+
}
442+
370443
if (effectiveLKGIssuer != null && effectiveLKGIssuer.IsValid)
371444
{
372445
return effectiveLKGIssuer.Issuer;
@@ -375,25 +448,80 @@ private string GetEffectiveLKGIssuer(bool isV2Issuer)
375448
return null;
376449
}
377450

378-
private static bool IsV2Issuer(SecurityToken securityToken)
451+
private static ProtocolVersion GetTokenIssuerVersion(SecurityToken securityToken)
379452
{
380-
return securityToken.Issuer.EndsWith(V2EndpointSuffixWithTrailingSlash, StringComparison.OrdinalIgnoreCase) ||
381-
securityToken.Issuer.EndsWith(V2EndpointSuffix, StringComparison.OrdinalIgnoreCase);
453+
if (securityToken.Issuer.EndsWith(V2EndpointSuffixWithTrailingSlash, StringComparison.OrdinalIgnoreCase) ||
454+
securityToken.Issuer.EndsWith(V2EndpointSuffix, StringComparison.OrdinalIgnoreCase))
455+
return ProtocolVersion.V2;
456+
457+
if (securityToken.Issuer.EndsWith(V11EndpointSuffixWithTrailingSlash, StringComparison.OrdinalIgnoreCase) ||
458+
securityToken.Issuer.EndsWith(V11EndpointSuffix, StringComparison.OrdinalIgnoreCase))
459+
return ProtocolVersion.V11;
460+
461+
return ProtocolVersion.V1;
382462
}
383463

384-
private BaseConfigurationManager GetEffectiveConfigurationManager(bool isV2Issuer)
464+
private BaseConfigurationManager GetEffectiveConfigurationManager(ProtocolVersion protocolVersion)
385465
{
386466
if (_configurationManagerProvider != null)
387467
{
388-
var aadAuthority = isV2Issuer ? AadAuthorityV2 : AadAuthorityV1;
389-
var configurationManager = _configurationManagerProvider(aadAuthority);
468+
string aadAuthority = GetAuthority(protocolVersion);
469+
390470

471+
var configurationManager = _configurationManagerProvider(aadAuthority);
391472
if (configurationManager != null)
392473
return configurationManager;
393474
}
394475

395-
// If no provider or provider returned null, fallback to previous strategy
396-
return isV2Issuer ? ConfigurationManagerV2 : ConfigurationManagerV1;
476+
// If no provider or provider returned null, fallback to previous strategy
477+
return GetConfigurationManager(protocolVersion);
478+
}
479+
480+
private BaseConfigurationManager GetConfigurationManager(ProtocolVersion protocolVersion)
481+
{
482+
switch (protocolVersion)
483+
{
484+
case ProtocolVersion.V1:
485+
return ConfigurationManagerV1;
486+
487+
case ProtocolVersion.V11:
488+
return ConfigurationManagerV11;
489+
490+
case ProtocolVersion.V2:
491+
return ConfigurationManagerV2;
492+
493+
default:
494+
return ConfigurationManagerV1;
495+
}
496+
}
497+
498+
private string GetAuthority(ProtocolVersion protocolVersion)
499+
{
500+
switch (protocolVersion)
501+
{
502+
case ProtocolVersion.V1:
503+
return AadAuthorityV1;
504+
505+
case ProtocolVersion.V11:
506+
return AadAuthorityV11;
507+
508+
case ProtocolVersion.V2:
509+
return AadAuthorityV2;
510+
511+
default:
512+
return AadAuthorityV1;
513+
}
514+
}
515+
516+
private static ProtocolVersion GetProtocolVersion(string aadAuthority)
517+
{
518+
if (aadAuthority.Contains(V2EndpointSuffix))
519+
return ProtocolVersion.V2;
520+
521+
if (aadAuthority.Contains(V11EndpointSuffix))
522+
return ProtocolVersion.V11;
523+
524+
return ProtocolVersion.V1;
397525
}
398526

399527
private static async Task<BaseConfiguration> GetBaseConfiguration(BaseConfigurationManager configurationManager, TokenValidationParameters validationParameters)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.IdentityModel.Validators
5+
{
6+
/// <summary>
7+
/// AAD protocol version.
8+
/// </summary>
9+
public enum ProtocolVersion
10+
{
11+
/// <summary>
12+
/// Protocol version 1.0
13+
/// </summary>
14+
V1,
15+
16+
/// <summary>
17+
/// Protocol version 1.1
18+
/// </summary>
19+
V11,
20+
21+
/// <summary>
22+
/// Protocol version 2.0
23+
/// </summary>
24+
V2
25+
}
26+
}

src/Microsoft.IdentityModel.Validators/GlobalSuppressions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Needs to be ignored", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.IsValidIssuer(System.String,System.String,System.String)~System.Boolean")]
99
#if NET6_0_OR_GREATER
10-
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.CreateV1Authority(System.String)~System.String")]
1110
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.IsValidIssuer(System.String,System.String,System.String)~System.Boolean")]
1211
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.#ctor(System.Net.Http.HttpClient,System.String)")]
12+
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.CreateV1Authority(System.String,System.String)~System.String")]
13+
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.GetProtocolVersion(System.String)~Microsoft.IdentityModel.Validators.AadIssuerValidator.ProtocolVersion")]
14+
[assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "Adding StringComparison.Ordinal adds a performance penalty.", Scope = "member", Target = "~M:Microsoft.IdentityModel.Validators.AadIssuerValidator.GetProtocolVersion(System.String)~Microsoft.IdentityModel.Validators.ProtocolVersion")]
1315
#endif
1416

0 commit comments

Comments
 (0)