Skip to content

Commit cc834d1

Browse files
authored
[Identity] Add multi-tenant live testing (#34257)
In the CI, there are credential envvars that correspond to a multi-tenant enabled application. Here live testing is provided for that along with corresponding recordings. Signed-off-by: Paul Van Eck <[email protected]>
1 parent eb99246 commit cc834d1

File tree

6 files changed

+105
-9
lines changed

6 files changed

+105
-9
lines changed

sdk/identity/azure-identity/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/identity/azure-identity",
5-
"Tag": "python/identity/azure-identity_ef8f51ecfd"
5+
"Tag": "python/identity/azure-identity_cb8dd6f319"
66
}

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@
77

88
from unittest import mock
99
import pytest
10-
from devtools_testutils import test_proxy, add_general_regex_sanitizer, is_live, add_body_key_sanitizer
10+
from devtools_testutils import (
11+
test_proxy,
12+
is_live,
13+
add_general_regex_sanitizer,
14+
add_body_key_sanitizer,
15+
add_header_regex_sanitizer,
16+
add_remove_header_sanitizer,
17+
set_custom_default_matcher,
18+
)
1119
from azure.identity._constants import DEVELOPER_SIGN_ON_CLIENT_ID, EnvironmentVariables
1220

1321
RECORD_IMDS = "--record-imds"
22+
TEST_ID = "00000000-0000-0000-0000-000000000000"
1423

1524

1625
def pytest_addoption(parser):
@@ -165,7 +174,11 @@ def event_loop():
165174

166175

167176
@pytest.fixture(scope="session", autouse=True)
168-
def add_sanitizers(test_proxy):
177+
def add_sanitizers(test_proxy, environment_variables):
178+
set_custom_default_matcher(
179+
excluded_headers="x-client-current-telemetry,x-client-last-telemetry,x-client-os,"
180+
"x-client-sku,x-client-ver,x-client-cpu,x-client-brkrver,x-ms-lib-capability" # cspell:ignore brkrver
181+
)
169182
if EnvironmentVariables.MSI_ENDPOINT in os.environ:
170183
url = os.environ.get(EnvironmentVariables.MSI_ENDPOINT)
171184
PLAYBACK_URL = "https://msi-endpoint/token"
@@ -190,6 +203,17 @@ def add_sanitizers(test_proxy):
190203
add_general_regex_sanitizer(regex=os.environ["OBO_USERNAME"], value="username")
191204
add_body_key_sanitizer(json_path="$..access_token", value="access_token")
192205

206+
# Multi-tenant environment variables sanitization
207+
sanitization_mapping = {
208+
"AZURE_IDENTITY_MULTI_TENANT_TENANT_ID": TEST_ID,
209+
"AZURE_IDENTITY_MULTI_TENANT_CLIENT_ID": TEST_ID,
210+
"AZURE_IDENTITY_MULTI_TENANT_CLIENT_SECRET": TEST_ID,
211+
}
212+
environment_variables.sanitize_batch(sanitization_mapping)
213+
add_header_regex_sanitizer(key="Set-Cookie", value="[set-cookie;]")
214+
add_remove_header_sanitizer(headers="Cookie")
215+
add_header_regex_sanitizer(key="client-request-id", value="sanitized")
216+
193217

194218
@pytest.fixture(scope="session", autouse=True)
195219
def patch_async_sleep():

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ def test_incomplete_configuration():
3434

3535

3636
@pytest.mark.parametrize(
37-
"credential_name,environment_variables",
37+
"credential_name,envvars",
3838
(
3939
("ClientSecretCredential", EnvironmentVariables.CLIENT_SECRET_VARS),
4040
("CertificateCredential", EnvironmentVariables.CERT_VARS),
4141
("UsernamePasswordCredential", EnvironmentVariables.USERNAME_PASSWORD_VARS),
4242
),
4343
)
44-
def test_passes_authority_argument(credential_name, environment_variables):
44+
def test_passes_authority_argument(credential_name, envvars):
4545
"""the credential pass the 'authority' keyword argument to its inner credential"""
4646

4747
authority = "authority"
4848

49-
with mock.patch.dict("os.environ", {variable: "foo" for variable in environment_variables}, clear=True):
49+
with mock.patch.dict("os.environ", {variable: "foo" for variable in envvars}, clear=True):
5050
with mock.patch(EnvironmentCredential.__module__ + "." + credential_name) as mock_credential:
5151
EnvironmentCredential(authority=authority)
5252

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,18 @@ async def test_incomplete_configuration():
7070

7171

7272
@pytest.mark.parametrize(
73-
"credential_name,environment_variables",
73+
"credential_name,envvars",
7474
(
7575
("ClientSecretCredential", EnvironmentVariables.CLIENT_SECRET_VARS),
7676
("CertificateCredential", EnvironmentVariables.CERT_VARS),
7777
),
7878
)
79-
def test_passes_authority_argument(credential_name, environment_variables):
79+
def test_passes_authority_argument(credential_name, envvars):
8080
"""the credential pass the 'authority' keyword argument to its inner credential"""
8181

8282
authority = "authority"
8383

84-
with mock.patch.dict(ENVIRON, {variable: "foo" for variable in environment_variables}, clear=True):
84+
with mock.patch.dict(ENVIRON, {variable: "foo" for variable in envvars}, clear=True):
8585
with mock.patch(EnvironmentCredential.__module__ + "." + credential_name) as mock_credential:
8686
EnvironmentCredential(authority=authority)
8787

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See LICENSE.txt in the project root for
4+
# license information.
5+
# -------------------------------------------------------------------------
6+
import os
7+
8+
import pytest
9+
from devtools_testutils import AzureRecordedTestCase, is_live
10+
from azure.core import PipelineClient
11+
from azure.core.rest import HttpRequest, HttpResponse
12+
from azure.identity import ClientSecretCredential
13+
14+
15+
class TestMultiTenantAuth(AzureRecordedTestCase):
16+
def _send_request(self, credential: ClientSecretCredential) -> HttpResponse:
17+
client = PipelineClient(base_url="https://graph.microsoft.com")
18+
token = credential.get_token("https://graph.microsoft.com/.default")
19+
headers = {"Authorization": "Bearer " + token.token, "ConsistencyLevel": "eventual"}
20+
request = HttpRequest("GET", "https://graph.microsoft.com/v1.0/applications/$count", headers=headers)
21+
response = client.send_request(request)
22+
return response
23+
24+
@pytest.mark.skipif(
25+
is_live() and not os.environ.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_ID"),
26+
reason="Multi-tenant envvars not configured.",
27+
)
28+
def test_multi_tenant_client_secret_graph_call(self, recorded_test, environment_variables):
29+
client_id = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_ID")
30+
tenant_id = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_TENANT_ID")
31+
client_secret = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_SECRET")
32+
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
33+
response = self._send_request(credential)
34+
assert response.status_code == 200
35+
assert int(response.text()) > 0
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See LICENSE.txt in the project root for
4+
# license information.
5+
# -------------------------------------------------------------------------
6+
import os
7+
8+
import pytest
9+
from devtools_testutils import AzureRecordedTestCase, is_live
10+
from azure.core import AsyncPipelineClient
11+
from azure.core.rest import HttpRequest, HttpResponse
12+
from azure.identity.aio import ClientSecretCredential
13+
14+
15+
class TestMultiTenantAuthAsync(AzureRecordedTestCase):
16+
async def _send_request(self, credential: ClientSecretCredential) -> HttpResponse:
17+
client = AsyncPipelineClient(base_url="https://graph.microsoft.com")
18+
token = await credential.get_token("https://graph.microsoft.com/.default")
19+
headers = {"Authorization": "Bearer " + token.token, "ConsistencyLevel": "eventual"}
20+
request = HttpRequest("GET", "https://graph.microsoft.com/v1.0/applications/$count", headers=headers)
21+
response = await client.send_request(request, stream=False)
22+
return response
23+
24+
@pytest.mark.asyncio
25+
@pytest.mark.skipif(
26+
is_live() and not os.environ.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_ID"),
27+
reason="Multi-tenant envvars not configured.",
28+
)
29+
async def test_multi_tenant_client_secret_graph_call(self, recorded_test, environment_variables):
30+
client_id = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_ID")
31+
tenant_id = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_TENANT_ID")
32+
client_secret = environment_variables.get("AZURE_IDENTITY_MULTI_TENANT_CLIENT_SECRET")
33+
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
34+
async with credential:
35+
response = await self._send_request(credential)
36+
assert response.status_code == 200
37+
assert int(response.text()) > 0

0 commit comments

Comments
 (0)