diff --git a/src/azure-cli-core/azure/cli/core/_profile.py b/src/azure-cli-core/azure/cli/core/_profile.py index 71411aa430b..9e74199353c 100644 --- a/src/azure-cli-core/azure/cli/core/_profile.py +++ b/src/azure-cli-core/azure/cli/core/_profile.py @@ -19,7 +19,7 @@ from azure.cli.core._environment import get_config_dir from azure.cli.core._session import ACCOUNT from azure.cli.core.util import get_file_json, in_cloud_console, open_page_in_browser, can_launch_browser,\ - is_windows, is_wsl + is_windows, is_wsl, scopes_to_resource from azure.cli.core.cloud import get_active_cloud, set_cloud_subscription logger = get_logger(__name__) @@ -172,6 +172,7 @@ def find_subscriptions_on_login(self, password, is_service_principal, tenant, + scopes=None, use_device_code=False, allow_no_subscriptions=False, subscription_finder=None, @@ -180,6 +181,11 @@ def find_subscriptions_on_login(self, allow_debug_adal_connection() subscriptions = [] + if scopes: + auth_resource = scopes_to_resource(scopes) + else: + auth_resource = self._ad_resource_uri + if not subscription_finder: subscription_finder = SubscriptionFinder(self.cli_ctx, self.auth_ctx_factory, @@ -193,14 +199,14 @@ def find_subscriptions_on_login(self, try: authority_url, _ = _get_authority_url(self.cli_ctx, tenant) subscriptions = subscription_finder.find_through_authorization_code_flow( - tenant, self._ad_resource_uri, authority_url) + tenant, self._ad_resource_uri, authority_url, auth_resource=auth_resource) except RuntimeError: use_device_code = True logger.warning('Not able to launch a browser to log you in, falling back to device code...') if use_device_code: subscriptions = subscription_finder.find_through_interactive_flow( - tenant, self._ad_resource_uri) + tenant, self._ad_resource_uri, auth_resource=auth_resource) else: if is_service_principal: if not tenant: @@ -638,7 +644,6 @@ def get_msal_token(self, scopes, data): if 'error' in result: logger.warning(result['error_description']) - from azure.cli.core.util import scopes_to_resource token_entry = self._login_with_authorization_code_flow(tenant, scopes_to_resource(scopes)) result = cred.acquire_token_by_refresh_token(token_entry['refreshToken'], scopes, data=data) @@ -894,9 +899,9 @@ def find_from_user_account(self, username, password, tenant, resource): result = self._find_using_specific_tenant(tenant, token_entry[_ACCESS_TOKEN]) return result - def find_through_authorization_code_flow(self, tenant, resource, authority_url): + def find_through_authorization_code_flow(self, tenant, resource, authority_url, auth_resource=None): # launch browser and get the code - results = _get_authorization_code(resource, authority_url) + results = _get_authorization_code(auth_resource or resource, authority_url) if not results.get('code'): raise CLIError('Login failed') # error detail is already displayed through previous steps @@ -913,9 +918,9 @@ def find_through_authorization_code_flow(self, tenant, resource, authority_url): result = self._find_using_specific_tenant(tenant, token_entry[_ACCESS_TOKEN]) return result - def find_through_interactive_flow(self, tenant, resource): + def find_through_interactive_flow(self, tenant, resource, auth_resource=None): context = self._create_auth_context(tenant) - code = context.acquire_user_code(resource, _CLIENT_ID) + code = context.acquire_user_code(auth_resource or resource, _CLIENT_ID) logger.warning(code['message']) token_entry = context.acquire_token_with_device_code(resource, code, _CLIENT_ID) self.user_id = token_entry[_TOKEN_ENTRY_USER_ID] diff --git a/src/azure-cli/azure/cli/command_modules/profile/__init__.py b/src/azure-cli/azure/cli/command_modules/profile/__init__.py index 634f3e177bf..0f6bcfacd65 100644 --- a/src/azure-cli/azure/cli/command_modules/profile/__init__.py +++ b/src/azure-cli/azure/cli/command_modules/profile/__init__.py @@ -57,6 +57,7 @@ def load_arguments(self, command): c.argument('use_device_code', action='store_true', help="Use CLI's old authentication flow based on device code. CLI will also use this if it can't launch a browser in your behalf, e.g. in remote SSH or Cloud Shell") c.argument('use_cert_sn_issuer', action='store_true', help='used with a service principal configured with Subject Name and Issuer Authentication in order to support automatic certificate rolls') + c.argument('scopes', options_list=['--scope'], nargs='+', help='Used in the /authorize request. It can cover only one static resource.') with self.argument_context('logout') as c: c.argument('username', help='account user, if missing, logout the current active account') diff --git a/src/azure-cli/azure/cli/command_modules/profile/custom.py b/src/azure-cli/azure/cli/command_modules/profile/custom.py index c6ce073d4f9..185949cb09f 100644 --- a/src/azure-cli/azure/cli/command_modules/profile/custom.py +++ b/src/azure-cli/azure/cli/command_modules/profile/custom.py @@ -113,7 +113,7 @@ def account_clear(cmd): # pylint: disable=inconsistent-return-statements def login(cmd, username=None, password=None, service_principal=None, tenant=None, allow_no_subscriptions=False, - identity=False, use_device_code=False, use_cert_sn_issuer=None): + identity=False, use_device_code=False, use_cert_sn_issuer=None, scopes=None): """Log in to access Azure subscriptions""" from adal.adal_error import AdalError import requests @@ -155,6 +155,7 @@ def login(cmd, username=None, password=None, service_principal=None, tenant=None password, service_principal, tenant, + scopes=scopes, use_device_code=use_device_code, allow_no_subscriptions=allow_no_subscriptions, use_cert_sn_issuer=use_cert_sn_issuer)