From 01d0b99e53a1995b39e59649bf3d550dc5408875 Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Fri, 1 Oct 2021 13:20:37 -0700 Subject: [PATCH] Update Multi-Tenant support to incorporate Arch Board Feedback (#20940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Multi-Tenant support to incorporate Arch Board Feedback * update * update * updates * update * update * updates * update * update * update * Update sdk/identity/azure-identity/CHANGELOG.md Co-authored-by: McCoy Patiño <39780829+mccoyp@users.noreply.github.com> Co-authored-by: McCoy Patiño <39780829+mccoyp@users.noreply.github.com> --- sdk/identity/azure-identity/CHANGELOG.md | 12 +- .../azure-identity/azure/identity/__init__.py | 2 - .../azure/identity/_constants.py | 2 +- .../identity/_credentials/application.py | 4 - .../_credentials/authorization_code.py | 6 +- .../azure/identity/_credentials/azure_cli.py | 14 +- .../identity/_credentials/azure_powershell.py | 15 +- .../azure/identity/_credentials/browser.py | 3 - .../identity/_credentials/certificate.py | 6 - .../identity/_credentials/client_secret.py | 6 - .../azure/identity/_credentials/default.py | 10 +- .../identity/_credentials/device_code.py | 3 - .../identity/_credentials/environment.py | 7 +- .../identity/_credentials/on_behalf_of.py | 3 - .../identity/_credentials/shared_cache.py | 4 - .../azure/identity/_credentials/silent.py | 3 +- .../identity/_credentials/user_password.py | 3 - .../azure/identity/_credentials/vscode.py | 3 - .../azure/identity/_internal/__init__.py | 15 +- .../identity/_internal/aad_client_base.py | 9 +- .../identity/_internal/get_token_mixin.py | 3 +- .../azure/identity/_internal/interactive.py | 3 +- .../identity/_internal/msal_credentials.py | 8 +- .../identity/aio/_credentials/application.py | 4 - .../aio/_credentials/authorization_code.py | 6 +- .../identity/aio/_credentials/azure_cli.py | 12 +- .../aio/_credentials/azure_powershell.py | 12 +- .../identity/aio/_credentials/certificate.py | 3 - .../aio/_credentials/client_secret.py | 3 - .../identity/aio/_credentials/default.py | 10 +- .../identity/aio/_credentials/environment.py | 7 +- .../identity/aio/_credentials/on_behalf_of.py | 5 +- .../identity/aio/_credentials/shared_cache.py | 6 +- .../azure/identity/aio/_credentials/vscode.py | 6 +- .../identity/aio/_internal/get_token_mixin.py | 3 +- .../azure-identity/tests/test_aad_client.py | 6 +- .../tests/test_aad_client_async.py | 6 +- .../azure-identity/tests/test_auth_code.py | 19 +-- .../tests/test_auth_code_async.py | 19 +-- .../tests/test_certificate_credential.py | 33 +--- .../test_certificate_credential_async.py | 19 +-- .../tests/test_cli_credential.py | 20 +-- .../tests/test_cli_credential_async.py | 20 +-- .../tests/test_client_secret_credential.py | 33 +--- .../test_client_secret_credential_async.py | 20 +-- .../azure-identity/tests/test_default.py | 30 ---- .../tests/test_default_async.py | 27 --- .../tests/test_interactive_credential.py | 18 +- sdk/identity/azure-identity/tests/test_obo.py | 6 +- .../azure-identity/tests/test_obo_async.py | 6 +- .../tests/test_powershell_credential.py | 20 +-- .../tests/test_powershell_credential_async.py | 20 +-- .../tests/test_shared_cache_credential.py | 154 +++++------------- .../test_shared_cache_credential_async.py | 19 +-- .../tests/test_vscode_credential.py | 20 +-- .../tests/test_vscode_credential_async.py | 20 +-- 56 files changed, 157 insertions(+), 599 deletions(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 49c726f3f0a2..64847d7e5a20 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -2,13 +2,15 @@ ## 1.7.0b5 (Unreleased) -### Features Added - ### Breaking Changes +> These changes do not impact the API of stable versions such as 1.6.0. +> Only code written against a beta version such as 1.7.0b1 may be affected. -### Bugs Fixed - -### Other Changes +- The `allow_multitenant_authentication` argument has been removed and the default behavior is now as if it were true. + The multitenant authentication feature can be totally disabled by setting the environment variable + `AZURE_IDENTITY_DISABLE_MULTITENANTAUTH` to `True`. +- `azure.identity.RegionalAuthority` is removed. +- `regional_authority` argument is removed for `CertificateCredential` and `ClientSecretCredential` ## 1.7.0b4 (2021-09-09) diff --git a/sdk/identity/azure-identity/azure/identity/__init__.py b/sdk/identity/azure-identity/azure/identity/__init__.py index 4d7dff365695..0969ad2e0504 100644 --- a/sdk/identity/azure-identity/azure/identity/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/__init__.py @@ -5,7 +5,6 @@ """Credentials for Azure SDK clients.""" from ._auth_record import AuthenticationRecord -from ._enums import RegionalAuthority from ._exceptions import AuthenticationRequiredError, CredentialUnavailableError from ._constants import AzureAuthorityHosts, KnownAuthorities from ._credentials import ( @@ -47,7 +46,6 @@ "InteractiveBrowserCredential", "KnownAuthorities", "OnBehalfOfCredential", - "RegionalAuthority", "ManagedIdentityCredential", "SharedTokenCacheCredential", "TokenCachePersistenceOptions", diff --git a/sdk/identity/azure-identity/azure/identity/_constants.py b/sdk/identity/azure-identity/azure/identity/_constants.py index 878d7f6bce7f..4cf9fb2d9287 100644 --- a/sdk/identity/azure-identity/azure/identity/_constants.py +++ b/sdk/identity/azure-identity/azure/identity/_constants.py @@ -44,7 +44,7 @@ class EnvironmentVariables: MSI_SECRET = "MSI_SECRET" AZURE_AUTHORITY_HOST = "AZURE_AUTHORITY_HOST" - AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION = "AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION" + AZURE_IDENTITY_DISABLE_MULTITENANTAUTH = "AZURE_IDENTITY_DISABLE_MULTITENANTAUTH" AZURE_REGIONAL_AUTHORITY_NAME = "AZURE_REGIONAL_AUTHORITY_NAME" AZURE_FEDERATED_TOKEN_FILE = "AZURE_FEDERATED_TOKEN_FILE" diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/application.py b/sdk/identity/azure-identity/azure/identity/_credentials/application.py index 46a84e13eb7b..abb22fbaabac 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/application.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/application.py @@ -48,10 +48,6 @@ class AzureApplicationCredential(ChainedTokenCredential): `_ for an overview of managed identities. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application or user is registered in. When False, which is the default, the credential will acquire tokens - only from the tenant specified by **AZURE_TENANT_ID**. This argument doesn't apply to managed identity - authentication. :keyword str authority: Authority of an Azure Active Directory endpoint, for example "login.microsoftonline.com", the authority for Azure Public Cloud, which is the default when no value is given for this keyword argument or environment variable AZURE_AUTHORITY_HOST. :class:`~azure.identity.AzureAuthorityHosts` defines authorities for diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/authorization_code.py b/sdk/identity/azure-identity/azure/identity/_credentials/authorization_code.py index 587547640744..7eae087b837c 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/authorization_code.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/authorization_code.py @@ -30,9 +30,6 @@ class AuthorizationCodeCredential(GetTokenMixin): the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. :keyword str client_secret: One of the application's client secrets. Required only for web apps and web APIs. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant specified by **tenant_id**. """ def __init__(self, tenant_id, client_id, authorization_code, redirect_uri, **kwargs): @@ -67,8 +64,7 @@ def get_token(self, *scopes, **kwargs): redeeming the authorization code. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` :raises ~azure.core.exceptions.ClientAuthenticationError: authentication failed. The error's ``message`` 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 d535a286adb7..a94e001852ec 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -35,15 +35,8 @@ class AzureCliCredential(object): """Authenticates by requesting a token from the Azure CLI. This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the identity logged in to the Azure CLI is registered in. When False, which is the default, the credential will - acquire tokens only from the tenant of the Azure CLI's active subscription. """ - def __init__(self, **kwargs): - self._allow_multitenant = kwargs.get("allow_multitenant_authentication", False) - def __enter__(self): return self @@ -55,7 +48,7 @@ def close(self): """Calling this method is unnecessary.""" @log_get_token("AzureCliCredential") - def get_token(self, *scopes, **kwargs): + def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use # type: (*str, **Any) -> AccessToken """Request an access token for `scopes`. @@ -63,8 +56,7 @@ def get_token(self, *scopes, **kwargs): also handle token caching because this credential doesn't cache the tokens it acquires. :param str scopes: desired scope for the access token. This credential allows only one scope per request. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` @@ -75,7 +67,7 @@ def get_token(self, *scopes, **kwargs): resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant("", self._allow_multitenant, **kwargs) + tenant = resolve_tenant("", **kwargs) if tenant: command += " --tenant " + tenant output = _run_command(command) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_powershell.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_powershell.py index 17869fbde253..78c34b81d76e 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_powershell.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_powershell.py @@ -51,16 +51,8 @@ class AzurePowerShellCredential(object): """Authenticates by requesting a token from Azure PowerShell. This requires previously logging in to Azure via "Connect-AzAccount", and will use the currently logged in identity. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the identity logged in to Azure PowerShell is registered in. When False, which is the default, the credential - will acquire tokens only from the tenant of Azure PowerShell's active subscription. """ - def __init__(self, **kwargs): - # type: (**Any) -> None - self._allow_multitenant = kwargs.get("allow_multitenant_authentication", False) - def __enter__(self): return self @@ -72,7 +64,7 @@ def close(self): """Calling this method is unnecessary.""" @log_get_token("AzurePowerShellCredential") - def get_token(self, *scopes, **kwargs): + def get_token(self, *scopes, **kwargs): # pylint: disable=no-self-use # type: (*str, **Any) -> AccessToken """Request an access token for `scopes`. @@ -80,8 +72,7 @@ def get_token(self, *scopes, **kwargs): also handle token caching because this credential doesn't cache the tokens it acquires. :param str scopes: desired scope for the access token. This credential allows only one scope per request. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` @@ -90,7 +81,7 @@ def get_token(self, *scopes, **kwargs): :raises ~azure.core.exceptions.ClientAuthenticationError: the credential invoked Azure PowerShell but didn't receive an access token """ - tenant_id = resolve_tenant("", self._allow_multitenant, **kwargs) + tenant_id = resolve_tenant("", **kwargs) command_line = get_command_line(scopes, tenant_id) output = run_command_line(command_line) token = parse_token(output) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py index 6aead5b26f47..5b624046a7ac 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py @@ -51,9 +51,6 @@ class InteractiveBrowserCredential(InteractiveCredential): will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions :keyword int timeout: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes). - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant specified by **tenant_id**. :raises ValueError: invalid **redirect_uri** """ diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py b/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py index cdb999d41898..1169fb178942 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py @@ -39,18 +39,12 @@ class CertificateCredential(ClientCredentialBase): :keyword password: The certificate's password. If a unicode string, it will be encoded as UTF-8. If the certificate requires a different encoding, pass appropriately encoded bytes instead. :paramtype password: str or bytes - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - the tenant specified by **tenant_id**. :keyword bool send_certificate_chain: if True, the credential will send the public certificate chain in the x5c header of each token request's JWT. This is required for Subject Name/Issuer (SNI) authentication. Defaults to False. :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword ~azure.identity.RegionalAuthority regional_authority: a :class:`~azure.identity.RegionalAuthority` to - which the credential will authenticate. This argument should be used only by applications deployed to Azure - VMs. """ def __init__(self, tenant_id, client_id, certificate_path=None, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py b/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py index 9623b0ef8b1d..4b68e401a023 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py @@ -21,15 +21,9 @@ class ClientSecretCredential(ClientCredentialBase): :keyword str authority: Authority of an Azure Active Directory endpoint, for example "login.microsoftonline.com", the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - the tenant specified by **tenant_id**. :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword ~azure.identity.RegionalAuthority regional_authority: a :class:`~azure.identity.RegionalAuthority` to - which the credential will authenticate. This argument should be used only by applications deployed to Azure - VMs. """ def __init__(self, tenant_id, client_id, client_secret, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/_credentials/default.py index 90ddc1b39b53..75c2111362bb 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/default.py @@ -47,9 +47,6 @@ class DefaultAzureCredential(ChainedTokenCredential): This default behavior is configurable with keyword arguments. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - its configured tenant. This argument doesn't apply to managed identity authentication. :keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com', the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. Managed identities ignore this because they reside in a single cloud. @@ -136,9 +133,9 @@ def __init__(self, **kwargs): if not exclude_visual_studio_code_credential: credentials.append(VisualStudioCodeCredential(**vscode_args)) if not exclude_cli_credential: - credentials.append(AzureCliCredential(**kwargs)) + credentials.append(AzureCliCredential()) if not exclude_powershell_credential: - credentials.append(AzurePowerShellCredential(**kwargs)) + credentials.append(AzurePowerShellCredential()) if not exclude_interactive_browser_credential: if interactive_browser_client_id: credentials.append( @@ -158,8 +155,7 @@ def get_token(self, *scopes, **kwargs): This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/device_code.py b/sdk/identity/azure-identity/azure/identity/_credentials/device_code.py index 657bd5eb5568..e5af7b89c8d1 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/device_code.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/device_code.py @@ -55,9 +55,6 @@ class DeviceCodeCredential(InteractiveCredential): :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant specified by **tenant_id**. """ def __init__(self, client_id=DEVELOPER_SIGN_ON_CLIENT_ID, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/environment.py b/sdk/identity/azure-identity/azure/identity/_credentials/environment.py index 8d0e7401d8b2..d2b134d11e9e 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/environment.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/environment.py @@ -52,10 +52,6 @@ class EnvironmentCredential(object): - **AZURE_TENANT_ID**: (optional) ID of the service principal's tenant. Also called its 'directory' ID. If not provided, defaults to the 'organizations' tenant, which supports only Azure Active Directory work or school accounts. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application or user is registered in. When False, which is the default, the credential will acquire tokens - only from the tenant specified by **AZURE_TENANT_ID**. """ def __init__(self, **kwargs): @@ -123,8 +119,7 @@ def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/on_behalf_of.py b/sdk/identity/azure-identity/azure/identity/_credentials/on_behalf_of.py index bc39c7a475e1..70f3c407ca16 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/on_behalf_of.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/on_behalf_of.py @@ -39,9 +39,6 @@ class OnBehalfOfCredential(MsalCredential, GetTokenMixin): :param str user_assertion: the access token the credential will use as the user assertion when requesting on-behalf-of tokens - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only - from the tenant specified by **tenant_id**. :keyword str authority: Authority of an Azure Active Directory endpoint, for example "login.microsoftonline.com", the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/shared_cache.py b/sdk/identity/azure-identity/azure/identity/_credentials/shared_cache.py index 906aaad174fc..3cef36e80507 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/shared_cache.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/shared_cache.py @@ -34,10 +34,6 @@ class SharedTokenCacheCredential(object): :keyword cache_persistence_options: configuration for persistent token caching. If not provided, the credential will use the persistent cache shared by Microsoft development applications :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or, if a value was given for **authentication_record**, the tenant specified by the - :class:`AuthenticationRecord`. """ def __init__(self, username=None, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/silent.py b/sdk/identity/azure-identity/azure/identity/_credentials/silent.py index b1aa1ade8c46..08e0611fa5e4 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/silent.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/silent.py @@ -35,7 +35,6 @@ def __init__(self, authentication_record, **kwargs): # authenticate in the tenant that produced the record unless "tenant_id" specifies another self._tenant_id = kwargs.pop("tenant_id", None) or self._auth_record.tenant_id validate_tenant_id(self._tenant_id) - self._allow_multitenant = kwargs.pop("allow_multitenant_authentication", False) self._cache = kwargs.pop("_cache", None) self._client_applications = {} # type: Dict[str, PublicClientApplication] self._client = MsalClient(**kwargs) @@ -74,7 +73,7 @@ def _initialize(self): self._initialized = True def _get_client_application(self, **kwargs): - tenant_id = resolve_tenant(self._tenant_id, self._allow_multitenant, **kwargs) + tenant_id = resolve_tenant(self._tenant_id, **kwargs) if tenant_id not in self._client_applications: # CP1 = can handle claims challenges (CAE) capabilities = None if "AZURE_IDENTITY_DISABLE_CP1" in os.environ else ["CP1"] diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/user_password.py b/sdk/identity/azure-identity/azure/identity/_credentials/user_password.py index 77281a185e6e..0521e8fa42d6 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/user_password.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/user_password.py @@ -37,9 +37,6 @@ class UsernamePasswordCredential(InteractiveCredential): :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant specified by **tenant_id**. """ def __init__(self, client_id, username, password, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/vscode.py b/sdk/identity/azure-identity/azure/identity/_credentials/vscode.py index cd6866f319da..a66dc9d234a9 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/vscode.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/vscode.py @@ -120,9 +120,6 @@ class VisualStudioCodeCredential(_VSCodeCredentialBase, GetTokenMixin): :keyword str tenant_id: ID of the tenant the credential should authenticate in. Defaults to the "Azure: Tenant" setting in VS Code's user settings or, when that setting has no value, the "organizations" tenant, which supports only Azure Active Directory work or school accounts. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant configured by **tenant_id** or VS Code's user settings. """ def __enter__(self): diff --git a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py index a1799b0679a8..d9c7203734a5 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py @@ -7,8 +7,6 @@ from six.moves.urllib_parse import urlparse -from azure.core.exceptions import ClientAuthenticationError - from .._constants import EnvironmentVariables, KnownAuthorities if TYPE_CHECKING: @@ -66,21 +64,16 @@ def validate_tenant_id(tenant_id): ) -def resolve_tenant(default_tenant, allow_multitenant, tenant_id=None, **_): - # type: (str, bool, Optional[str], **Any) -> str +def resolve_tenant(default_tenant, tenant_id=None, **_): + # type: (str, Optional[str], **Any) -> str """Returns the correct tenant for a token request given a credential's configuration""" if ( tenant_id is None - or tenant_id == default_tenant - or os.environ.get(EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION) + or default_tenant == "adfs" + or os.environ.get(EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH) ): return default_tenant - if not allow_multitenant: - raise ClientAuthenticationError( - 'The specified tenant for this token request, "{}", does not match'.format(tenant_id) - + ' the configured tenant, and "allow_multitenant_authentication" is False.' - ) return tenant_id diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py index b6a44e8d5681..f33cf40ce227 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py @@ -47,13 +47,12 @@ class AadClientBase(ABC): _POST = ["POST"] def __init__( - self, tenant_id, client_id, authority=None, cache=None, allow_multitenant_authentication=False, **kwargs + self, tenant_id, client_id, authority=None, cache=None, **kwargs ): - # type: (str, str, Optional[str], Optional[TokenCache], bool, **Any) -> None + # type: (str, str, Optional[str], Optional[TokenCache], **Any) -> None self._authority = normalize_authority(authority) if authority else get_default_authority() self._tenant_id = tenant_id - self._allow_multitenant = allow_multitenant_authentication self._cache = cache or TokenCache() self._client_id = client_id @@ -61,7 +60,7 @@ def __init__( def get_cached_access_token(self, scopes, **kwargs): # type: (Iterable[str], **Any) -> Optional[AccessToken] - tenant = resolve_tenant(self._tenant_id, self._allow_multitenant, **kwargs) + tenant = resolve_tenant(self._tenant_id, **kwargs) tokens = self._cache.find( TokenCache.CredentialType.ACCESS_TOKEN, target=list(scopes), @@ -260,7 +259,7 @@ def _get_refresh_token_request(self, scopes, refresh_token, **kwargs): def _get_token_url(self, **kwargs): # type: (**Any) -> str - tenant = resolve_tenant(self._tenant_id, self._allow_multitenant, **kwargs) + tenant = resolve_tenant(self._tenant_id, **kwargs) return "/".join((self._authority, tenant, "oauth2/v2.0/token")) def _post(self, data, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/_internal/get_token_mixin.py b/sdk/identity/azure-identity/azure/identity/_internal/get_token_mixin.py index d8b683e984bd..29f30bb1fb8a 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/get_token_mixin.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/get_token_mixin.py @@ -57,8 +57,7 @@ def get_token(self, *scopes, **kwargs): This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/_internal/interactive.py b/sdk/identity/azure-identity/azure/identity/_internal/interactive.py index a095c783c595..e448e6d90a9c 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/interactive.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/interactive.py @@ -109,8 +109,7 @@ def get_token(self, *scopes, **kwargs): :param str scopes: desired scopes for the access token. This method requires at least one scope. :keyword str claims: additional claims required in the token, such as those returned in a resource provider's claims challenge following an authorization failure - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py b/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py index 8ac10bbd687d..4ab266ae26c3 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py @@ -28,13 +28,9 @@ def __init__(self, client_id, client_credential=None, **kwargs): # type: (str, Optional[Union[str, Dict]], **Any) -> None authority = kwargs.pop("authority", None) self._authority = normalize_authority(authority) if authority else get_default_authority() - self._regional_authority = kwargs.pop( - "regional_authority", os.environ.get(EnvironmentVariables.AZURE_REGIONAL_AUTHORITY_NAME) - ) + self._regional_authority = os.environ.get(EnvironmentVariables.AZURE_REGIONAL_AUTHORITY_NAME) self._tenant_id = kwargs.pop("tenant_id", None) or "organizations" validate_tenant_id(self._tenant_id) - self._allow_multitenant = kwargs.pop("allow_multitenant_authentication", False) - self._client = MsalClient(**kwargs) self._client_applications = {} # type: Dict[str, msal.ClientApplication] self._client_credential = client_credential @@ -63,7 +59,7 @@ def close(self): def _get_app(self, **kwargs): # type: (**Any) -> msal.ClientApplication - tenant_id = resolve_tenant(self._tenant_id, self._allow_multitenant, **kwargs) + tenant_id = resolve_tenant(self._tenant_id, **kwargs) if tenant_id not in self._client_applications: # CP1 = can handle claims challenges (CAE) capabilities = None if "AZURE_IDENTITY_DISABLE_CP1" in os.environ else ["CP1"] diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/application.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/application.py index 7e63bc9b78db..c7812ea69587 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/application.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/application.py @@ -48,10 +48,6 @@ class AzureApplicationCredential(ChainedTokenCredential): `_ for an overview of managed identities. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application or user is registered in. When False, which is the default, the credential will acquire tokens - only from the tenant specified by **AZURE_TENANT_ID**. This argument doesn't apply to managed identity - authentication. :keyword str authority: Authority of an Azure Active Directory endpoint, for example "login.microsoftonline.com", the authority for Azure Public Cloud, which is the default when no value is given for this keyword argument or environment variable AZURE_AUTHORITY_HOST. :class:`~azure.identity.AzureAuthorityHosts` defines authorities for diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/authorization_code.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/authorization_code.py index 225fbe434d94..4befed6e9eeb 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/authorization_code.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/authorization_code.py @@ -30,9 +30,6 @@ class AuthorizationCodeCredential(AsyncContextManager, GetTokenMixin): the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. :keyword str client_secret: One of the application's client secrets. Required only for web apps and web APIs. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant specified by **tenant_id**. """ async def __aenter__(self): @@ -66,8 +63,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": redeeming the authorization code. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` 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 944a2211d023..869cf5de69ae 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 @@ -31,15 +31,8 @@ class AzureCliCredential(AsyncContextManager): """Authenticates by requesting a token from the Azure CLI. This requires previously logging in to Azure via "az login", and will use the CLI's currently logged in identity. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the identity logged in to the Azure CLI is registered in. When False, which is the default, the credential will - acquire tokens only from the tenant of the Azure CLI's active subscription. """ - def __init__(self, **kwargs: "Any") -> None: - self._allow_multitenant = kwargs.get("allow_multitenant_authentication", False) - @log_get_token_async async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": """Request an access token for `scopes`. @@ -48,8 +41,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": also handle token caching because this credential doesn't cache the tokens it acquires. :param str scopes: desired scope for the access token. This credential allows only one scope per request. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` @@ -63,7 +55,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": resource = _scopes_to_resource(*scopes) command = COMMAND_LINE.format(resource) - tenant = resolve_tenant("", self._allow_multitenant, **kwargs) + tenant = resolve_tenant("", **kwargs) if tenant: command += " --tenant " + tenant output = await _run_command(command) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_powershell.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_powershell.py index cfb3cd4331a1..0881dd4e2b99 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_powershell.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_powershell.py @@ -28,15 +28,8 @@ class AzurePowerShellCredential(AsyncContextManager): """Authenticates by requesting a token from Azure PowerShell. This requires previously logging in to Azure via "Connect-AzAccount", and will use the currently logged in identity. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the identity logged in to Azure PowerShell is registered in. When False, which is the default, the credential - will acquire tokens only from the tenant of Azure PowerShell's active subscription. """ - def __init__(self, **kwargs: "Any") -> None: - self._allow_multitenant = kwargs.get("allow_multitenant_authentication", False) - @log_get_token_async async def get_token( self, *scopes: str, **kwargs: "Any" @@ -47,8 +40,7 @@ async def get_token( also handle token caching because this credential doesn't cache the tokens it acquires. :param str scopes: desired scope for the access token. This credential allows only one scope per request. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` @@ -61,7 +53,7 @@ async def get_token( if sys.platform.startswith("win") and not isinstance(asyncio.get_event_loop(), asyncio.ProactorEventLoop): return _SyncCredential().get_token(*scopes, **kwargs) - tenant_id = resolve_tenant("", self._allow_multitenant, **kwargs) + tenant_id = resolve_tenant("", **kwargs) command_line = get_command_line(scopes, tenant_id) output = await run_command_line(command_line) token = parse_token(output) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py index a78b9b790eac..0957e6a151c6 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py @@ -40,9 +40,6 @@ class CertificateCredential(AsyncContextManager, GetTokenMixin): :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - the tenant specified by **tenant_id**. """ def __init__(self, tenant_id, client_id, certificate_path=None, **kwargs): diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py index 676e0b15e790..4bcfa49cbd19 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py @@ -29,9 +29,6 @@ class ClientSecretCredential(AsyncContextManager, GetTokenMixin): :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - the tenant specified by **tenant_id**. """ def __init__(self, tenant_id: str, client_id: str, client_secret: str, **kwargs: "Any") -> None: diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py index 8888e5d28874..5b32b0429c54 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/default.py @@ -42,9 +42,6 @@ class DefaultAzureCredential(ChainedTokenCredential): This default behavior is configurable with keyword arguments. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only from - its configured tenant. This argument doesn't apply to managed identity authentication. :keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com', the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. Managed identities ignore this because they reside in a single cloud. @@ -121,9 +118,9 @@ def __init__(self, **kwargs: "Any") -> None: if not exclude_visual_studio_code_credential: credentials.append(VisualStudioCodeCredential(**vscode_args)) if not exclude_cli_credential: - credentials.append(AzureCliCredential(**kwargs)) + credentials.append(AzureCliCredential()) if not exclude_powershell_credential: - credentials.append(AzurePowerShellCredential(**kwargs)) + credentials.append(AzurePowerShellCredential()) super().__init__(*credentials) @@ -133,8 +130,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/environment.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/environment.py index d4c0bdff2047..944add051c94 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/environment.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/environment.py @@ -37,10 +37,6 @@ class EnvironmentCredential(AsyncContextManager): - **AZURE_CLIENT_ID**: the service principal's client ID - **AZURE_CLIENT_CERTIFICATE_PATH**: path to a PEM or PKCS12 certificate file including the private key. The certificate must not be password-protected. - - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application or user is registered in. When False, which is the default, the credential will acquire tokens - only from the tenant specified by **AZURE_TENANT_ID**. """ def __init__(self, **kwargs: "Any") -> None: @@ -91,8 +87,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/on_behalf_of.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/on_behalf_of.py index bc7c75f2123a..202de061d3ae 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/on_behalf_of.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/on_behalf_of.py @@ -36,9 +36,6 @@ class OnBehalfOfCredential(AsyncContextManager, GetTokenMixin): :param str user_assertion: the access token the credential will use as the user assertion when requesting on-behalf-of tokens - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the application is registered in. When False, which is the default, the credential will acquire tokens only - from the tenant specified by **tenant_id**. :keyword str authority: Authority of an Azure Active Directory endpoint, for example "login.microsoftonline.com", the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` defines authorities for other clouds. @@ -74,7 +71,7 @@ def __init__( else: self._client_credential = client_credential - # note AadClient handles "allow_multitenant_authentication", "authority", and any pipeline kwargs + # note AadClient handles "authority" and any pipeline kwargs self._client = AadClient(tenant_id, client_id, **kwargs) self._assertion = user_assertion diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/shared_cache.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/shared_cache.py index b663f16623af..1852b8523586 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/shared_cache.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/shared_cache.py @@ -32,9 +32,6 @@ class SharedTokenCacheCredential(SharedTokenCacheBase, AsyncContextManager): :keyword cache_persistence_options: configuration for persistent token caching. If not provided, the credential will use the persistent cache shared by Microsoft development applications :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant. """ async def __aenter__(self): @@ -57,8 +54,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": # py This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode.py index 586354f8ff30..c66e1e1c2611 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode.py @@ -26,9 +26,6 @@ class VisualStudioCodeCredential(_VSCodeCredentialBase, AsyncContextManager, Get :keyword str tenant_id: ID of the tenant the credential should authenticate in. Defaults to the "Azure: Tenant" setting in VS Code's user settings or, when that setting has no value, the "organizations" tenant, which supports only Azure Active Directory work or school accounts. - :keyword bool allow_multitenant_authentication: when True, enables the credential to acquire tokens from any tenant - the user is registered in. When False, which is the default, the credential will acquire tokens only from the - user's home tenant or the tenant configured by **tenant_id** or VS Code's user settings. """ async def __aenter__(self) -> "VisualStudioCodeCredential": @@ -48,8 +45,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py b/sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py index 17b8d225b55d..f41db52d4132 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py @@ -47,8 +47,7 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": This method is called automatically by Azure SDK clients. :param str scopes: desired scopes for the access token. This method requires at least one scope. - :keyword str tenant_id: optional tenant to include in the token request. If **allow_multitenant_authentication** - is False, specifying a tenant with this argument may raise an exception. + :keyword str tenant_id: optional tenant to include in the token request. :rtype: :class:`azure.core.credentials.AccessToken` diff --git a/sdk/identity/azure-identity/tests/test_aad_client.py b/sdk/identity/azure-identity/tests/test_aad_client.py index 68a452c1e287..3bee135d4268 100644 --- a/sdk/identity/azure-identity/tests/test_aad_client.py +++ b/sdk/identity/azure-identity/tests/test_aad_client.py @@ -304,11 +304,7 @@ def test_multitenant_cache(): assert client_b.get_cached_access_token([scope]) is None # but C allows multitenant auth and should therefore return the token from tenant_a when appropriate - client_c = AadClient(tenant_id=tenant_c, allow_multitenant_authentication=True, **common_args) + client_c = AadClient(tenant_id=tenant_c, **common_args) assert client_c.get_cached_access_token([scope]) is None token = client_c.get_cached_access_token([scope], tenant_id=tenant_a) assert token.token == expected_token - with patch.dict( - "os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}, clear=True - ): - assert client_c.get_cached_access_token([scope], tenant_id=tenant_a) is None diff --git a/sdk/identity/azure-identity/tests/test_aad_client_async.py b/sdk/identity/azure-identity/tests/test_aad_client_async.py index dba17bc11cf6..ab30393f93d3 100644 --- a/sdk/identity/azure-identity/tests/test_aad_client_async.py +++ b/sdk/identity/azure-identity/tests/test_aad_client_async.py @@ -308,11 +308,7 @@ async def test_multitenant_cache(): assert client_b.get_cached_access_token([scope]) is None # but C allows multitenant auth and should therefore return the token from tenant_a when appropriate - client_c = AadClient(tenant_id=tenant_c, allow_multitenant_authentication=True, **common_args) + client_c = AadClient(tenant_id=tenant_c, **common_args) assert client_c.get_cached_access_token([scope]) is None token = client_c.get_cached_access_token([scope], tenant_id=tenant_a) assert token.token == expected_token - with patch.dict( - "os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}, clear=True - ): - assert client_c.get_cached_access_token([scope], tenant_id=tenant_a) is None diff --git a/sdk/identity/azure-identity/tests/test_auth_code.py b/sdk/identity/azure-identity/tests/test_auth_code.py index 29ab3733a633..f2fe752ff528 100644 --- a/sdk/identity/azure-identity/tests/test_auth_code.py +++ b/sdk/identity/azure-identity/tests/test_auth_code.py @@ -118,9 +118,7 @@ def test_auth_code_credential(): assert transport.send.call_count == 2 -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -138,7 +136,6 @@ def send(request, **_): "client-id", "authcode", "https://localhost", - allow_multitenant_authentication=True, transport=Mock(send=send), ) token = credential.get_token("scope") @@ -154,10 +151,7 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -174,15 +168,12 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) + token = credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_auth_code_async.py b/sdk/identity/azure-identity/tests/test_auth_code_async.py index 5eb55e6515cc..e5a91ca62750 100644 --- a/sdk/identity/azure-identity/tests/test_auth_code_async.py +++ b/sdk/identity/azure-identity/tests/test_auth_code_async.py @@ -142,9 +142,7 @@ async def test_auth_code_credential(): assert transport.send.call_count == 2 -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -162,7 +160,6 @@ async def send(request, **_): "client-id", "authcode", "https://localhost", - allow_multitenant_authentication=True, transport=Mock(send=send), ) token = await credential.get_token("scope") @@ -178,10 +175,7 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == first_token - async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -198,15 +192,12 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = await credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="un" + expected_tenant) + token = await credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_certificate_credential.py b/sdk/identity/azure-identity/tests/test_certificate_credential.py index 389bf336297c..9215882abb3a 100644 --- a/sdk/identity/azure-identity/tests/test_certificate_credential.py +++ b/sdk/identity/azure-identity/tests/test_certificate_credential.py @@ -7,7 +7,8 @@ from azure.core.exceptions import ClientAuthenticationError from azure.core.pipeline.policies import ContentDecodePolicy, SansIOHTTPPolicy -from azure.identity import CertificateCredential, RegionalAuthority, TokenCachePersistenceOptions +from azure.identity import CertificateCredential, TokenCachePersistenceOptions +from azure.identity._enums import RegionalAuthority from azure.identity._constants import EnvironmentVariables from azure.identity._credentials.certificate import load_pkcs12_certificate from azure.identity._internal.user_agent import USER_AGENT @@ -151,17 +152,6 @@ def test_regional_authority(): for region in RegionalAuthority: mock_confidential_client.reset_mock() - with patch.dict("os.environ", {}, clear=True): - credential = CertificateCredential("tenant", "client-id", PEM_CERT_PATH, regional_authority=region) - with patch("msal.ConfidentialClientApplication", mock_confidential_client): - # must call get_token because the credential constructs the MSAL application lazily - credential.get_token("scope") - - assert mock_confidential_client.call_count == 1 - _, kwargs = mock_confidential_client.call_args - assert kwargs["azure_region"] == region - mock_confidential_client.reset_mock() - # region can be configured via environment variable with patch.dict("os.environ", {EnvironmentVariables.AZURE_REGIONAL_AUTHORITY_NAME: region}, clear=True): credential = CertificateCredential("tenant", "client-id", PEM_CERT_PATH) @@ -359,9 +349,7 @@ def test_certificate_arguments(): @pytest.mark.parametrize("cert_path,cert_password", ALL_CERTS) -def test_allow_multitenant_authentication(cert_path, cert_password): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(cert_path, cert_password): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -382,7 +370,6 @@ def send(request, **_): "client-id", cert_path, password=cert_password, - allow_multitenant_authentication=True, transport=Mock(send=send), ) token = credential.get_token("scope") @@ -401,8 +388,6 @@ def send(request, **_): @pytest.mark.parametrize("cert_path,cert_password", ALL_CERTS) def test_multitenant_authentication_backcompat(cert_path, cert_password): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -426,13 +411,5 @@ def send(request, **_): token = credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled - with patch.dict( - os.environ, {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}, clear=True - ): - token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + token = credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_certificate_credential_async.py b/sdk/identity/azure-identity/tests/test_certificate_credential_async.py index a2338e78a910..8c5cc5b67efa 100644 --- a/sdk/identity/azure-identity/tests/test_certificate_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_certificate_credential_async.py @@ -270,9 +270,7 @@ def test_certificate_arguments(): @pytest.mark.asyncio @pytest.mark.parametrize("cert_path,cert_password", ALL_CERTS) -async def test_allow_multitenant_authentication(cert_path, cert_password): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(cert_path, cert_password): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -290,7 +288,6 @@ async def send(request, **_): "client-id", cert_path, password=cert_password, - allow_multitenant_authentication=True, transport=Mock(send=send), ) token = await credential.get_token("scope") @@ -310,8 +307,6 @@ async def send(request, **_): @pytest.mark.asyncio @pytest.mark.parametrize("cert_path,cert_password", ALL_CERTS) async def test_multitenant_authentication_backcompat(cert_path, cert_password): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -332,13 +327,5 @@ async def send(request, **_): token = await credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled - with patch.dict( - "os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}, clear=True - ): - token = await credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + token = await credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 diff --git a/sdk/identity/azure-identity/tests/test_cli_credential.py b/sdk/identity/azure-identity/tests/test_cli_credential.py index bac97fd4ac7c..6eb71b97e722 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential.py @@ -152,9 +152,7 @@ def test_timeout(): AzureCliCredential().get_token("scope") -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): default_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -174,7 +172,7 @@ def fake_check_output(command_line, **_): } ) - credential = AzureCliCredential(allow_multitenant_authentication=True) + credential = AzureCliCredential() with mock.patch(CHECK_OUTPUT, fake_check_output): token = credential.get_token("scope") assert token.token == first_token @@ -189,10 +187,7 @@ def fake_check_output(command_line, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -214,15 +209,8 @@ def fake_check_output(command_line, **_): token = credential.get_token("scope") assert token.token == expected_token - # specifying a tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled with mock.patch.dict( - "os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"} + "os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"} ): token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert ( - token.token == expected_token - ), "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_cli_credential_async.py b/sdk/identity/azure-identity/tests/test_cli_credential_async.py index d5f5885f5d1f..2276a1bff3e5 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential_async.py @@ -185,9 +185,7 @@ async def test_timeout(): assert proc.kill.call_count == 1 -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): default_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -208,7 +206,7 @@ async def fake_exec(*args, **_): ).encode() return mock.Mock(communicate=mock.Mock(return_value=get_completed_future((output, b""))), returncode=0) - credential = AzureCliCredential(allow_multitenant_authentication=True) + credential = AzureCliCredential() with mock.patch(SUBPROCESS_EXEC, fake_exec): token = await credential.get_token("scope") assert token.token == first_token @@ -223,10 +221,7 @@ async def fake_exec(*args, **_): token = await credential.get_token("scope") assert token.token == first_token - async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -249,13 +244,6 @@ async def fake_exec(*args, **_): token = await credential.get_token("scope") assert token.token == expected_token - # specifying a tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled - with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="un" + expected_tenant) - assert ( - token.token == expected_token - ), "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_client_secret_credential.py b/sdk/identity/azure-identity/tests/test_client_secret_credential.py index 7c694c617c60..2528bf0ad191 100644 --- a/sdk/identity/azure-identity/tests/test_client_secret_credential.py +++ b/sdk/identity/azure-identity/tests/test_client_secret_credential.py @@ -4,7 +4,8 @@ # ------------------------------------ from azure.core.exceptions import ClientAuthenticationError from azure.core.pipeline.policies import ContentDecodePolicy, SansIOHTTPPolicy -from azure.identity import ClientSecretCredential, RegionalAuthority, TokenCachePersistenceOptions +from azure.identity import ClientSecretCredential, TokenCachePersistenceOptions +from azure.identity._enums import RegionalAuthority from azure.identity._constants import EnvironmentVariables from azure.identity._internal.user_agent import USER_AGENT from msal import TokenCache @@ -128,17 +129,6 @@ def test_regional_authority(): for region in RegionalAuthority: mock_confidential_client.reset_mock() - with patch.dict("os.environ", {}, clear=True): - credential = ClientSecretCredential("tenant", "client-id", "secret", regional_authority=region) - with patch("msal.ConfidentialClientApplication", mock_confidential_client): - # must call get_token because the credential constructs the MSAL application lazily - credential.get_token("scope") - - assert mock_confidential_client.call_count == 1 - _, kwargs = mock_confidential_client.call_args - assert kwargs["azure_region"] == region - mock_confidential_client.reset_mock() - # region can be configured via environment variable with patch.dict("os.environ", {EnvironmentVariables.AZURE_REGIONAL_AUTHORITY_NAME: region}, clear=True): credential = ClientSecretCredential("tenant", "client-id", "secret") @@ -211,9 +201,7 @@ def test_cache_multiple_clients(): assert len(cache.find(TokenCache.CredentialType.ACCESS_TOKEN)) == 2 -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -230,7 +218,7 @@ def send(request, **_): return mock_response(json_payload=build_aad_response(access_token=token)) credential = ClientSecretCredential( - first_tenant, "client-id", "secret", allow_multitenant_authentication=True, transport=Mock(send=send) + first_tenant, "client-id", "secret", transport=Mock(send=send) ) token = credential.get_token("scope") assert token.token == first_token @@ -245,10 +233,7 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -266,15 +251,9 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_client_secret_credential_async.py b/sdk/identity/azure-identity/tests/test_client_secret_credential_async.py index 60554ce9c90b..03e8d323c81d 100644 --- a/sdk/identity/azure-identity/tests/test_client_secret_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_client_secret_credential_async.py @@ -251,9 +251,7 @@ async def test_cache_multiple_clients(): @pytest.mark.asyncio -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -267,7 +265,7 @@ async def send(request, **_): return mock_response(json_payload=build_aad_response(access_token=token)) credential = ClientSecretCredential( - first_tenant, "client-id", "secret", allow_multitenant_authentication=True, transport=Mock(send=send) + first_tenant, "client-id", "secret", transport=Mock(send=send) ) token = await credential.get_token("scope") assert token.token == first_token @@ -282,11 +280,8 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == first_token - @pytest.mark.asyncio async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -301,15 +296,12 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = await credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="un" + expected_tenant) + token = await credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_default.py b/sdk/identity/azure-identity/tests/test_default.py index 8c8189996861..1c9120a9942a 100644 --- a/sdk/identity/azure-identity/tests/test_default.py +++ b/sdk/identity/azure-identity/tests/test_default.py @@ -402,36 +402,6 @@ def validate_client_id(credential): validate_client_id(mock_credential) -@pytest.mark.parametrize("expected_value", (True, False)) -def test_allow_multitenant_authentication(expected_value): - """the credential should pass "allow_multitenant_authentication" to the inner credentials which support it""" - - inner_credentials = { - credential: Mock() - for credential in ( - "AzureCliCredential", - "AzurePowerShellCredential", - "EnvironmentCredential", - "InteractiveBrowserCredential", - "ManagedIdentityCredential", # will ignore the argument - "SharedTokenCacheCredential", - ) - } - with patch.multiple(DefaultAzureCredential.__module__, **inner_credentials): - DefaultAzureCredential( - allow_multitenant_authentication=expected_value, exclude_interactive_browser_credential=False - ) - - for credential_name, mock_credential in inner_credentials.items(): - assert mock_credential.call_count == 1 - _, kwargs = mock_credential.call_args - - assert "allow_multitenant_authentication" in kwargs, ( - '"allow_multitenant_authentication" was not passed to ' + credential_name - ) - assert kwargs["allow_multitenant_authentication"] == expected_value - - def test_unexpected_kwarg(): """the credential shouldn't raise when given an unexpected keyword argument""" DefaultAzureCredential(foo=42) diff --git a/sdk/identity/azure-identity/tests/test_default_async.py b/sdk/identity/azure-identity/tests/test_default_async.py index 0f144350640c..e4ff1a9fcf11 100644 --- a/sdk/identity/azure-identity/tests/test_default_async.py +++ b/sdk/identity/azure-identity/tests/test_default_async.py @@ -312,33 +312,6 @@ def get_credential_for_shared_cache_test(expected_refresh_token, expected_access return DefaultAzureCredential(_cache=cache, transport=transport, **exclude_other_credentials, **kwargs) -@pytest.mark.parametrize("expected_value", (True, False)) -def test_allow_multitenant_authentication(expected_value): - """the credential should pass "allow_multitenant_authentication" to the inner credentials which support it""" - - inner_credentials = { - credential: Mock() - for credential in ( - "AzureCliCredential", - "AzurePowerShellCredential", - "EnvironmentCredential", - "ManagedIdentityCredential", # will ignore the argument - "SharedTokenCacheCredential", - ) - } - with patch.multiple(DefaultAzureCredential.__module__, **inner_credentials): - DefaultAzureCredential(allow_multitenant_authentication=expected_value) - - for credential_name, mock_credential in inner_credentials.items(): - assert mock_credential.call_count == 1 - _, kwargs = mock_credential.call_args - - assert "allow_multitenant_authentication" in kwargs, ( - '"allow_multitenant_authentication" was not passed to ' + credential_name - ) - assert kwargs["allow_multitenant_authentication"] == expected_value - - def test_unexpected_kwarg(): """the credential shouldn't raise when given an unexpected keyword argument""" DefaultAzureCredential(foo=42) diff --git a/sdk/identity/azure-identity/tests/test_interactive_credential.py b/sdk/identity/azure-identity/tests/test_interactive_credential.py index e82f76f6c5ba..ba6e407e3aec 100644 --- a/sdk/identity/azure-identity/tests/test_interactive_credential.py +++ b/sdk/identity/azure-identity/tests/test_interactive_credential.py @@ -282,9 +282,7 @@ def _request_token(self, *_, **__): assert record.username == username -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -312,7 +310,6 @@ def send(request, **_): credential = MockCredential( tenant_id=first_tenant, - allow_multitenant_authentication=True, request_token=request_token, transport=Mock(send=send), ) @@ -329,10 +326,7 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -360,15 +354,9 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_obo.py b/sdk/identity/azure-identity/tests/test_obo.py index 7cd402ee8c36..413b149be398 100644 --- a/sdk/identity/azure-identity/tests/test_obo.py +++ b/sdk/identity/azure-identity/tests/test_obo.py @@ -92,9 +92,7 @@ def test_obo_cert(self): credential.get_token(self.obo_settings["scope"]) -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -113,7 +111,7 @@ def send(request, **_): transport = Mock(send=Mock(wraps=send)) credential = OnBehalfOfCredential( - first_tenant, "client-id", "secret", "assertion", allow_multitenant_authentication=True, transport=transport + first_tenant, "client-id", "secret", "assertion", transport=transport ) token = credential.get_token("scope") assert token.token == first_token diff --git a/sdk/identity/azure-identity/tests/test_obo_async.py b/sdk/identity/azure-identity/tests/test_obo_async.py index 0bbaecb79150..c39957be0afd 100644 --- a/sdk/identity/azure-identity/tests/test_obo_async.py +++ b/sdk/identity/azure-identity/tests/test_obo_async.py @@ -69,9 +69,7 @@ async def test_context_manager(): @pytest.mark.asyncio -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -87,7 +85,7 @@ async def send(request, **_): transport = Mock(send=Mock(wraps=send)) credential = OnBehalfOfCredential( - first_tenant, "client-id", "secret", "assertion", allow_multitenant_authentication=True, transport=transport + first_tenant, "client-id", "secret", "assertion", transport=transport ) token = await credential.get_token("scope") assert token.token == first_token diff --git a/sdk/identity/azure-identity/tests/test_powershell_credential.py b/sdk/identity/azure-identity/tests/test_powershell_credential.py index cdf83543f220..3766b84cb6e8 100644 --- a/sdk/identity/azure-identity/tests/test_powershell_credential.py +++ b/sdk/identity/azure-identity/tests/test_powershell_credential.py @@ -243,9 +243,7 @@ def Popen(args, **kwargs): assert Fake.calls == 2 -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_token = "***" second_tenant = "second-tenant" second_token = first_token * 2 @@ -264,7 +262,7 @@ def fake_Popen(command, **_): communicate = Mock(return_value=(stdout, "")) return Mock(communicate=communicate, returncode=0) - credential = AzurePowerShellCredential(allow_multitenant_authentication=True) + credential = AzurePowerShellCredential() with patch(POPEN, fake_Popen): token = credential.get_token("scope") assert token.token == first_token @@ -276,10 +274,7 @@ def fake_Popen(command, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_token = "***" def fake_Popen(command, **_): @@ -300,13 +295,6 @@ def fake_Popen(command, **_): token = credential.get_token("scope") assert token.token == expected_token - # specifying a tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="some tenant") - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = credential.get_token("scope", tenant_id="some tenant") - assert ( - token.token == expected_token - ), "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_powershell_credential_async.py b/sdk/identity/azure-identity/tests/test_powershell_credential_async.py index 2e67d6c19906..0dcc56267f78 100644 --- a/sdk/identity/azure-identity/tests/test_powershell_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_powershell_credential_async.py @@ -244,9 +244,7 @@ async def mock_exec(*args, **kwargs): assert calls == 2 -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_token = "***" second_tenant = "second-tenant" second_token = first_token * 2 @@ -266,7 +264,7 @@ async def fake_exec(*args, **_): communicate = Mock(return_value=get_completed_future((stdout.encode(), b""))) return Mock(communicate=communicate, returncode=0) - credential = AzurePowerShellCredential(allow_multitenant_authentication=True) + credential = AzurePowerShellCredential() with patch(CREATE_SUBPROCESS_EXEC, fake_exec): token = await credential.get_token("scope") assert token.token == first_token @@ -278,10 +276,7 @@ async def fake_exec(*args, **_): token = await credential.get_token("scope") assert token.token == first_token - async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_token = "***" async def fake_exec(*args, **_): @@ -302,13 +297,6 @@ async def fake_exec(*args, **_): token = await credential.get_token("scope") assert token.token == expected_token - # specifying a tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="some tenant") - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="some tenant") - assert ( - token.token == expected_token - ), "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_shared_cache_credential.py b/sdk/identity/azure-identity/tests/test_shared_cache_credential.py index 5081825cebb5..287815c00cce 100644 --- a/sdk/identity/azure-identity/tests/test_shared_cache_credential.py +++ b/sdk/identity/azure-identity/tests/test_shared_cache_credential.py @@ -825,9 +825,7 @@ def test_claims_challenge(): assert kwargs["claims_challenge"] == expected_claims -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): default_tenant = "organizations" first_token = "***" second_tenant = "second-tenant" @@ -851,7 +849,7 @@ def send(request, **_): cache = populated_cache(expected_account) credential = SharedTokenCacheCredential( - allow_multitenant_authentication=True, authority=authority, transport=Mock(send=send), _cache=cache + authority=authority, transport=Mock(send=send), _cache=cache ) token = credential.get_token("scope") assert token.token == first_token @@ -867,56 +865,7 @@ def send(request, **_): assert token.token == first_token -def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - - default_tenant = "organizations" - expected_token = "***" - - def send(request, **_): - parsed = urlparse(request.url) - tenant_id = parsed.path.split("/")[1] - assert tenant_id == default_tenant - return mock_response( - json_payload=build_aad_response( - access_token=expected_token, - id_token_claims=id_token_claims(aud="...", iss="...", sub="..."), - ) - ) - - tenant_id = "tenant-id" - client_id = "client-id" - authority = "localhost" - object_id = "object-id" - username = "me" - - expected_account = get_account_event( - username, object_id, tenant_id, authority=authority, client_id=client_id, refresh_token="**" - ) - cache = populated_cache(expected_account) - - credential = SharedTokenCacheCredential(authority=authority, transport=Mock(send=send), _cache=cache) - - token = credential.get_token("scope") - assert token.token == expected_token - - # explicitly specifying the configured tenant is okay - token = credential.get_token("scope", tenant_id=default_tenant) - assert token.token == expected_token - - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="some tenant") - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): - token = credential.get_token("scope", tenant_id="some tenant") - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" - - -def test_allow_multitenant_authentication_auth_record(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication_auth_record(): default_tenant = "organizations" first_token = "***" second_tenant = "second-tenant" @@ -947,7 +896,6 @@ def send(request, **_): cache = populated_cache(expected_account) credential = SharedTokenCacheCredential( - allow_multitenant_authentication=True, authority=authority, transport=Mock(send=send), authentication_record=record, @@ -967,64 +915,6 @@ def send(request, **_): assert token.token == first_token -def test_multitenant_authentication_not_allowed_authentication_record(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - - default_tenant = "organizations" - expected_token = "***" - - authority = AzureAuthorityHosts.AZURE_PUBLIC_CLOUD - object_id = "object-id" - home_account_id = object_id + "." + default_tenant - record = AuthenticationRecord(default_tenant, "client-id", authority, home_account_id, "user") - - def send(request, **_): - parsed = urlparse(request.url) - tenant_id = parsed.path.split("/")[1] - if "/oauth2/v2.0/token" not in request.url: - return get_discovery_response("https://{}/{}".format(parsed.netloc, tenant_id)) - - assert tenant_id == default_tenant - return mock_response( - json_payload=build_aad_response( - access_token=expected_token, - id_token_claims=id_token_claims(aud="...", iss="...", sub="..."), - ) - ) - - expected_account = get_account_event( - record.username, - object_id, - record.tenant_id, - authority=record.authority, - client_id=record.client_id, - refresh_token="**", - ) - cache = populated_cache(expected_account) - - credential = SharedTokenCacheCredential( - authority=authority, transport=Mock(send=send), authentication_record=record, _cache=cache - ) - - token = credential.get_token("scope") - assert token.token == expected_token - - # explicitly specifying the configured tenant is okay - token = credential.get_token("scope", tenant_id=default_tenant) - assert token.token == expected_token - - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="some tenant") - - # ...unless the compat switch is enabled - with patch.dict( - "os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}, clear=True - ): - token = credential.get_token("scope", tenant_id="some tenant") - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" - - def get_account_event( username, uid, utid, authority=None, client_id="client-id", refresh_token="refresh-token", scopes=None, **kwargs ): @@ -1054,3 +944,41 @@ def populated_cache(*accounts): cache.add(account) cache.add = lambda *_, **__: None # prevent anything being added to the cache return cache + +def test_multitenant_authentication_not_allowed(): + default_tenant = "organizations" + expected_token = "***" + + def send(request, **_): + parsed = urlparse(request.url) + tenant_id = parsed.path.split("/")[1] + assert tenant_id == default_tenant + return mock_response( + json_payload=build_aad_response( + access_token=expected_token, + id_token_claims=id_token_claims(aud="...", iss="...", sub="..."), + ) + ) + + tenant_id = "tenant-id" + client_id = "client-id" + authority = "localhost" + object_id = "object-id" + username = "me" + + expected_account = get_account_event( + username, object_id, tenant_id, authority=authority, client_id=client_id, refresh_token="**" + ) + cache = populated_cache(expected_account) + + credential = SharedTokenCacheCredential(authority=authority, transport=Mock(send=send), _cache=cache) + + token = credential.get_token("scope") + assert token.token == expected_token + + token = credential.get_token("scope", tenant_id=default_tenant) + assert token.token == expected_token + + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): + token = credential.get_token("scope", tenant_id="some tenant") + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_shared_cache_credential_async.py b/sdk/identity/azure-identity/tests/test_shared_cache_credential_async.py index a6d7f0d67d60..9346755360f1 100644 --- a/sdk/identity/azure-identity/tests/test_shared_cache_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_shared_cache_credential_async.py @@ -606,9 +606,7 @@ async def test_initialization(): @pytest.mark.asyncio -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_token = "***" second_tenant = "second-tenant" second_token = first_token * 2 @@ -630,7 +628,7 @@ async def send(request, **_): cache = populated_cache(expected_account) credential = SharedTokenCacheCredential( - allow_multitenant_authentication=True, authority=authority, transport=Mock(send=send), _cache=cache + authority=authority, transport=Mock(send=send), _cache=cache ) token = await credential.get_token("scope") assert token.token == first_token @@ -645,11 +643,8 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == first_token - @pytest.mark.asyncio async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - default_tenant = "organizations" expected_token = "***" @@ -675,15 +670,9 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = await credential.get_token("scope", tenant_id=default_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="some tenant") - - # ...unless the compat switch is enabled - with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="some tenant") - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential.py b/sdk/identity/azure-identity/tests/test_vscode_credential.py index e6db05f56e5f..befe86ad7ce3 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential.py @@ -277,9 +277,7 @@ def test_no_user_settings(): assert transport.send.call_count == 1 -def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -293,7 +291,7 @@ def send(request, **_): return mock_response(json_payload=build_aad_response(access_token=token)) credential = get_credential( - tenant_id=first_tenant, allow_multitenant_authentication=True, transport=mock.Mock(send=send) + tenant_id=first_tenant, transport=mock.Mock(send=send) ) with mock.patch(GET_REFRESH_TOKEN, lambda _: "**"): token = credential.get_token("scope") @@ -310,10 +308,7 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == first_token - def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -329,15 +324,12 @@ def send(request, **_): token = credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - credential.get_token("scope", tenant_id="un" + expected_tenant) + token = credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 - # ...unless the compat switch is enabled - with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py index 40c996e39957..ff5716c7d9ad 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py @@ -268,9 +268,7 @@ async def test_no_user_settings(): @pytest.mark.asyncio -async def test_allow_multitenant_authentication(): - """When allow_multitenant_authentication is True, the credential should respect get_token(tenant_id=...)""" - +async def test_multitenant_authentication(): first_tenant = "first-tenant" first_token = "***" second_tenant = "second-tenant" @@ -284,7 +282,7 @@ async def send(request, **_): return mock_response(json_payload=build_aad_response(access_token=token)) credential = get_credential( - tenant_id=first_tenant, allow_multitenant_authentication=True, transport=mock.Mock(send=send) + tenant_id=first_tenant, transport=mock.Mock(send=send) ) with mock.patch(GET_REFRESH_TOKEN, lambda _: "**"): token = await credential.get_token("scope") @@ -301,11 +299,8 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == first_token - @pytest.mark.asyncio async def test_multitenant_authentication_not_allowed(): - """get_token(tenant_id=...) should raise when allow_multitenant_authentication is False (the default)""" - expected_tenant = "expected-tenant" expected_token = "***" @@ -321,15 +316,12 @@ async def send(request, **_): token = await credential.get_token("scope") assert token.token == expected_token - # explicitly specifying the configured tenant is okay token = await credential.get_token("scope", tenant_id=expected_tenant) assert token.token == expected_token - # but any other tenant should get an error - with pytest.raises(ClientAuthenticationError, match="allow_multitenant_authentication"): - await credential.get_token("scope", tenant_id="un" + expected_tenant) + token = await credential.get_token("scope", tenant_id="un" + expected_tenant) + assert token.token == expected_token * 2 - # ...unless the compat switch is enabled - with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_ENABLE_LEGACY_TENANT_SELECTION: "true"}): + with mock.patch.dict("os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}): token = await credential.get_token("scope", tenant_id="un" + expected_tenant) - assert token.token == expected_token, "credential should ignore tenant_id kwarg when the compat switch is enabled" + assert token.token == expected_token