Skip to content

Commit c3d443c

Browse files
authored
Ensure TenantIdResolver performs case-insensitive tenant ID comparisons (#51694)
1 parent a91286e commit c3d443c

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
### Bugs Fixed
1919

20+
- Tenant ID comparisons in credential options are now case-insensitive. This affects `AdditionallyAllowedTenants` values which will now be matched against tenant IDs without case sensitivity, making the authentication more resilient to case differences in tenant IDs returned from WWW-Authenticate challenges ([#51693](https://github.com/Azure/azure-sdk-for-net/issues/51693)).
21+
2022
### Other Changes
2123

2224
- Added the `EditorBrowsable(Never)` attribute to property `VisualStudioCodeTenantId` as `TenantId` is preferred. The `VisualStudioCodeTenantId` property exists only to provide backwards compatibility.

sdk/identity/Azure.Identity/src/TenantIdResolver.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ public override string Resolve(string explicitTenantId, TokenRequestContext cont
2121
{
2222
bool disableMultiTenantAuth = IdentityCompatSwitches.DisableTenantDiscovery;
2323

24-
if (context.TenantId != explicitTenantId && context.TenantId != null && explicitTenantId != null)
24+
if (!string.Equals(context.TenantId, explicitTenantId, StringComparison.OrdinalIgnoreCase) && context.TenantId != null && explicitTenantId != null)
2525
{
26-
if (disableMultiTenantAuth || explicitTenantId == Constants.AdfsTenantId)
26+
if (disableMultiTenantAuth || string.Equals(explicitTenantId, Constants.AdfsTenantId, StringComparison.OrdinalIgnoreCase))
2727
{
2828
AzureIdentityEventSource.Singleton.TenantIdDiscoveredAndNotUsed(explicitTenantId, context.TenantId);
2929
}
@@ -36,11 +36,11 @@ public override string Resolve(string explicitTenantId, TokenRequestContext cont
3636
string resolvedTenantId = disableMultiTenantAuth switch
3737
{
3838
true => explicitTenantId,
39-
false when explicitTenantId == Constants.AdfsTenantId => explicitTenantId,
39+
false when string.Equals(explicitTenantId, Constants.AdfsTenantId, StringComparison.OrdinalIgnoreCase) => explicitTenantId,
4040
_ => context.TenantId ?? explicitTenantId
4141
};
4242

43-
if (explicitTenantId != null && resolvedTenantId != explicitTenantId && additionallyAllowedTenantIds != AllTenants && Array.BinarySearch(additionallyAllowedTenantIds, resolvedTenantId, StringComparer.OrdinalIgnoreCase) < 0)
43+
if (explicitTenantId != null && !string.Equals(resolvedTenantId, explicitTenantId, StringComparison.OrdinalIgnoreCase) && additionallyAllowedTenantIds != AllTenants && Array.BinarySearch(additionallyAllowedTenantIds, resolvedTenantId, StringComparer.OrdinalIgnoreCase) < 0)
4444
{
4545
throw new AuthenticationFailedException($"The current credential is not configured to acquire tokens for tenant {resolvedTenantId}. To enable acquiring tokens for this tenant add it to the AdditionallyAllowedTenants on the credential options, or add \"*\" to AdditionallyAllowedTenants to allow acquiring tokens for any tenant. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/multitenant/troubleshoot");
4646
}

sdk/identity/Azure.Identity/tests/TenantIdResolverTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,64 @@ public static void AssertAllowedTenantIdsEnforcedAsync(string tenantId, TokenReq
109109
StringAssert.Contains($"The current credential is not configured to acquire tokens for tenant {tokenRequestContext.TenantId}", ex.Message);
110110
}
111111
}
112+
113+
[Test]
114+
public void ResolveWithCaseInsensitiveTenantIdComparison()
115+
{
116+
const string upperCaseTenantId = "CLIENT-TENANT";
117+
const string lowerCaseTenantId = "client-tenant";
118+
const string mixedCaseTenantId = "Client-Tenant";
119+
120+
var contextWithUpperCase = new TokenRequestContext(Array.Empty<string>(), tenantId: upperCaseTenantId);
121+
var contextWithLowerCase = new TokenRequestContext(Array.Empty<string>(), tenantId: lowerCaseTenantId);
122+
var contextWithMixedCase = new TokenRequestContext(Array.Empty<string>(), tenantId: mixedCaseTenantId);
123+
124+
// Test that different case variations of the same tenant ID are considered equal
125+
var result1 = TenantIdResolverBase.Default.Resolve(lowerCaseTenantId, contextWithUpperCase, TenantIdResolverBase.AllTenants);
126+
var result2 = TenantIdResolverBase.Default.Resolve(upperCaseTenantId, contextWithLowerCase, TenantIdResolverBase.AllTenants);
127+
var result3 = TenantIdResolverBase.Default.Resolve(mixedCaseTenantId, contextWithLowerCase, TenantIdResolverBase.AllTenants);
128+
129+
// All should resolve to the context tenant ID as that takes precedence
130+
Assert.AreEqual(upperCaseTenantId, result1);
131+
Assert.AreEqual(lowerCaseTenantId, result2);
132+
Assert.AreEqual(lowerCaseTenantId, result3);
133+
}
134+
135+
[Test]
136+
public void ResolveWithCaseInsensitiveAdfsTenantId()
137+
{
138+
const string upperCaseAdfs = "ADFS";
139+
const string mixedCaseAdfs = "Adfs";
140+
const string lowerCaseAdfs = "adfs";
141+
142+
var contextWithHint = new TokenRequestContext(Array.Empty<string>(), tenantId: "some-hint");
143+
144+
// Test that different case variations of ADFS are all recognized
145+
var result1 = TenantIdResolverBase.Default.Resolve(upperCaseAdfs, contextWithHint, TenantIdResolverBase.AllTenants);
146+
var result2 = TenantIdResolverBase.Default.Resolve(mixedCaseAdfs, contextWithHint, TenantIdResolverBase.AllTenants);
147+
var result3 = TenantIdResolverBase.Default.Resolve(lowerCaseAdfs, contextWithHint, TenantIdResolverBase.AllTenants);
148+
149+
// For ADFS, the explicit tenant ID should be returned regardless of case
150+
Assert.AreEqual(upperCaseAdfs, result1);
151+
Assert.AreEqual(mixedCaseAdfs, result2);
152+
Assert.AreEqual(lowerCaseAdfs, result3);
153+
}
154+
155+
[Test]
156+
public void ResolveWithCaseInsensitiveComparisonForAllowedTenants()
157+
{
158+
const string explicitTenantId = "explicit-tenant";
159+
const string upperCaseContextTenant = "CONTEXT-TENANT";
160+
const string lowerCaseContextTenant = "context-tenant";
161+
162+
var contextWithUpperCase = new TokenRequestContext(Array.Empty<string>(), tenantId: upperCaseContextTenant);
163+
var additionallyAllowedTenants = new[] { lowerCaseContextTenant };
164+
165+
// The context tenant ID (uppercase) should be allowed because it matches
166+
// the additionally allowed tenant (lowercase) in a case-insensitive manner
167+
var result = TenantIdResolverBase.Default.Resolve(explicitTenantId, contextWithUpperCase, additionallyAllowedTenants);
168+
169+
Assert.AreEqual(upperCaseContextTenant, result);
170+
}
112171
}
113172
}

0 commit comments

Comments
 (0)