Skip to content

Commit ce9d767

Browse files
authored
[Identity] Update tenant resolution logic (#42721)
* [Identity] Update tenant resolution logic Our tenant resolution logic shouldn't error out requests for certain dev credentials (e.g. `DeviceCodeCredential and `InteractiveBrowserCredential`) if a tenant is passed into `get_token` or `get_token_info`. This happens if the no tenant was configured on the credential and the default "organizations" tenant is used. Signed-off-by: Paul Van Eck <[email protected]> * Update changelog Signed-off-by: Paul Van Eck <[email protected]> --------- Signed-off-by: Paul Van Eck <[email protected]>
1 parent b0806db commit ce9d767

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
### Bugs Fixed
1313

1414
- Fixed an issue where `AzureDeveloperCliCredential` would time out during token requests when `azd` prompts for user interaction. This issue commonly occurred in environments where the `AZD_DEBUG` environment variable was set, causing the Azure Developer CLI to display additional prompts that interfered with automated token acquisition. ([#42535](https://github.com/Azure/azure-sdk-for-python/pull/42535))
15+
- Fixed an issue where credentials configured with a default tenant ID of "organizations" (such as `InteractiveBrowserCredential` and `DeviceCodeCredential`) would fail authentication when a specific tenant ID was provided in `get_token` or `get_token_info` method calls. ([#42721](https://github.com/Azure/azure-sdk-for-python/pull/42721))
1516

1617
### Other Changes
1718

sdk/identity/azure-identity/azure/identity/_internal/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ def resolve_tenant(
128128
tenant_id,
129129
)
130130
return tenant_id
131+
# Some dev credentials commonly default to the "organizations" special tenant which can authenticate users against
132+
# multiple tenants that the user belongs to. If an allowed tenant list was not provided and the credential's
133+
# tenant is set to 'organizations', allow the request with the specified tenant ID.
134+
if not additionally_allowed_tenants and default_tenant == "organizations":
135+
return tenant_id
131136
raise ClientAuthenticationError(
132137
message="The current credential is not configured to acquire tokens for tenant {}. "
133138
"To enable acquiring tokens for this tenant add it to the additionally_allowed_tenants "

sdk/identity/azure-identity/tests/test_device_code_credential.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ def test_device_code_credential(get_token_method):
236236
@pytest.mark.parametrize("get_token_method", GET_TOKEN_METHODS)
237237
def test_tenant_id(get_token_method):
238238
client_id = "client-id"
239+
tenant_id = "tenant-id"
239240
expected_token = "access-token"
240241
user_code = "user-code"
241242
verification_uri = "verification-uri"
@@ -271,12 +272,64 @@ def test_tenant_id(get_token_method):
271272
callback = Mock()
272273
credential = DeviceCodeCredential(
273274
client_id=client_id,
275+
tenant_id=tenant_id,
274276
prompt_callback=callback,
275277
transport=transport,
276278
disable_instance_discovery=True,
277279
additionally_allowed_tenants=["*"],
278280
)
279281

282+
kwargs = {"tenant_id": "tenant-id-2"}
283+
if get_token_method == "get_token_info":
284+
kwargs = {"options": kwargs}
285+
token = getattr(credential, get_token_method)("scope", **kwargs)
286+
assert token.token == expected_token
287+
288+
289+
@pytest.mark.parametrize("get_token_method", GET_TOKEN_METHODS)
290+
def test_default_tenant_id(get_token_method):
291+
"""If no tenant_id is provided, token request tenants should be allowed"""
292+
client_id = "client-id"
293+
expected_token = "access-token"
294+
user_code = "user-code"
295+
verification_uri = "verification-uri"
296+
expires_in = 42
297+
298+
transport = validating_transport(
299+
requests=[Request()] * 3, # not validating requests because they're formed by MSAL
300+
responses=[
301+
# expected requests: discover tenant, start device code flow, poll for completion
302+
get_discovery_response(),
303+
mock_response(
304+
json_payload={
305+
"device_code": "_",
306+
"user_code": user_code,
307+
"verification_uri": verification_uri,
308+
"expires_in": expires_in,
309+
}
310+
),
311+
mock_response(
312+
json_payload=dict(
313+
build_aad_response(
314+
access_token=expected_token,
315+
expires_in=expires_in,
316+
refresh_token="_",
317+
id_token=build_id_token(aud=client_id),
318+
),
319+
scope="scope",
320+
),
321+
),
322+
],
323+
)
324+
325+
callback = Mock()
326+
credential = DeviceCodeCredential(
327+
client_id=client_id,
328+
prompt_callback=callback,
329+
transport=transport,
330+
disable_instance_discovery=True,
331+
)
332+
280333
kwargs = {"tenant_id": "tenant_id"}
281334
if get_token_method == "get_token_info":
282335
kwargs = {"options": kwargs}

0 commit comments

Comments
 (0)