From 3a8806335a974df9d89e994291f0d522d4515e09 Mon Sep 17 00:00:00 2001 From: jiasli <4003950+jiasli@users.noreply.github.com> Date: Tue, 3 Jun 2025 16:11:22 +0800 Subject: [PATCH] mi-msrestazure --- src/azure-cli-core/azure/cli/core/_profile.py | 108 +----- .../cli/core/auth/adal_authentication.py | 129 ------- .../azure/cli/core/telemetry.py | 7 - .../azure/cli/core/tests/test_profile.py | 324 +----------------- .../tests/latest/test_appconfig_aad_auth.py | 1 - 5 files changed, 22 insertions(+), 547 deletions(-) delete mode 100644 src/azure-cli-core/azure/cli/core/auth/adal_authentication.py diff --git a/src/azure-cli-core/azure/cli/core/_profile.py b/src/azure-cli-core/azure/cli/core/_profile.py index 8df59ee2bc4..ff3bf7c0dde 100644 --- a/src/azure-cli-core/azure/cli/core/_profile.py +++ b/src/azure-cli-core/azure/cli/core/_profile.py @@ -220,63 +220,8 @@ def login(self, self._set_subscriptions(consolidated) return deepcopy(consolidated) - def login_with_managed_identity_msrestazure(self, client_id=None, object_id=None, resource_id=None, - allow_no_subscriptions=None): - # Old way of using msrestazure for managed identity - import jwt - from azure.cli.core.auth.adal_authentication import MSIAuthenticationWrapper - resource = self.cli_ctx.cloud.endpoints.active_directory_resource_id - - id_arg_count = len([arg for arg in (client_id, object_id, resource_id) if arg]) - if id_arg_count > 1: - raise CLIError('Usage error: Provide only one of --client-id, --object-id, --resource-id.') - - if id_arg_count == 0: - identity_type = MsiAccountTypes.system_assigned - identity_id = None - msi_creds = MSIAuthenticationWrapper(resource=resource) - elif client_id: - identity_type = MsiAccountTypes.user_assigned_client_id - identity_id = client_id - msi_creds = MSIAuthenticationWrapper(resource=resource, client_id=client_id) - elif object_id: - identity_type = MsiAccountTypes.user_assigned_object_id - identity_id = object_id - msi_creds = MSIAuthenticationWrapper(resource=resource, object_id=object_id) - elif resource_id: - identity_type = MsiAccountTypes.user_assigned_resource_id - identity_id = resource_id - msi_creds = MSIAuthenticationWrapper(resource=resource, msi_res_id=resource_id) - - token_entry = msi_creds.token - token = token_entry['access_token'] - logger.info('MSI: token was retrieved. Now trying to initialize local accounts...') - decode = jwt.decode(token, algorithms=['RS256'], options={"verify_signature": False}) - tenant = decode['tid'] - - subscription_finder = SubscriptionFinder(self.cli_ctx) - subscriptions = subscription_finder.find_using_specific_tenant(tenant, msi_creds) - base_name = ('{}-{}'.format(identity_type, identity_id) if identity_id else identity_type) - user = _USER_ASSIGNED_IDENTITY if identity_id else _SYSTEM_ASSIGNED_IDENTITY - if not subscriptions: - if allow_no_subscriptions: - subscriptions = self._build_tenant_level_accounts([tenant]) - else: - raise CLIError('No access was configured for the VM, hence no subscriptions were found. ' - "If this is expected, use '--allow-no-subscriptions' to have tenant level access.") - - consolidated = self._normalize_properties(user, subscriptions, is_service_principal=True, - user_assigned_identity_id=base_name) - self._set_subscriptions(consolidated) - return deepcopy(consolidated) - def login_with_managed_identity(self, client_id=None, object_id=None, resource_id=None, allow_no_subscriptions=None): - if not _use_msal_managed_identity(self.cli_ctx): - return self.login_with_managed_identity_msrestazure( - client_id=client_id, object_id=object_id, resource_id=resource_id, - allow_no_subscriptions=allow_no_subscriptions) - import jwt from .auth.constants import ACCESS_TOKEN @@ -366,21 +311,14 @@ def get_login_credentials(self, subscription_id=None, aux_subscriptions=None, au if in_cloud_console() and account[_USER_ENTITY].get(_CLOUD_SHELL_ID): # Cloud Shell from .auth.msal_credentials import CloudShellCredential - # The credential must be wrapped by CredentialAdaptor so that it can work with Track 1 SDKs. + # The credential must be wrapped by CredentialAdaptor so that it can work with SDK. sdk_cred = CredentialAdaptor(CloudShellCredential()) elif managed_identity_type: # managed identity - if _use_msal_managed_identity(self.cli_ctx): - # The credential must be wrapped by CredentialAdaptor so that it can work with Track 1 SDKs. - cred = MsiAccountTypes.msal_credential_factory(managed_identity_type, managed_identity_id) - sdk_cred = CredentialAdaptor(cred) - else: - # The resource is merely used by msrestazure to get the first access token. - # It is not actually used in an API invocation. - sdk_cred = MsiAccountTypes.msi_auth_factory( - managed_identity_type, managed_identity_id, - self.cli_ctx.cloud.endpoints.active_directory_resource_id) + # The credential must be wrapped by CredentialAdaptor so that it can work with SDK. + cred = MsiAccountTypes.msal_credential_factory(managed_identity_type, managed_identity_id) + sdk_cred = CredentialAdaptor(cred) else: # user and service principal @@ -433,15 +371,10 @@ def get_raw_token(self, resource=None, scopes=None, subscription=None, tenant=No # managed identity if tenant: raise CLIError("Tenant shouldn't be specified for managed identity account") - if _use_msal_managed_identity(self.cli_ctx): - cred = MsiAccountTypes.msal_credential_factory(managed_identity_type, managed_identity_id) - if credential_out: - credential_out['credential'] = cred - sdk_cred = CredentialAdaptor(cred) - else: - from .auth.util import scopes_to_resource - sdk_cred = MsiAccountTypes.msi_auth_factory(managed_identity_type, managed_identity_id, - scopes_to_resource(scopes)) + cred = MsiAccountTypes.msal_credential_factory(managed_identity_type, managed_identity_id) + if credential_out: + credential_out['credential'] = cred + sdk_cred = CredentialAdaptor(cred) else: sdk_cred = CredentialAdaptor(self._create_credential(account, tenant_id=tenant)) @@ -772,19 +705,6 @@ def valid_msi_account_types(): return [MsiAccountTypes.system_assigned, MsiAccountTypes.user_assigned_client_id, MsiAccountTypes.user_assigned_object_id, MsiAccountTypes.user_assigned_resource_id] - @staticmethod - def msi_auth_factory(cli_account_name, identity, resource): - from azure.cli.core.auth.adal_authentication import MSIAuthenticationWrapper - if cli_account_name == MsiAccountTypes.system_assigned: - return MSIAuthenticationWrapper(resource=resource) - if cli_account_name == MsiAccountTypes.user_assigned_client_id: - return MSIAuthenticationWrapper(resource=resource, client_id=identity) - if cli_account_name == MsiAccountTypes.user_assigned_object_id: - return MSIAuthenticationWrapper(resource=resource, object_id=identity) - if cli_account_name == MsiAccountTypes.user_assigned_resource_id: - return MSIAuthenticationWrapper(resource=resource, msi_res_id=identity) - raise ValueError("unrecognized msi account name '{}'".format(cli_account_name)) - @staticmethod def parse_ids(client_id=None, object_id=None, resource_id=None): id_arg_count = len([arg for arg in (client_id, object_id, resource_id) if arg]) @@ -931,9 +851,7 @@ def _create_subscription_client(self, credential): .format(ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS, self.cli_ctx.cloud.profile)) api_version = get_api_version(self.cli_ctx, ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS) - # MSIAuthenticationWrapper already implements get_token, so no need to wrap it with CredentialAdaptor - from azure.cli.core.auth.adal_authentication import MSIAuthenticationWrapper - sdk_cred = credential if isinstance(credential, MSIAuthenticationWrapper) else CredentialAdaptor(credential) + sdk_cred = CredentialAdaptor(credential) client_kwargs = _prepare_mgmt_client_kwargs_track2(self.cli_ctx, sdk_cred) client = client_type(sdk_cred, api_version=api_version, base_url=self.cli_ctx.cloud.endpoints.resource_manager, @@ -984,11 +902,3 @@ def _create_identity_instance(cli_ctx, authority, tenant_id=None, client_id=None use_msal_http_cache=use_msal_http_cache, enable_broker_on_windows=enable_broker_on_windows, instance_discovery=instance_discovery) - - -def _use_msal_managed_identity(cli_ctx): - from azure.cli.core.telemetry import set_use_msal_managed_identity - # Use core.use_msal_managed_identity=false to use the old msrestazure implementation - use_msal_managed_identity = cli_ctx.config.getboolean('core', 'use_msal_managed_identity', fallback=True) - set_use_msal_managed_identity(use_msal_managed_identity) - return use_msal_managed_identity diff --git a/src/azure-cli-core/azure/cli/core/auth/adal_authentication.py b/src/azure-cli-core/azure/cli/core/auth/adal_authentication.py deleted file mode 100644 index 8aeabf4b7ca..00000000000 --- a/src/azure-cli-core/azure/cli/core/auth/adal_authentication.py +++ /dev/null @@ -1,129 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -import requests -from knack.log import get_logger -from msrestazure.azure_active_directory import MSIAuthentication - -from .util import scopes_to_resource, AccessToken - -logger = get_logger(__name__) - - -class MSIAuthenticationWrapper(MSIAuthentication): - # This method is exposed for Azure Core. Add *scopes, **kwargs to fit azure.core requirement - # pylint: disable=line-too-long - def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument - logger.debug("MSIAuthenticationWrapper.get_token: scopes=%r, kwargs=%r", scopes, kwargs) - - if 'data' in kwargs: - from azure.cli.core.util import in_cloud_console - if in_cloud_console(): - # Use MSAL to get VM SSH certificate - import msal - from .util import check_result, build_sdk_access_token - from .constants import AZURE_CLI_CLIENT_ID - app = msal.PublicClientApplication( - AZURE_CLI_CLIENT_ID, # Use a real client_id, so that cache would work - # TODO: This PoC does not currently maintain a token cache; - # Ideally we should reuse the real MSAL app object which has cache configured. - # token_cache=..., - ) - result = app.acquire_token_interactive(list(scopes), prompt="none", data=kwargs["data"]) - check_result(result, scopes=scopes) - return build_sdk_access_token(result) - - from azure.cli.core.azclierror import AuthenticationError - raise AuthenticationError("VM SSH currently doesn't support managed identity.") - - # Use msrestazure to get access token - resource = scopes_to_resource(scopes) - if resource: - # If available, use resource provided by SDK - self.resource = resource - self.set_token() - # VM managed identity endpoint 2018-02-01 token entry sample: - # curl "http://169.254.169.254:80/metadata/identity/oauth2/token?resource=https://management.core.windows.net/&api-version=2018-02-01" -H "Metadata: true" - # { - # "access_token": "eyJ0eXAiOiJKV...", - # "client_id": "da95e381-d7ab-4fdc-8047-2457909c723b", - # "expires_in": "86386", - # "expires_on": "1605238724", - # "ext_expires_in": "86399", - # "not_before": "1605152024", - # "resource": "https://management.core.windows.net/", - # "token_type": "Bearer" - # } - - # App Service managed identity endpoint 2017-09-01 token entry sample: - # curl "${MSI_ENDPOINT}?resource=https://management.core.windows.net/&api-version=2017-09-01" -H "secret: ${MSI_SECRET}" - # { - # "access_token": "eyJ0eXAiOiJKV...", - # "expires_on":"11/05/2021 15:18:31 +00:00", - # "resource":"https://management.core.windows.net/", - # "token_type":"Bearer", - # "client_id":"df45d93a-de31-47ca-acef-081ca60d1a83" - # } - return AccessToken(self.token['access_token'], _normalize_expires_on(self.token['expires_on'])) - - def set_token(self): - import traceback - from azure.cli.core.azclierror import AzureConnectionError, AzureResponseError - try: - super().set_token() - except requests.exceptions.ConnectionError as err: - logger.debug('throw requests.exceptions.ConnectionError when doing MSIAuthentication: \n%s', - traceback.format_exc()) - raise AzureConnectionError('Failed to connect to MSI. Please make sure MSI is configured correctly ' - 'and check the network connection.\nError detail: {}'.format(str(err))) - except requests.exceptions.HTTPError as err: - logger.debug('throw requests.exceptions.HTTPError when doing MSIAuthentication: \n%s', - traceback.format_exc()) - try: - raise AzureResponseError('Failed to connect to MSI. Please make sure MSI is configured correctly.\n' - 'Get Token request returned http error: {}, reason: {}' - .format(err.response.status, err.response.reason)) - except AttributeError: - raise AzureResponseError('Failed to connect to MSI. Please make sure MSI is configured correctly.\n' - 'Get Token request returned: {}'.format(err.response)) - except TimeoutError as err: - logger.debug('throw TimeoutError when doing MSIAuthentication: \n%s', - traceback.format_exc()) - raise AzureConnectionError('MSI endpoint is not responding. Please make sure MSI is configured correctly.\n' - 'Error detail: {}'.format(str(err))) - - def signed_session(self, session=None): - logger.debug("MSIAuthenticationWrapper.signed_session invoked by Track 1 SDK") - super().signed_session(session) - - def get_auxiliary_tokens(self, *scopes, **kwargs): # pylint:disable=no-self-use,unused-argument - """This method is added to align with CredentialAdaptor.get_auxiliary_tokens - Since managed identity belongs to a single tenant and currently doesn't support cross-tenant authentication, - simply return None.""" - return None - - -def _normalize_expires_on(expires_on): - """ - The expires_on field returned by managed identity differs on Azure VM (epoch str) and App Service (datetime str). - Normalize to epoch int. - """ - try: - # Treat as epoch string "1605238724" - expires_on_epoch_int = int(expires_on) - except ValueError: - import datetime - - # Python 3.6 doesn't recognize timezone as +00:00. - # These lines can be dropped after Python 3.6 is dropped. - # https://stackoverflow.com/questions/30999230/how-to-parse-timezone-with-colon - if expires_on[-3] == ":": - expires_on = expires_on[:-3] + expires_on[-2:] - - # Treat as datetime string "11/05/2021 15:18:31 +00:00" - expires_on_epoch_int = int(datetime.datetime.strptime(expires_on, '%m/%d/%Y %H:%M:%S %z').timestamp()) - - logger.debug("Normalize expires_on: %r -> %r", expires_on, expires_on_epoch_int) - return expires_on_epoch_int diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index 0fb4349ccc1..2388002f532 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -78,7 +78,6 @@ def __init__(self, correlation_id=None, application=None): self.enable_broker_on_windows = None self.msal_telemetry = None self.login_experience_v2 = None - self.use_msal_managed_identity = None def add_event(self, name, properties): for key in self.instrumentation_key: @@ -235,7 +234,6 @@ def _get_azure_cli_properties(self): set_custom_properties(result, 'EnableBrokerOnWindows', str(self.enable_broker_on_windows)) set_custom_properties(result, 'MsalTelemetry', self.msal_telemetry) set_custom_properties(result, 'LoginExperienceV2', str(self.login_experience_v2)) - set_custom_properties(result, 'UseMsalManagedIdentity', str(self.use_msal_managed_identity)) return result @@ -488,11 +486,6 @@ def set_msal_telemetry(msal_telemetry): @decorators.suppress_all_exceptions() def set_login_experience_v2(login_experience_v2): _session.login_experience_v2 = login_experience_v2 - - -@decorators.suppress_all_exceptions() -def set_use_msal_managed_identity(use_msal_managed_identity): - _session.use_msal_managed_identity = use_msal_managed_identity # endregion diff --git a/src/azure-cli-core/azure/cli/core/tests/test_profile.py b/src/azure-cli-core/azure/cli/core/tests/test_profile.py index 719a58ad014..e5b3da158f8 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_profile.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_profile.py @@ -100,39 +100,6 @@ def acquire_token(self, scopes, **kwargs): } -class MSRestAzureAuthStub: - - def __init__(self, *args, **kwargs): - self._token = { - 'token_type': 'Bearer', - 'access_token': TestProfile.test_mi_access_token, - 'expires_on': MOCK_EXPIRES_ON_STR - } - self.set_token_invoked_count = 0 - self.token_read_count = 0 - self.get_token_scopes = None - self.client_id = kwargs.get('client_id') - self.object_id = kwargs.get('object_id') - self.msi_res_id = kwargs.get('msi_res_id') - self.resource = kwargs.get('resource') - - def set_token(self): - self.set_token_invoked_count += 1 - - @property - def token(self): - self.token_read_count += 1 - return self._token - - @token.setter - def token(self, value): - self._token = value - - def get_token(self, *args, **kwargs): - self.get_token_scopes = args - return AccessToken(self.token['access_token'], int(self.token['expires_on'])) - - class TestProfile(unittest.TestCase): @classmethod @@ -534,111 +501,6 @@ def test_login_in_cloud_shell(self, cloud_shell_credential_mock, create_subscrip self.assertEqual(s['name'], self.display_name1) self.assertEqual(s['id'], self.id1.split('/')[-1]) - @mock.patch('requests.get', autospec=True) - @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_login_with_mi_system_assigned(self, create_subscription_client_mock, mock_get): - mock_subscription_client = mock.MagicMock() - mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] - create_subscription_client_mock.return_value = mock_subscription_client - - cli = DummyCli() - storage_mock = {'subscriptions': None} - profile = Profile(cli_ctx=cli, storage=storage_mock) - - test_token_entry = { - 'token_type': 'Bearer', - 'access_token': TestProfile.test_mi_access_token - } - encoded_test_token = json.dumps(test_token_entry).encode() - good_response = mock.MagicMock() - good_response.status_code = 200 - good_response.content = encoded_test_token - mock_get.return_value = good_response - - subscriptions = profile.login_with_managed_identity() - - # assert - self.assertEqual(len(subscriptions), 1) - s = subscriptions[0] - self.assertEqual(s['user']['name'], 'systemAssignedIdentity') - self.assertEqual(s['user']['type'], 'servicePrincipal') - self.assertEqual(s['user']['assignedIdentityInfo'], 'MSI') - self.assertEqual(s['name'], self.display_name1) - self.assertEqual(s['id'], self.id1.split('/')[-1]) - self.assertEqual(s['tenantId'], self.test_mi_tenant) - - @mock.patch('requests.get', autospec=True) - @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_login_with_mi_no_subscriptions(self, create_subscription_client_mock, mock_get): - mock_subscription_client = mock.MagicMock() - mock_subscription_client.subscriptions.list.return_value = [] - create_subscription_client_mock.return_value = mock_subscription_client - - cli = DummyCli() - storage_mock = {'subscriptions': None} - profile = Profile(cli_ctx=cli, storage=storage_mock) - - test_token_entry = { - 'token_type': 'Bearer', - 'access_token': TestProfile.test_mi_access_token - } - encoded_test_token = json.dumps(test_token_entry).encode() - good_response = mock.MagicMock() - good_response.status_code = 200 - good_response.content = encoded_test_token - mock_get.return_value = good_response - - subscriptions = profile.login_with_managed_identity(allow_no_subscriptions=True) - - # assert - self.assertEqual(len(subscriptions), 1) - s = subscriptions[0] - - self.assertEqual(s['name'], 'N/A(tenant level account)') - self.assertEqual(s['id'], self.test_mi_tenant) - self.assertEqual(s['tenantId'], self.test_mi_tenant) - - self.assertEqual(s['user']['name'], 'systemAssignedIdentity') - self.assertEqual(s['user']['type'], 'servicePrincipal') - self.assertEqual(s['user']['assignedIdentityInfo'], 'MSI') - - @mock.patch('requests.get', autospec=True) - @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_login_with_mi_user_assigned_client_id(self, create_subscription_client_mock, mock_get): - mock_subscription_client = mock.MagicMock() - mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] - create_subscription_client_mock.return_value = mock_subscription_client - - cli = DummyCli() - storage_mock = {'subscriptions': None} - profile = Profile(cli_ctx=cli, storage=storage_mock) - - test_token_entry = { - 'token_type': 'Bearer', - 'access_token': TestProfile.test_mi_access_token - } - test_client_id = '54826b22-38d6-4fb2-bad9-b7b93a3e9999' - encoded_test_token = json.dumps(test_token_entry).encode() - good_response = mock.MagicMock() - good_response.status_code = 200 - good_response.content = encoded_test_token - mock_get.return_value = good_response - - subscriptions = profile.login_with_managed_identity(client_id=test_client_id) - - self.assertEqual(len(subscriptions), 1) - s = subscriptions[0] - self.assertEqual(s['name'], self.display_name1) - self.assertEqual(s['id'], self.id1.split('/')[-1]) - self.assertEqual(s['tenantId'], self.test_mi_tenant) - - self.assertEqual(s['user']['name'], 'userAssignedIdentity') - self.assertEqual(s['user']['type'], 'servicePrincipal') - self.assertEqual(s['user']['assignedIdentityInfo'], 'MSIClient-{}'.format(test_client_id)) - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', autospec=True) @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) @@ -680,43 +542,9 @@ def set_token(self): self.assertEqual(s['user']['type'], 'servicePrincipal') self.assertEqual(s['user']['assignedIdentityInfo'], 'MSIObject-{}'.format(test_object_id)) - @mock.patch('requests.get', autospec=True) - @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_login_with_mi_user_assigned_resource_id(self, create_subscription_client_mock, - mock_get): - - mock_subscription_client = mock.MagicMock() - mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] - create_subscription_client_mock.return_value = mock_subscription_client - - cli = DummyCli() - storage_mock = {'subscriptions': None} - profile = Profile(cli_ctx=cli, storage=storage_mock) - - test_token_entry = { - 'token_type': 'Bearer', - 'access_token': TestProfile.test_mi_access_token - } - test_res_id = ('/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourcegroups/g1/' - 'providers/Microsoft.ManagedIdentity/userAssignedIdentities/id1') - - encoded_test_token = json.dumps(test_token_entry).encode() - good_response = mock.MagicMock() - good_response.status_code = 200 - good_response.content = encoded_test_token - mock_get.return_value = good_response - - subscriptions = profile.login_with_managed_identity(resource_id=test_res_id) - - s = subscriptions[0] - self.assertEqual(s['user']['name'], 'userAssignedIdentity') - self.assertEqual(s['user']['type'], 'servicePrincipal') - self.assertEqual(subscriptions[0]['user']['assignedIdentityInfo'], 'MSIResource-{}'.format(test_res_id)) - @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_login_with_mi_system_assigned_msal(self, create_subscription_client_mock): + def test_login_with_mi_system_assigned(self, create_subscription_client_mock): mock_subscription_client = mock.MagicMock() mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] create_subscription_client_mock.return_value = mock_subscription_client @@ -743,7 +571,7 @@ def test_login_with_mi_system_assigned_msal(self, create_subscription_client_moc @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_login_with_mi_system_assigned_no_subscriptions_msal(self, create_subscription_client_mock): + def test_login_with_mi_system_assigned_no_subscriptions(self, create_subscription_client_mock): mock_subscription_client = mock.MagicMock() mock_subscription_client.subscriptions.list.return_value = [] create_subscription_client_mock.return_value = mock_subscription_client @@ -772,7 +600,7 @@ def test_login_with_mi_system_assigned_no_subscriptions_msal(self, create_subscr @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_login_with_mi_user_assigned_client_id_msal(self, create_subscription_client_mock): + def test_login_with_mi_user_assigned_client_id(self, create_subscription_client_mock): mock_subscription_client = mock.MagicMock() mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] create_subscription_client_mock.return_value = mock_subscription_client @@ -800,7 +628,7 @@ def test_login_with_mi_user_assigned_client_id_msal(self, create_subscription_cl @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_login_with_mi_user_assigned_object_id_msal(self, create_subscription_client_mock): + def test_login_with_mi_user_assigned_object_id(self, create_subscription_client_mock): mock_subscription_client = mock.MagicMock() mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] create_subscription_client_mock.return_value = mock_subscription_client @@ -823,7 +651,7 @@ def test_login_with_mi_user_assigned_object_id_msal(self, create_subscription_cl @mock.patch('azure.cli.core._profile.SubscriptionFinder._create_subscription_client', autospec=True) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_login_with_mi_user_assigned_resource_id_msal(self, create_subscription_client_mock): + def test_login_with_mi_user_assigned_resource_id(self, create_subscription_client_mock): mock_subscription_client = mock.MagicMock() mock_subscription_client.subscriptions.list.return_value = [deepcopy(self.subscription1_raw)] create_subscription_client_mock.return_value = mock_subscription_client @@ -1157,95 +985,8 @@ def test_get_login_credentials_aux_tenants(self, get_user_credential_mock): aux_subscriptions=[test_subscription_id2], aux_tenants=[test_tenant_id2]) - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', MSRestAzureAuthStub) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_get_login_credentials_mi_system_assigned(self): - profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) - consolidated = profile._normalize_properties('systemAssignedIdentity', - [deepcopy(self.test_mi_subscription)], - True, - user_assigned_identity_id="MSI") - profile._set_subscriptions(consolidated) - - cred, subscription_id, _ = profile.get_login_credentials() - - self.assertEqual(subscription_id, self.test_mi_subscription_id) - - # sniff test the msi_auth object - cred.set_token() - cred.token - self.assertTrue(cred.set_token_invoked_count) - self.assertTrue(cred.token_read_count) - - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', MSRestAzureAuthStub) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_get_login_credentials_mi_user_assigned_with_client_id(self): - profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) - test_client_id = '12345678-38d6-4fb2-bad9-b7b93a3e8888' - consolidated = profile._normalize_properties('userAssignedIdentity', - [deepcopy(self.test_mi_subscription)], - True, - user_assigned_identity_id='MSIClient-{}'.format(test_client_id)) - profile._set_subscriptions(consolidated, secondary_key_name='name') - - cred, subscription_id, _ = profile.get_login_credentials() - - self.assertEqual(subscription_id, self.test_mi_subscription_id) - - # sniff test the msi_auth object - cred.set_token() - cred.token - self.assertTrue(cred.set_token_invoked_count) - self.assertTrue(cred.token_read_count) - self.assertTrue(cred.client_id, test_client_id) - - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', MSRestAzureAuthStub) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_get_login_credentials_mi_user_assigned_with_object_id(self): - profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) - test_object_id = '12345678-38d6-4fb2-bad9-b7b93a3e9999' - consolidated = profile._normalize_properties('userAssignedIdentity', - [deepcopy(self.test_mi_subscription)], - True, - user_assigned_identity_id='MSIObject-{}'.format(test_object_id)) - profile._set_subscriptions(consolidated, secondary_key_name='name') - - cred, subscription_id, _ = profile.get_login_credentials() - - self.assertEqual(subscription_id, self.test_mi_subscription_id) - - # sniff test the msi_auth object - cred.set_token() - cred.token - self.assertTrue(cred.set_token_invoked_count) - self.assertTrue(cred.token_read_count) - self.assertTrue(cred.object_id, test_object_id) - - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', MSRestAzureAuthStub) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_get_login_credentials_mi_user_assigned_with_res_id(self): - profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) - test_res_id = ('/subscriptions/{}/resourceGroups/r1/providers/Microsoft.ManagedIdentity/' - 'userAssignedIdentities/id1').format(self.test_mi_subscription_id) - consolidated = profile._normalize_properties('userAssignedIdentity', - [deepcopy(self.test_mi_subscription)], - True, - user_assigned_identity_id='MSIResource-{}'.format(test_res_id)) - profile._set_subscriptions(consolidated, secondary_key_name='name') - - cred, subscription_id, _ = profile.get_login_credentials() - - self.assertEqual(subscription_id, self.test_mi_subscription_id) - - # sniff test the msi_auth object - cred.set_token() - cred.token - self.assertTrue(cred.set_token_invoked_count) - self.assertTrue(cred.token_read_count) - self.assertTrue(cred.msi_res_id, test_res_id) - @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_login_credentials_mi_system_assigned_msal(self): + def test_get_login_credentials_mi_system_assigned(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties('systemAssignedIdentity', [deepcopy(self.test_mi_subscription)], @@ -1261,7 +1002,7 @@ def test_get_login_credentials_mi_system_assigned_msal(self): assert cred._credential.resource_id is None @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_login_credentials_mi_user_assigned_client_id_msal(self): + def test_get_login_credentials_mi_user_assigned_client_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', @@ -1279,7 +1020,7 @@ def test_get_login_credentials_mi_user_assigned_client_id_msal(self): assert cred._credential.resource_id is None @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_login_credentials_mi_user_assigned_object_id_msal(self): + def test_get_login_credentials_mi_user_assigned_object_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', @@ -1297,7 +1038,7 @@ def test_get_login_credentials_mi_user_assigned_object_id_msal(self): assert cred._credential.resource_id is None @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_login_credentials_mi_user_assigned_resource_id_msal(self): + def test_get_login_credentials_mi_user_assigned_resource_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', @@ -1402,48 +1143,9 @@ def test_get_raw_token_for_sp(self, get_service_principal_credential_mock): self.assertIsNone(sub) self.assertEqual(tenant, self.tenant_id) - @mock.patch('azure.cli.core.auth.adal_authentication.MSIAuthenticationWrapper', autospec=True) - @mock.patch.dict('os.environ', {'AZURE_CORE_USE_MSAL_MANAGED_IDENTITY': 'false'}) - def test_get_raw_token_mi_system_assigned(self, mock_msi_auth): - profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) - consolidated = profile._normalize_properties('systemAssignedIdentity', - [deepcopy(self.test_mi_subscription)], - True, - user_assigned_identity_id='MSI') - profile._set_subscriptions(consolidated) - - mi_auth_instance = None - - def mi_auth_factory(*args, **kwargs): - nonlocal mi_auth_instance - mi_auth_instance = MSRestAzureAuthStub(*args, **kwargs) - return mi_auth_instance - - mock_msi_auth.side_effect = mi_auth_factory - - # action - cred, subscription_id, tenant_id = profile.get_raw_token(resource=self.adal_resource) - - # Make sure resource/scopes are passed to MSIAuthenticationWrapper - assert mi_auth_instance.resource == self.adal_resource - assert list(mi_auth_instance.get_token_scopes) == self.msal_scopes - - self.assertEqual(cred[0], 'Bearer') - self.assertEqual(cred[1], self.test_mi_access_token) - - # Make sure expires_on and expiresOn are set - self.assertEqual(cred[2]['expires_on'], MOCK_EXPIRES_ON_INT) - self.assertEqual(cred[2]['expiresOn'], MOCK_EXPIRES_ON_DATETIME) - self.assertEqual(subscription_id, self.test_mi_subscription_id) - self.assertEqual(tenant_id, self.test_mi_tenant) - - # verify tenant shouldn't be specified for MSI account - with self.assertRaisesRegex(CLIError, "Tenant shouldn't be specified"): - cred, subscription_id, _ = profile.get_raw_token(resource='http://test_resource', tenant=self.tenant_id) - @mock.patch('azure.cli.core.auth.util._now_timestamp', new=_now_timestamp_mock) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_raw_token_mi_system_assigned_msal(self): + def test_get_raw_token_mi_system_assigned(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties('systemAssignedIdentity', [deepcopy(self.test_mi_subscription)], @@ -1477,7 +1179,7 @@ def test_get_raw_token_mi_system_assigned_msal(self): @mock.patch('azure.cli.core.auth.util._now_timestamp', new=_now_timestamp_mock) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_raw_token_mi_user_assigned_client_id_msal(self): + def test_get_raw_token_mi_user_assigned_client_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', @@ -1508,7 +1210,7 @@ def test_get_raw_token_mi_user_assigned_client_id_msal(self): @mock.patch('azure.cli.core.auth.util._now_timestamp', new=_now_timestamp_mock) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_raw_token_mi_user_assigned_object_id_msal(self): + def test_get_raw_token_mi_user_assigned_object_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', @@ -1539,7 +1241,7 @@ def test_get_raw_token_mi_user_assigned_object_id_msal(self): @mock.patch('azure.cli.core.auth.util._now_timestamp', new=_now_timestamp_mock) @mock.patch('azure.cli.core.auth.msal_credentials.ManagedIdentityCredential', ManagedIdentityCredentialStub) - def test_get_raw_token_mi_user_assigned_resource_id_msal(self): + def test_get_raw_token_mi_user_assigned_resource_id(self): profile = Profile(cli_ctx=DummyCli(), storage={'subscriptions': None}) consolidated = profile._normalize_properties( 'userAssignedIdentity', diff --git a/src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_aad_auth.py b/src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_aad_auth.py index 81d78e95019..dec416ac3aa 100644 --- a/src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_aad_auth.py +++ b/src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_aad_auth.py @@ -14,7 +14,6 @@ from azure.cli.command_modules.appconfig._utils import get_appconfig_data_client from azure.cli.core._profile import Profile from azure.cli.core.auth.credential_adaptor import CredentialAdaptor -from azure.cli.core.auth.adal_authentication import MSIAuthenticationWrapper from azure.cli.core.cloud import get_active_cloud from azure.cli.core.mock import DummyCli from knack.util import CLIError