From 4c79c0e3584063598c159b2d057e94255800c6c2 Mon Sep 17 00:00:00 2001 From: Ron Date: Wed, 13 Jul 2022 15:05:24 -0700 Subject: [PATCH 01/11] Update azure_cli.py Updates the Azure CLI SDK To allow to create credential objects that are connected to tenants. This is EXTREMELY useful when you work with multiple tenants. --- .../azure/identity/aio/_credentials/azure_cli.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index 869cf5de69ae..c5e2d7cf47f4 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -32,6 +32,10 @@ class AzureCliCredential(AsyncContextManager): This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. """ + def __init__(self, tenant_id = None): + AsyncContextManager.__init__(self) + + self.tenant_id = tenant_id @log_get_token_async async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": @@ -55,7 +59,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant("", **kwargs) + tenant = resolve_tenant("", **kwargs) if self.tenant_id is None else resolve_tenant("", self.tenant_id, **kwargs) if tenant: command += " --tenant " + tenant output = await _run_command(command) From cba56372293e6ec82dbdda382a80fa647d1b84ae Mon Sep 17 00:00:00 2001 From: Ron Date: Wed, 13 Jul 2022 15:10:36 -0700 Subject: [PATCH 02/11] Update azure_cli.py --- .../azure-identity/azure/identity/aio/_credentials/azure_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index c5e2d7cf47f4..2be7633b9bb7 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -32,7 +32,7 @@ class AzureCliCredential(AsyncContextManager): This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. """ - def __init__(self, tenant_id = None): + def __init__(self, tenant_id: str = None): AsyncContextManager.__init__(self) self.tenant_id = tenant_id From 31956e3a68c9e0bd3ada97569d8f997ddc8aed6c Mon Sep 17 00:00:00 2001 From: Ron Date: Mon, 18 Jul 2022 11:50:58 -0700 Subject: [PATCH 03/11] Update azure_cli.py --- .../azure/identity/aio/_credentials/azure_cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index 2be7633b9bb7..dfe28776351f 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -59,7 +59,8 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant("", **kwargs) if self.tenant_id is None else resolve_tenant("", self.tenant_id, **kwargs) + tenant = resolve_tenant(default_tenant= "", **kwargs) if self.tenant_id is None else resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + if tenant: command += " --tenant " + tenant output = await _run_command(command) From efb9f7a8ede8e11c57cf1cbb115790c6bf13fb35 Mon Sep 17 00:00:00 2001 From: Ron Date: Mon, 18 Jul 2022 11:51:01 -0700 Subject: [PATCH 04/11] Update azure_cli.py --- .../azure/identity/_credentials/azure_cli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py index a94e001852ec..aaa805b3ce50 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -36,6 +36,10 @@ class AzureCliCredential(object): This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. """ + def __init__(self, tenant_id: str = None): + object.__init__(self) + + self.tenant_id = tenant_id def __enter__(self): return self @@ -67,7 +71,8 @@ def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant("", **kwargs) + tenant = resolve_tenant(default_tenant= "", **kwargs) if self.tenant_id is None else resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + if tenant: command += " --tenant " + tenant output = _run_command(command) From 20c49206ec67608df749c1134e9b7390b6b875fa Mon Sep 17 00:00:00 2001 From: Ron Date: Mon, 18 Jul 2022 12:04:42 -0700 Subject: [PATCH 05/11] Update test_cli_credential.py --- .../tests/test_cli_credential.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sdk/identity/azure-identity/tests/test_cli_credential.py b/sdk/identity/azure-identity/tests/test_cli_credential.py index 6eb71b97e722..1ed04ae3e0b8 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential.py @@ -152,6 +152,36 @@ def test_timeout(): AzureCliCredential().get_token("scope") +def test_multitenant_authentication_class(): + default_tenant = "first-tenant" + first_token = "***" + second_tenant = "second-tenant" + second_token = first_token * 2 + + def fake_check_output(command_line, **_): + match = re.search("--tenant (.*)", command_line[-1]) + tenant = match.groups()[0] if match else default_tenant + assert tenant in (default_tenant, second_tenant), 'unexpected tenant "{}"'.format(tenant) + return json.dumps( + { + "expiresOn": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), + "accessToken": first_token if tenant == default_tenant else second_token, + "subscription": "some-guid", + "tenant": tenant, + "tokenType": "Bearer", + } + ) + + with mock.patch(CHECK_OUTPUT, fake_check_output): + token = AzureCliCredential().get_token("scope") + assert token.token == first_token + + token = AzureCliCredential(tenant_id= default_tenant).get_token("scope") + assert token.token == first_token + + token = AzureCliCredential(tenant_id= second_tenant).get_token("scope") + assert token.token == second_token + def test_multitenant_authentication(): default_tenant = "first-tenant" first_token = "***" From 81a302e5b2a828d43ad7d32db3ce909a9b8d03c3 Mon Sep 17 00:00:00 2001 From: Ron Date: Mon, 18 Jul 2022 15:00:28 -0700 Subject: [PATCH 06/11] Update azure_cli.py --- .../azure-identity/azure/identity/_credentials/azure_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py index aaa805b3ce50..0221e7c55c97 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -71,7 +71,7 @@ def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant(default_tenant= "", **kwargs) if self.tenant_id is None else resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + tenant = resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) if tenant: command += " --tenant " + tenant From 392cf61c888753265c626518cf65661e8160ba8e Mon Sep 17 00:00:00 2001 From: Ron Date: Mon, 18 Jul 2022 15:00:54 -0700 Subject: [PATCH 07/11] Update azure_cli.py --- .../azure-identity/azure/identity/aio/_credentials/azure_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index dfe28776351f..8d1c8732c6ed 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -59,7 +59,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant(default_tenant= "", **kwargs) if self.tenant_id is None else resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + tenant = resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) if tenant: command += " --tenant " + tenant From 7ca8ca62f32a4540a0d27cad3783511c3b36fc0e Mon Sep 17 00:00:00 2001 From: Ron Date: Tue, 19 Jul 2022 12:16:10 -0700 Subject: [PATCH 08/11] Update azure_cli.py --- .../azure-identity/azure/identity/_credentials/azure_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py index 0221e7c55c97..9f40d2dd541a 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -36,7 +36,7 @@ class AzureCliCredential(object): This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. """ - def __init__(self, tenant_id: str = None): + def __init__(self, tenant_id: str = ""): object.__init__(self) self.tenant_id = tenant_id @@ -71,7 +71,7 @@ def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + tenant = resolve_tenant(default_tenant= self.tenant_id, **kwargs) if tenant: command += " --tenant " + tenant From f1350a09ad6f5b2d2601ae52386e1dc5340f77e1 Mon Sep 17 00:00:00 2001 From: Ron Date: Tue, 19 Jul 2022 12:16:49 -0700 Subject: [PATCH 09/11] Update azure_cli.py --- .../azure/identity/aio/_credentials/azure_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index 8d1c8732c6ed..f36872aab02a 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -32,7 +32,7 @@ class AzureCliCredential(AsyncContextManager): This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. """ - def __init__(self, tenant_id: str = None): + def __init__(self, tenant_id: str = ""): AsyncContextManager.__init__(self) self.tenant_id = tenant_id @@ -59,7 +59,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant(default_tenant= "", tenant_id= self.tenant_id, **kwargs) + tenant = resolve_tenant(default_tenant= self.tenant_id, **kwargs) if tenant: command += " --tenant " + tenant From 4e948406c52ace4561b258cd5212b7dd2182ee98 Mon Sep 17 00:00:00 2001 From: Ron Date: Fri, 22 Jul 2022 12:20:29 -0700 Subject: [PATCH 10/11] Update azure_cli.py --- .../azure-identity/azure/identity/_credentials/azure_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py index 9f40d2dd541a..e443fc8fea53 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -72,7 +72,7 @@ def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) tenant = resolve_tenant(default_tenant= self.tenant_id, **kwargs) - + if tenant: command += " --tenant " + tenant output = _run_command(command) From 8e0bab861d83a564b637781f18b0b4fd8af7d13f Mon Sep 17 00:00:00 2001 From: Ron Date: Fri, 22 Jul 2022 12:20:58 -0700 Subject: [PATCH 11/11] Update azure_cli.py --- .../azure-identity/azure/identity/aio/_credentials/azure_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index f36872aab02a..33ee4f5cac96 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -60,7 +60,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) tenant = resolve_tenant(default_tenant= self.tenant_id, **kwargs) - + if tenant: command += " --tenant " + tenant output = await _run_command(command)