Ejemplo n.º 1
0
def load_subscriptions(all_clouds=False, refresh=False):
    profile = Profile()
    if refresh:
        subscriptions = profile.refresh_accounts()
    subscriptions = profile.load_cached_subscriptions(all_clouds)
    return subscriptions
Ejemplo n.º 2
0
 def _get_token(server, resource, scope):  # pylint: disable=unused-argument
     return Profile(cli_ctx=cli_ctx).get_login_credentials(resource)[0]._token_retriever()  # pylint: disable=protected-access
Ejemplo n.º 3
0
def send_raw_request(cli_ctx, method, url, headers=None, uri_parameters=None,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
                     body=None, skip_authorization_header=False, resource=None, output_file=None,
                     generated_client_request_id_name='x-ms-client-request-id'):
    import uuid
    from requests import Session, Request
    from requests.structures import CaseInsensitiveDict

    result = CaseInsensitiveDict()
    for s in headers or []:
        try:
            temp = shell_safe_json_parse(s)
            result.update(temp)
        except CLIError:
            key, value = s.split('=', 1)
            result[key] = value
    headers = result

    # If Authorization header is already provided, don't bother with the token
    if 'Authorization' in headers:
        skip_authorization_header = True

    # Handle User-Agent
    agents = [get_az_user_agent()]

    # Borrow AZURE_HTTP_USER_AGENT from msrest
    # https://github.com/Azure/msrest-for-python/blob/4cc8bc84e96036f03b34716466230fb257e27b36/msrest/pipeline/universal.py#L70
    _ENV_ADDITIONAL_USER_AGENT = 'AZURE_HTTP_USER_AGENT'
    import os
    if _ENV_ADDITIONAL_USER_AGENT in os.environ:
        agents.append(os.environ[_ENV_ADDITIONAL_USER_AGENT])

    # Custom User-Agent provided as command argument
    if 'User-Agent' in headers:
        agents.append(headers['User-Agent'])
    headers['User-Agent'] = ' '.join(agents)

    if generated_client_request_id_name:
        headers[generated_client_request_id_name] = str(uuid.uuid4())

    # try to figure out the correct content type
    if body:
        try:
            _ = shell_safe_json_parse(body)
            if 'Content-Type' not in headers:
                headers['Content-Type'] = 'application/json'
        except Exception:  # pylint: disable=broad-except
            pass

    # add telemetry
    headers['CommandName'] = cli_ctx.data['command']
    if cli_ctx.data.get('safe_params'):
        headers['ParameterSetName'] = ' '.join(cli_ctx.data['safe_params'])

    result = {}
    for s in uri_parameters or []:
        try:
            temp = shell_safe_json_parse(s)
            result.update(temp)
        except CLIError:
            key, value = s.split('=', 1)
            result[key] = value
    uri_parameters = result or None

    # If url is an ARM resource ID, like /subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01,
    # default to Azure Resource Manager.
    # https://management.azure.com/ + subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01
    if '://' not in url:
        url = cli_ctx.cloud.endpoints.resource_manager + url.lstrip('/')

    # Replace common tokens with real values. It is for smooth experience if users copy and paste the url from
    # Azure Rest API doc
    from azure.cli.core._profile import Profile
    profile = Profile()
    if '{subscriptionId}' in url:
        url = url.replace('{subscriptionId}', cli_ctx.data['subscription_id'] or profile.get_subscription_id())

    token_subscription = None
    _subscription_regexes = [re.compile('https://management.azure.com/subscriptions/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})'),
                             re.compile('https://graph.windows.net/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})')]
    for regex in _subscription_regexes:
        match = regex.match(url)
        if match:
            token_subscription = match.groups()[0]
            logger.debug('Retrieve token from subscription %s', token_subscription)

    if not skip_authorization_header and url.lower().startswith('https://'):
        if not resource:
            endpoints = cli_ctx.cloud.endpoints
            # If url starts with ARM endpoint, like https://management.azure.com/,
            # use active_directory_resource_id for resource.
            # This follows the same behavior as azure.cli.core.commands.client_factory._get_mgmt_service_client
            if url.lower().startswith(endpoints.resource_manager.rstrip('/')):
                resource = endpoints.active_directory_resource_id
            else:
                from azure.cli.core.cloud import CloudEndpointNotSetException
                for p in [x for x in dir(endpoints) if not x.startswith('_')]:
                    try:
                        value = getattr(endpoints, p)
                    except CloudEndpointNotSetException:
                        continue
                    if isinstance(value, six.string_types) and url.lower().startswith(value.lower()):
                        resource = value
                        break
        if resource:
            token_info, _, _ = profile.get_raw_token(resource, subscription=token_subscription)
            logger.debug('Retrievd AAD token for resource: %s', resource or 'ARM')
            token_type, token, _ = token_info
            headers = headers or {}
            headers['Authorization'] = '{} {}'.format(token_type, token)
        else:
            logger.warning("Can't derive appropriate Azure AD resource from --url to acquire an access token. "
                           "If access token is required, use --resource to specify the resource")
    try:
        # https://requests.readthedocs.io/en/latest/user/advanced/#prepared-requests
        s = Session()
        req = Request(method=method, url=url, headers=headers, params=uri_parameters, data=body)
        prepped = s.prepare_request(req)

        # Merge environment settings into session
        settings = s.merge_environment_settings(prepped.url, {}, None, not should_disable_connection_verify(), None)
        _log_request(prepped)
        r = s.send(prepped, **settings)
        _log_response(r)
    except Exception as ex:  # pylint: disable=broad-except
        raise CLIError(ex)

    if not r.ok:
        reason = r.reason
        if r.text:
            reason += '({})'.format(r.text)
        raise CLIError(reason)
    if output_file:
        with open(output_file, 'wb') as fd:
            for chunk in r.iter_content(chunk_size=128):
                fd.write(chunk)
    return r
Ejemplo n.º 4
0
    def _initialize_session(self):
        """
        Creates a session using available authentication type.

        Auth priority:
        1. Token Auth
        2. Tenant Auth
        3. Azure CLI Auth

        """

        # Only run once
        if self.credentials is not None:
            return

        tenant_auth_variables = [
            constants.ENV_TENANT_ID, constants.ENV_SUB_ID,
            constants.ENV_CLIENT_ID, constants.ENV_CLIENT_SECRET
        ]

        token_auth_variables = [
            constants.ENV_ACCESS_TOKEN, constants.ENV_SUB_ID
        ]

        msi_auth_variables = [constants.ENV_USE_MSI, constants.ENV_SUB_ID]

        if self.authorization_file:
            self.credentials, self.subscription_id = self.load_auth_file(
                self.authorization_file)
            self.log.info("Creating session with authorization file")

        elif all(k in os.environ for k in token_auth_variables):
            # Token authentication
            self.credentials = BasicTokenAuthentication(
                token={'access_token': os.environ[constants.ENV_ACCESS_TOKEN]})
            self.subscription_id = os.environ[constants.ENV_SUB_ID]
            self.log.info("Creating session with Token Authentication")
            self._is_token_auth = True

        elif all(k in os.environ for k in tenant_auth_variables):
            # Tenant (service principal) authentication
            self.credentials = ServicePrincipalCredentials(
                client_id=os.environ[constants.ENV_CLIENT_ID],
                secret=os.environ[constants.ENV_CLIENT_SECRET],
                tenant=os.environ[constants.ENV_TENANT_ID],
                resource=self.resource_namespace)
            self.subscription_id = os.environ[constants.ENV_SUB_ID]
            self.tenant_id = os.environ[constants.ENV_TENANT_ID]
            self.log.info(
                "Creating session with Service Principal Authentication")

        elif all(k in os.environ for k in msi_auth_variables):
            # MSI authentication
            if constants.ENV_CLIENT_ID in os.environ:
                self.credentials = MSIAuthentication(
                    client_id=os.environ[constants.ENV_CLIENT_ID],
                    resource=self.resource_namespace)
            else:
                self.credentials = MSIAuthentication(
                    resource=self.resource_namespace)

            self.subscription_id = os.environ[constants.ENV_SUB_ID]
            self.log.info("Creating session with MSI Authentication")
        else:
            # Azure CLI authentication
            self._is_cli_auth = True
            (self.credentials, self.subscription_id,
             self.tenant_id) = Profile().get_login_credentials(
                 resource=self.resource_namespace)

            self.log.info("Creating session with Azure CLI Authentication")

        # TODO: cleanup this workaround when issue resolved.
        # https://github.com/Azure/azure-sdk-for-python/issues/5096
        if self.resource_namespace == constants.RESOURCE_VAULT:
            access_token = AccessToken(token=self.get_bearer_token())
            self.credentials = KeyVaultAuthentication(
                lambda _1, _2, _3: access_token)

        # Let provided id parameter override everything else
        if self.subscription_id_override is not None:
            self.subscription_id = self.subscription_id_override

        self.log.info("Session using Subscription ID: %s" %
                      self.subscription_id)

        if self.credentials is None:
            self.log.error('Unable to locate credentials for Azure session.')
Ejemplo n.º 5
0
from azure.cli.core.application import Configuration
from azure.cli.core.commands import LongRunningOperation, get_op_handler
from azure.cli.core.cloud import get_active_cloud_name
from azure.cli.core._config import az_config, DEFAULTS_SECTION
from azure.cli.core._environment import get_config_dir
from azure.cli.core._profile import _SUBSCRIPTION_NAME, Profile
from azure.cli.core._session import ACCOUNT, CONFIG, SESSION
import azure.cli.core.telemetry as cli_telemetry
from azure.cli.core.util import (show_version_info_exit, handle_exception)
from azure.cli.core.util import CLIError

SHELL_CONFIGURATION = azclishell.configuration.CONFIGURATION
SHELL_CONFIG_DIR = azclishell.configuration.get_config_dir

NOTIFICATIONS = ""
PROFILE = Profile()
SELECT_SYMBOL = azclishell.configuration.SELECT_SYMBOL
PART_SCREEN_EXAMPLE = .3
START_TIME = datetime.datetime.utcnow()
CLEAR_WORD = get_os_clear_screen_word()


def space_examples(list_examples, rows):
    """ makes the example text """
    examples_with_index = []

    for i, _ in list(enumerate(list_examples)):
        examples_with_index.append("[" + str(i + 1) + "] " +
                                   list_examples[i][0] + list_examples[i][1])

    example = "".join(exam for exam in examples_with_index)
Ejemplo n.º 6
0
 def test_create_token_cache(self, mock_read_file):
     mock_read_file.return_value = []
     profile = Profile()
     cache = profile._creds_cache.adal_token_cache
     self.assertFalse(cache.read_items())
     self.assertTrue(mock_read_file.called)
Ejemplo n.º 7
0
def _get_profile():
    from azure.cli.core._profile import Profile
    return Profile(cli_ctx=_session.application)
Ejemplo n.º 8
0
def get_subscription_id():
    profile = Profile()
    _, subscription_id, _ = profile.get_login_credentials()
    return subscription_id
Ejemplo n.º 9
0
def createDeployment(cmd,
                     name,
                     location,
                     templateId,
                     description=None,
                     parameters=None,
                     parameterFile=None,
                     solutionStorageConnectionString=None,
                     subscription=None):
    """Creates a deployment with the specified parameters.
    name: The name of the deployment. (must be alphanumeric lowercase between 3 to 9 characters beginning with a letter)
    location: The location to deploy the solution to.
    templateId: The unique id of the template which the deployment will be bulit from.
    description[optional]: The optional description of the deployment.
    parameters[optional]:
    solutionStorageConnectionString[optional]:
    subscription[optional]: Provides an alternate subscription to use if desired.
    """
    if subscription is None:
        subscription = get_subscription_id(cmd.cli_ctx)
        logger.info("Using default subscription: " + subscription)
    profile = Profile(cli_ctx=cmd.cli_ctx)
    auth_token = profile.get_raw_token(subscription=subscription)
    if parameters is not None and parameterFile is not None:
        raise CLIError(
            "May not have parameters and a parameters file at the same time.")
    elif parameterFile is not None:
        logger.info("Using parameter file: " + parameterFile)
        try:
            with open(parameterFile) as jsonfile:
                parameters = json.load(jsonfile)
            logger.info("Parameters loaded.")
        except IOError:
            raise CLIError("Could not open file.")
    elif parameters is not None:
        logger.info("Using parameters from commandline argument.")
        validators.validate_json_arg(parameters)
        parameters = json.loads(parameters)
        logger.info("Parameters loaded")
    creds = authentication.BasicTokenAuthentication(
        {'access_token': auth_token[0][1]})
    ciqsapi = ciqs_api.CiqsApi(creds=creds, base_url=api.getEndpoint())
    request = models.MicrosoftCiqsModelsDeploymentCreateDeploymentRequest(
        name,
        location,
        template_id=templateId,
        subscription=subscription,
        description=description,
        referrer='az ciqs',
        solution_storage_connection_string=solutionStorageConnectionString,
        parameters=parameters)
    try:
        logger.info("Sending request.")
        response = ciqsapi.post_api_deployments_by_subscription_id_by_template_id(
            subscription_id=subscription,
            template_id=templateId,
            body=request,
            ms_asm_refresh_token=auth_token[0][2]['refreshToken'])
    except msrest.exceptions.HttpOperationError as e:
        message = e.response.json()
        raise CLIError(message)
    return response
Ejemplo n.º 10
0
def _call_rp_configure_cicd(
        target_name,
        target_resource_group,
        vsts_account_name,
        vsts_project_name,
        registry_name,
        registry_resource_id,
        remote_url,
        remote_branch,
        remote_access_token,
        create_release=True):
    """
    Calls the RP to build and deploy the service(s) in the cluster.

    :param target_name: Name of the target Azure container service instance to deploy containers to.
    :type target_name: String
    :param target_resource_group: Name of Azure container service's resource group.
    :type target_resource_group: String
    :param remote_url: Remote url of the GitHub or VSTS source repository that will be built and deployed. If omitted, a source repository will be searched for in the current working directory.
    :type remote_url: String
    :param remote_branch: Remote branch of the GitHub or VSTS source repository that will be built and deployed. If omitted refs/heads/master will be selected.
    :type remote_branch: String
    :param remote_access_token: GitHub personal access token (minimum permission is 'repo'). Required if the source repository is in GitHub.
    :type remote_access_token: String
    :param vsts_account_name: VSTS account name to create the build and release definitions. A new VSTS account is created if omitted or does not exist.
    :type vsts_account_name: String
    :param vsts_project_name: VSTS project name to create the build and release definitions. A new VSTS project is created if omitted or does not exist.
    :type vsts_project_name: String
    :param registry_resource_id: Azure container registry resource id.
    :type registry_resource_id: String
    :param registry_name: Azure container registry name. A new Azure container registry is created if omitted or does not exist.
    :type registry_name: String
    :param create_release: Whether to create a release definition and deploy the application.
    :type create_release: bool
    """
    profile = Profile()
    cred, subscription_id, _ = profile.get_login_credentials()

    o_auth_token = cred.signed_session().headers['Authorization']
    container_service_resource_id = CONTAINER_SERVICE_RESOURCE_URL.format(subscription_id=subscription_id, resource_group_name=target_resource_group, container_service_name=target_name)
    data = {
        'acsResourceId': container_service_resource_id,
        'vstsAccountName': vsts_account_name,
        'vstsProjectName': vsts_project_name,
        'registryName': registry_name,
        'registryResourceId': registry_resource_id,
        'remoteToken': remote_access_token,
        'remoteUrl': remote_url,
        'remoteBranch': remote_branch,
        'createRelease' : create_release
    }

    configure_ci_cd_url = SERVICE_URL.format(
        subscription_id=subscription_id) + '/configureCI?api-version=' + API_VERSION

    headers = {}
    headers['Authorization'] = o_auth_token
    headers['Content-Type'] = 'application/json; charset=utf-8'
    headers['x-ms-client-request-id'] = str(uuid.uuid1())
    req = requests.post(configure_ci_cd_url, data=json.dumps(data), headers=headers, timeout=600)
    while req.status_code == 202:  # Long-running operation
        time.sleep(10)
        req = requests.get(BASE_URL + req.headers['Location'], headers=headers, timeout=600)
    if req.status_code != 200:
        raise CLIError(
            'Server returned status code: ' + str(req.status_code) + '. Could not configure CI/CD: ' + req.text)
    json_request = req.json()
    return json_request
Ejemplo n.º 11
0
    def create_bot_json(
            cmd,
            client,
            resource_group_name,
            resource_name,
            logger,
            app_password=None,  # pylint:disable=too-many-locals
            raw_bot_properties=None,
            password_only=True):
        """

        :param cmd:
        :param client:
        :param resource_group_name:
        :param resource_name:
        :param logger:
        :param app_password:
        :param raw_bot_properties:
        :return: Dictionary
        """
        if not raw_bot_properties:
            raw_bot_properties = client.bots.get(
                resource_group_name=resource_group_name,
                resource_name=resource_name)

        # Initialize names bot_file and secret to capture botFilePath and botFileSecret values from the application's
        # settings.
        bot_file = None
        bot_file_secret = None
        profile = Profile(cli_ctx=cmd.cli_ctx)
        if not app_password:
            site_name = WebAppOperations.get_bot_site_name(
                raw_bot_properties.properties.endpoint)
            app_settings = WebAppOperations.get_app_settings(
                cmd=cmd,
                resource_group_name=resource_group_name,
                name=site_name)

            app_password_values = [
                item['value'] for item in app_settings
                if item['name'] == 'MicrosoftAppPassword'
            ]
            app_password = app_password_values[
                0] if app_password_values else None
            if not app_password:
                bot_file_values = [
                    item['value'] for item in app_settings
                    if item['name'] == 'botFilePath'
                ]
                bot_file = bot_file_values[0] if bot_file_values else None
                bot_file_secret_values = [
                    item['value'] for item in app_settings
                    if item['name'] == 'botFileSecret'
                ]
                bot_file_secret = bot_file_secret_values[
                    0] if bot_file_secret_values else None

        if not bot_file and not app_password:
            bot_site_name = WebAppOperations.get_bot_site_name(
                raw_bot_properties.properties.endpoint)
            scm_url = WebAppOperations.get_scm_url(cmd, resource_group_name,
                                                   bot_site_name, None)

            # TODO: Reevaluate "Public-or-Gov" Azure logic.
            is_public_azure = (
                'azurewebsites.net' in raw_bot_properties.properties.endpoint
                or '.net' in raw_bot_properties.properties.endpoint
                or '.com' in raw_bot_properties.properties.endpoint)
            host = 'https://portal.azure.com/' if is_public_azure else 'https://portal.azure.us/'
            subscription_id = get_subscription_id(cmd.cli_ctx)
            tenant_id = profile.get_subscription(
                subscription=client.config.subscription_id)['tenantId']
            settings_url = host + '#@{}/resource/subscriptions/{}/resourceGroups/{}/providers/Microsoft.BotService/botServices/{}/app_settings'.format(tenant_id, subscription_id, resource_group_name, resource_name)  # pylint: disable=line-too-long

            logger.warning(
                '"MicrosoftAppPassword" and "botFilePath" not found in application settings'
            )
            logger.warning(
                'To see your bot\'s application settings, visit %s' %
                settings_url)
            logger.warning(
                'To visit your deployed bot\'s code on Azure, visit Kudu for your bot at %s'
                % scm_url)

        elif not app_password and bot_file:
            # We have the information we need to obtain the MSA App app password via bot file data from Kudu.
            kudu_client = KuduClient(cmd, resource_group_name, resource_name,
                                     raw_bot_properties, logger)
            bot_file_data = kudu_client.get_bot_file(bot_file)
            app_password = BotJsonFormatter.__decrypt_bot_file(
                bot_file_data, bot_file_secret, logger, password_only)

        return {
            'type':
            'abs',
            'id':
            raw_bot_properties.name,
            'name':
            raw_bot_properties.properties.display_name,
            'appId':
            raw_bot_properties.properties.msa_app_id,
            'appPassword':
            app_password,
            'endpoint':
            raw_bot_properties.properties.endpoint,
            'resourceGroup':
            str(resource_group_name),
            'tenantId':
            profile.get_subscription(
                subscription=client.config.subscription_id)['tenantId'],
            'subscriptionId':
            client.config.subscription_id,
            'serviceName':
            resource_name
        }
Ejemplo n.º 12
0
def create_service_principal_for_rbac(
        # pylint:disable=too-many-arguments,too-many-statements,too-many-locals, too-many-branches
        name=None,
        password=None,
        years=1,
        create_cert=False,
        cert=None,
        scopes=None,
        role='Contributor',
        expanded_view=None,
        skip_assignment=False):
    '''create a service principal and configure its access to Azure resources
    :param str name: a display name or an app id uri. Command will generate one if missing.
    :param str password: the password used to login. If missing, command will generate one.
    :param str cert: PEM formatted public certificate. Do not include private key info.
    :param str years: Years the password will be valid.
    :param str scopes: space separated scopes the service principal's role assignment applies to.
           Defaults to the root of the current subscription.
    :param str role: role the service principal has on the resources.
    '''
    import time
    graph_client = _graph_client_factory()
    role_client = _auth_client_factory().role_assignments
    scopes = scopes or ['/subscriptions/' + role_client.config.subscription_id]
    sp_oid = None
    _RETRY_TIMES = 36

    app_display_name = None
    if name and '://' not in name:
        app_display_name = name
        name = "http://" + name  # normalize be a valid graph service principal name

    if name:
        query_exp = 'servicePrincipalNames/any(x:x eq \'{}\')'.format(name)
        aad_sps = list(graph_client.service_principals.list(filter=query_exp))
        if aad_sps:
            raise CLIError("'{}' already exists.".format(name))

    # pylint: disable=protected-access
    public_cert_string = None
    cert_file = None
    password = None

    if len([x for x in [cert, create_cert, password] if x]) > 1:
        raise CLIError('Usage error: --cert | --create-cert | --password')
    if create_cert:
        public_cert_string, cert_file = _create_self_signed_cert(years)
    elif cert:
        public_cert_string = cert
    else:
        password = password or str(uuid.uuid4())

    start_date = datetime.datetime.utcnow()
    app_display_name = app_display_name or (
        'azure-cli-' + start_date.strftime('%Y-%m-%d-%H-%M-%S'))
    if name is None:
        name = 'http://' + app_display_name  # just a valid uri, no need to exist

    end_date = start_date + relativedelta(years=years)

    aad_application = create_application(
        graph_client.applications,
        display_name=app_display_name,
        # pylint: disable=too-many-function-args
        homepage='http://' + app_display_name,
        identifier_uris=[name],
        available_to_other_tenants=False,
        password=password,
        key_value=public_cert_string,
        start_date=start_date,
        end_date=end_date)
    # pylint: disable=no-member
    app_id = aad_application.app_id
    # retry till server replication is done
    for l in range(0, _RETRY_TIMES):
        try:
            aad_sp = _create_service_principal(app_id, resolve_app=False)
            break
        except Exception as ex:  # pylint: disable=broad-except
            # pylint: disable=line-too-long
            if l < _RETRY_TIMES and (' does not reference ' in str(ex)
                                     or ' does not exist ' in str(ex)):
                time.sleep(5)
                logger.warning('Retrying service principal creation: %s/%s',
                               l + 1, _RETRY_TIMES)
            else:
                logger.warning(
                    "Creating service principal failed for appid '%s'. Trace followed:\n%s",
                    name,
                    ex.response.headers if hasattr(ex, 'response') else ex)  # pylint: disable=no-member
                raise
    sp_oid = aad_sp.object_id

    # retry while server replication is done
    if not skip_assignment:
        # pylint: disable=line-too-long
        for scope in scopes:
            for l in range(0, _RETRY_TIMES):
                try:
                    _create_role_assignment(role,
                                            sp_oid,
                                            None,
                                            scope,
                                            resolve_assignee=False)
                    break
                except Exception as ex:
                    if l < _RETRY_TIMES and ' does not exist in the directory ' in str(
                            ex):
                        time.sleep(5)
                        logger.warning(
                            'Retrying role assignment creation: %s/%s', l + 1,
                            _RETRY_TIMES)
                        continue
                    else:
                        # dump out history for diagnoses
                        logger.warning('Role assignment creation failed.\n')
                        if getattr(ex, 'response', None) is not None:
                            logger.warning(
                                'role assignment response headers: %s\n',
                                ex.response.headers)  # pylint: disable=no-member
                    raise

    if expanded_view:
        from azure.cli.core._profile import Profile
        profile = Profile()
        result = profile.get_expanded_subscription_info(
            scopes[0].split('/')[2] if scopes else None, app_id, password)
    else:
        result = {
            'appId': app_id,
            'password': password,
            'name': name,
            'displayName': app_display_name,
            'tenant': graph_client.config.tenant_id
        }
        if cert_file:
            # pylint: disable=line-too-long
            logger.warning(
                "Please copy %s to a safe place. When run 'az login' provide the file path to the --password argument",
                cert_file)
            result['fileWithCertAndPrivateKey'] = cert_file
    return result
Ejemplo n.º 13
0
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):
    """Log in to access Azure subscriptions"""
    from adal.adal_error import AdalError
    import requests

    # quick argument usage check
    if any([password, service_principal, tenant]) and identity:
        raise CLIError(
            "usage error: '--identity' is not applicable with other arguments")
    if any([password, service_principal, username, identity
            ]) and use_device_code:
        raise CLIError(
            "usage error: '--use-device-code' is not applicable with other arguments"
        )
    if use_cert_sn_issuer and not service_principal:
        raise CLIError(
            "usage error: '--use-sn-issuer' is only applicable with a service principal"
        )
    if service_principal and not username:
        raise CLIError(
            'usage error: --service-principal --username NAME --password SECRET --tenant TENANT'
        )

    interactive = False

    profile = Profile(cli_ctx=cmd.cli_ctx, async_persist=False)

    if identity:
        if in_cloud_console():
            return profile.find_subscriptions_in_cloud_console()
        return profile.find_subscriptions_in_vm_with_msi(
            username, allow_no_subscriptions)
    if in_cloud_console():  # tell users they might not need login
        logger.warning(_CLOUD_CONSOLE_LOGIN_WARNING)

    if username:
        if not password:
            try:
                password = prompt_pass('Password: '******'Please specify both username and password in non-interactive mode.'
                )
    else:
        interactive = True

    try:
        subscriptions = profile.find_subscriptions_on_login(
            interactive,
            username,
            password,
            service_principal,
            tenant,
            use_device_code=use_device_code,
            allow_no_subscriptions=allow_no_subscriptions,
            use_cert_sn_issuer=use_cert_sn_issuer)
    except AdalError as err:
        # try polish unfriendly server errors
        if username:
            msg = str(err)
            suggestion = "For cross-check, try 'az login' to authenticate through browser."
            if ('ID3242:' in msg) or ('Server returned an unknown AccountType'
                                      in msg):
                raise CLIError("The user name might be invalid. " + suggestion)
            if 'Server returned error in RSTR - ErrorCode' in msg:
                raise CLIError(
                    "Logging in through command line is not supported. " +
                    suggestion)
            if 'wstrust' in msg:
                raise CLIError(
                    "Authentication failed due to error of '" + msg + "' "
                    "This typically happens when attempting a Microsoft account, which requires "
                    "interactive login. Please invoke 'az login' to cross check. "
                    # pylint: disable=line-too-long
                    "More details are available at https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Username-Password-Authentication"
                )
        raise CLIError(err)
    except requests.exceptions.SSLError as err:
        from azure.cli.core.util import SSLERROR_TEMPLATE
        raise CLIError(SSLERROR_TEMPLATE.format(str(err)))
    except requests.exceptions.ConnectionError as err:
        raise CLIError(
            'Please ensure you have network connection. Error detail: ' +
            str(err))
    all_subscriptions = list(subscriptions)
    for sub in all_subscriptions:
        sub['cloudName'] = sub.pop('environmentName', None)
    return all_subscriptions
Ejemplo n.º 14
0
def login(username=None,
          password=None,
          service_principal=None,
          tenant=None,
          allow_no_subscriptions=False):
    """Log in to access Azure subscriptions"""
    import os
    import re
    from adal.adal_error import AdalError
    import requests
    interactive = False

    profile = Profile()

    if username:
        if not password:
            # in a VM with managed service identity?
            result = profile.init_if_in_msi_env(username)
            if result:
                return result
            try:
                password = prompt_pass('Password: '******'Please specify both username and password in non-interactive mode.'
                )
    else:
        # in a cloud console?
        console_tokens = os.environ.get('AZURE_CONSOLE_TOKENS', None)
        if console_tokens:
            return profile.find_subscriptions_in_cloud_console(
                re.split(';|,', console_tokens))

        interactive = True

    try:
        subscriptions = profile.find_subscriptions_on_login(
            interactive,
            username,
            password,
            service_principal,
            tenant,
            allow_no_subscriptions=allow_no_subscriptions)
    except AdalError as err:
        # try polish unfriendly server errors
        if username:
            msg = str(err)
            suggestion = "For cross-check, try 'az login' to authenticate through browser."
            if ('ID3242:' in msg) or ('Server returned an unknown AccountType'
                                      in msg):
                raise CLIError("The user name might be invalid. " + suggestion)
            if 'Server returned error in RSTR - ErrorCode' in msg:
                raise CLIError(
                    "Logging in through command line is not supported. " +
                    suggestion)
        raise CLIError(err)
    except requests.exceptions.ConnectionError as err:
        raise CLIError(
            'Please ensure you have network connection. Error detail: ' +
            str(err))
    all_subscriptions = list(subscriptions)
    for sub in all_subscriptions:
        sub['cloudName'] = sub.pop('environmentName', None)
    return all_subscriptions
Ejemplo n.º 15
0
def _get_profile():
    from azure.cli.core._profile import Profile
    return Profile()
Ejemplo n.º 16
0
def load_subscriptions(all_clouds=False):
    profile = Profile()
    subscriptions = profile.load_cached_subscriptions(all_clouds)
    return subscriptions
Ejemplo n.º 17
0
def get_subscription_id(cli_ctx):
    from azure.cli.core._profile import Profile
    if not cli_ctx.data.get('subscription_id'):
        cli_ctx.data['subscription_id'] = Profile(
            cli_ctx=cli_ctx).get_subscription_id()
    return cli_ctx.data['subscription_id']
Ejemplo n.º 18
0
def show_subscription(subscription=None, expanded_view=None):
    profile = Profile()
    if not expanded_view:
        return profile.get_subscription(subscription)
    else:
        return profile.get_expanded_subscription_info(subscription)
Ejemplo n.º 19
0
def create_keyvault(
        cmd,
        client,  # pylint: disable=too-many-locals
        resource_group_name,
        vault_name,
        location=None,
        sku=None,
        enabled_for_deployment=None,
        enabled_for_disk_encryption=None,
        enabled_for_template_deployment=None,
        enable_soft_delete=None,
        enable_purge_protection=None,
        bypass=None,
        default_action=None,
        no_self_perms=None,
        tags=None):
    from azext_keyvault.mgmt.keyvault.models import (
        VaultCreateOrUpdateParameters, Permissions, KeyPermissions,
        SecretPermissions, CertificatePermissions, StoragePermissions,
        AccessPolicyEntry, Sku, VaultProperties)
    from azure.cli.core._profile import Profile
    from azure.graphrbac.models import GraphErrorException
    from azure.graphrbac import GraphRbacManagementClient

    profile = Profile(cli_ctx=cmd.cli_ctx)
    cred, _, tenant_id = profile.get_login_credentials(
        resource=cmd.cli_ctx.cloud.endpoints.active_directory_graph_resource_id
    )

    graph_client = GraphRbacManagementClient(
        cred,
        tenant_id,
        base_url=cmd.cli_ctx.cloud.endpoints.active_directory_graph_resource_id
    )
    subscription = profile.get_subscription()

    # if bypass or default_action was specified create a NetworkRuleSet
    # if neither were specified we make network_acls None
    network_acls = _create_network_rule_set(
        bypass, default_action) if bypass or default_action else None

    if no_self_perms:
        access_policies = []
    else:
        permissions = Permissions(
            keys=[
                KeyPermissions.get, KeyPermissions.create,
                KeyPermissions.delete, KeyPermissions.list,
                KeyPermissions.update, KeyPermissions.import_enum,
                KeyPermissions.backup, KeyPermissions.restore,
                KeyPermissions.recover
            ],
            secrets=[
                SecretPermissions.get, SecretPermissions.list,
                SecretPermissions.set, SecretPermissions.delete,
                SecretPermissions.backup, SecretPermissions.restore,
                SecretPermissions.recover
            ],
            certificates=[
                CertificatePermissions.get, CertificatePermissions.list,
                CertificatePermissions.delete, CertificatePermissions.create,
                CertificatePermissions.import_enum,
                CertificatePermissions.update,
                CertificatePermissions.managecontacts,
                CertificatePermissions.getissuers,
                CertificatePermissions.listissuers,
                CertificatePermissions.setissuers,
                CertificatePermissions.deleteissuers,
                CertificatePermissions.manageissuers,
                CertificatePermissions.recover
            ],
            storage=[
                StoragePermissions.get, StoragePermissions.list,
                StoragePermissions.delete, StoragePermissions.set,
                StoragePermissions.update, StoragePermissions.regeneratekey,
                StoragePermissions.setsas, StoragePermissions.listsas,
                StoragePermissions.getsas, StoragePermissions.deletesas
            ])
        try:
            object_id = _get_current_user_object_id(graph_client)
        except GraphErrorException:
            object_id = _get_object_id(graph_client, subscription=subscription)
        if not object_id:
            raise CLIError(
                'Cannot create vault.\nUnable to query active directory for information '
                'about the current user.\nYou may try the --no-self-perms flag to '
                'create a vault without permissions.')
        access_policies = [
            AccessPolicyEntry(tenant_id=tenant_id,
                              object_id=object_id,
                              permissions=permissions)
        ]
    properties = VaultProperties(
        tenant_id=tenant_id,
        sku=Sku(name=sku),
        access_policies=access_policies,
        vault_uri=None,
        enabled_for_deployment=enabled_for_deployment,
        enabled_for_disk_encryption=enabled_for_disk_encryption,
        enabled_for_template_deployment=enabled_for_template_deployment,
        enable_soft_delete=enable_soft_delete,
        enable_purge_protection=enable_purge_protection,
        network_acls=network_acls)
    parameters = VaultCreateOrUpdateParameters(location=location,
                                               tags=tags,
                                               properties=properties)
    return client.create_or_update(resource_group_name=resource_group_name,
                                   vault_name=vault_name,
                                   parameters=parameters)
Ejemplo n.º 20
0
def account_clear():
    """Clear all stored subscriptions. To clear individual, use 'logout'"""
    profile = Profile()
    profile.logout_all()
Ejemplo n.º 21
0
def _get_aad_token(cli_ctx,
                   login_server,
                   only_refresh_token,
                   repository=None,
                   permission='*'):
    """Obtains refresh and access tokens for an AAD-enabled registry.
    :param str login_server: The registry login server URL to log in to
    :param bool only_refresh_token: Whether to ask for only refresh token, or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    login_server = login_server.rstrip('/')

    challenge = requests.get('https://' + login_server + '/v2/',
                             verify=(not should_disable_connection_verify()))
    if challenge.status_code not in [
            401
    ] or 'WWW-Authenticate' not in challenge.headers:
        raise CLIError(
            "Registry '{}' did not issue a challenge.".format(login_server))

    authenticate = challenge.headers['WWW-Authenticate']

    tokens = authenticate.split(' ', 2)
    if len(tokens) < 2 or tokens[0].lower() != 'bearer':
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    params = {
        y[0]: y[1].strip('"')
        for y in (x.strip().split('=', 2) for x in tokens[1].split(','))
    }
    if 'realm' not in params or 'service' not in params:
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    authurl = urlparse(params['realm'])
    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cli_ctx)
    creds, _, tenant = profile.get_raw_token()

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    content = {
        'grant_type': 'access_token',
        'service': params['service'],
        'tenant': tenant,
        'access_token': creds[1]
    }

    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))

    if response.status_code not in [200]:
        raise CLIError(
            "Access to registry '{}' was denied. Response code: {}.".format(
                login_server, response.status_code))

    refresh_token = loads(response.content.decode("utf-8"))["refresh_token"]
    if only_refresh_token:
        return refresh_token

    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/token', '', '', ''))

    if repository is None:
        scope = 'registry:catalog:*'
    else:
        scope = 'repository:{}:{}'.format(repository, permission)

    content = {
        'grant_type': 'refresh_token',
        'service': login_server,
        'scope': scope,
        'refresh_token': refresh_token
    }
    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))
    access_token = loads(response.content.decode("utf-8"))["access_token"]

    return access_token
Ejemplo n.º 22
0
def set_active_subscription(cmd, subscription):
    """Set the current subscription"""
    profile = Profile(cli_ctx=cmd.cli_ctx)
    if not id:
        raise CLIError('Please provide subscription id or unique name.')
    profile.set_active_subscription(subscription)
Ejemplo n.º 23
0
    def _authenticate(self):
        try:
            keyvault_client_id = self._auth_params.get('keyvault_client_id')
            keyvault_secret_id = self._auth_params.get('keyvault_secret_id')

            # If user provided KeyVault secret, we will pull auth params information from it
            if keyvault_secret_id:
                self._auth_params.update(
                    json.loads(
                        get_keyvault_secret(keyvault_client_id,
                                            keyvault_secret_id)))

            client_id = self._auth_params.get('client_id')
            client_secret = self._auth_params.get('client_secret')
            access_token = self._auth_params.get('access_token')
            tenant_id = self._auth_params.get('tenant_id')
            use_msi = self._auth_params.get('use_msi')
            subscription_id = self._auth_params.get('subscription_id')

            if access_token and subscription_id:
                log.info("Creating session with Token Authentication")
                self.subscription_id = subscription_id
                self.credentials = BasicTokenAuthentication(
                    token={'access_token': access_token})
                self._is_token_auth = True

            elif client_id and client_secret and tenant_id and subscription_id:
                log.info(
                    "Creating session with Service Principal Authentication")
                self.subscription_id = subscription_id
                self.credentials = ServicePrincipalCredentials(
                    client_id=client_id,
                    secret=client_secret,
                    tenant=tenant_id,
                    resource=self.resource_namespace)
                self.tenant_id = tenant_id

            elif use_msi and subscription_id:
                log.info("Creating session with MSI Authentication")
                self.subscription_id = subscription_id
                if client_id:
                    self.credentials = MSIAuthentication(
                        client_id=client_id, resource=self.resource_namespace)
                else:
                    self.credentials = MSIAuthentication(
                        resource=self.resource_namespace)

            elif self._auth_params.get('enable_cli_auth'):
                log.info("Creating session with Azure CLI Authentication")
                self._is_cli_auth = True
                (self.credentials, self.subscription_id,
                 self.tenant_id) = Profile().get_login_credentials(
                     resource=self.resource_namespace)
            log.info("Session using Subscription ID: %s" %
                     self.subscription_id)

        except AuthenticationError as e:
            log.error('Azure Authentication Failure\n'
                      'Error: {0}'.format(
                          json.dumps(e.inner_exception.error_response,
                                     indent=2)))
            sys.exit(1)
        except HTTPError as e:
            if keyvault_client_id and keyvault_secret_id:
                log.error(
                    'Azure Authentication Failure\n'
                    'Error: Cannot retrieve SP credentials from the Key Vault '
                    '(KV uses MSI to access) with client id: {0}'.format(
                        keyvault_client_id))
            elif use_msi:
                log.error(
                    'Azure Authentication Failure\n'
                    'Error: Could not authenticate using managed service identity {0}'
                    .format(client_id if client_id else '(system identity)'))
            else:
                log.error('Azure Authentication Failure: %s' % e.response)
            sys.exit(1)
        except CLIError as e:
            log.error(
                'Azure Authentication Failure\n'
                'Error: Could not authenticate with Azure CLI credentials: {0}'
                .format(e))
            sys.exit(1)
        except Exception as e:
            log.error('Azure Authentication Failure\n' 'Error: {0}'.format(e))
            sys.exit(1)
Ejemplo n.º 24
0
def account_clear(cmd):
    """Clear all stored subscriptions. To clear individual, use 'logout'"""
    if in_cloud_console():
        logger.warning(_CLOUD_CONSOLE_LOGOUT_WARNING)
    profile = Profile(cli_ctx=cmd.cli_ctx)
    profile.logout_all()
    def aml_env_setup(self, line):
        from azure.cli.core._profile import Profile
        self._redirect_logging('az.azure.cli.core._profile')
        p = argparse.ArgumentParser()
        p.add_argument('-n',
                       '--name',
                       help='base name for your environment',
                       required=True)
        p.add_argument('-k',
                       dest='kubernetes',
                       help='Flag to indicate kubernetes environment',
                       required=False,
                       action='store_true')
        p.add_argument('-l',
                       dest='local_only',
                       help='Flag to exclude ACS deployment',
                       required=False,
                       action='store_true')
        p.add_argument('-a',
                       dest='service_principal_app_id',
                       help='AppID of service principal',
                       required=False)
        p.add_argument('-p',
                       dest='service_principal_password',
                       help='Client Secret of service principal',
                       required=False)
        parsed_args = p.parse_args(line.split())
        # validate that user has selected a subscription
        profile = Profile()
        subs = profile.load_cached_subscriptions()
        if not subs:
            print(
                'Please run %select_sub before attempting to set up environment.'
            )
            return
        from azure.cli.command_modules.ml.env import env_setup
        from azure.cli.command_modules.ml._util import JupyterContext
        c = JupyterContext()
        c.set_input_response('Continue with this subscription (Y/n)? ', 'y')
        print(
            'Setting up AML environment. Feel free to continue exploring the rest '
            'of your notebook until this cell updates, though kernel will be busy...'
        )
        with Capturing() as output:
            env_setup(None, parsed_args.name, parsed_args.kubernetes,
                      parsed_args.local_only,
                      parsed_args.service_principal_app_id,
                      parsed_args.service_principal_password, c)
        acs_regex = r"az ml env setup -s (?P<deployment_id>[^']+)"
        env_regex = r'export (?P<k>[^=]+)=(?P<v>.+)'

        for line in output:
            s = re.search(acs_regex, line)
            if s:
                print(
                    'To check the status of the deployment, run line magic %check_deployment'
                )
            else:
                s = re.search(env_regex, line)
                if s:
                    self.print_and_update_env(s.group('k'), s.group('v'))
                else:
                    print(line)

        print('These values have also been added to the current environment.')
Ejemplo n.º 26
0
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):
    """Log in to access Azure subscriptions"""
    from adal.adal_error import AdalError
    import requests

    # quick argument usage check
    if any([password, service_principal, tenant]) and identity:
        raise CLIError(
            "usage error: '--identity' is not applicable with other arguments")
    if any([password, service_principal, username, identity
            ]) and use_device_code:
        raise CLIError(
            "usage error: '--use-device-code' is not applicable with other arguments"
        )
    if use_cert_sn_issuer and not service_principal:
        raise CLIError(
            "usage error: '--use-sn-issuer' is only applicable with a service principal"
        )
    if service_principal and not username:
        raise CLIError(
            'usage error: --service-principal --username NAME --password SECRET --tenant TENANT'
        )

    interactive = False

    profile = Profile(cli_ctx=cmd.cli_ctx, async_persist=False)

    if identity:
        if in_cloud_console():
            return profile.find_subscriptions_in_cloud_console()
        return profile.find_subscriptions_in_vm_with_msi(
            username, allow_no_subscriptions)
    elif in_cloud_console():  # tell users they might not need login
        logger.warning(_CLOUD_CONSOLE_LOGIN_WARNING)

    if username:
        if not password:
            try:
                password = prompt_pass('Password: '******'Please specify both username and password in non-interactive mode.'
                )
    else:
        interactive = True

    try:
        subscriptions = profile.find_subscriptions_on_login(
            interactive,
            username,
            password,
            service_principal,
            tenant,
            use_device_code=use_device_code,
            allow_no_subscriptions=allow_no_subscriptions,
            use_cert_sn_issuer=use_cert_sn_issuer)
    except AdalError as err:
        # try polish unfriendly server errors
        if username:
            msg = str(err)
            suggestion = "For cross-check, try 'az login' to authenticate through browser."
            if ('ID3242:' in msg) or ('Server returned an unknown AccountType'
                                      in msg):
                raise CLIError("The user name might be invalid. " + suggestion)
            if 'Server returned error in RSTR - ErrorCode' in msg:
                raise CLIError(
                    "Logging in through command line is not supported. " +
                    suggestion)
        raise CLIError(err)
    except requests.exceptions.ConnectionError as err:
        raise CLIError(
            'Please ensure you have network connection. Error detail: ' +
            str(err))
    all_subscriptions = list(subscriptions)
    for sub in all_subscriptions:
        sub['cloudName'] = sub.pop('environmentName', None)
    return all_subscriptions
Ejemplo n.º 27
0
def _get_subscription_id():
    _, sub_id, _ = Profile().get_login_credentials(subscription_id=None)
    return sub_id
Ejemplo n.º 28
0
def create_keyvault(
        client,
        resource_group_name,
        vault_name,
        location=None,  #pylint:disable=too-many-arguments
        sku=SkuName.standard.value,
        enabled_for_deployment=None,
        enabled_for_disk_encryption=None,
        enabled_for_template_deployment=None,
        no_self_perms=None,
        tags=None):
    from azure.mgmt.keyvault.models import VaultCreateOrUpdateParameters
    from azure.cli.core._profile import Profile, CLOUD
    from azure.graphrbac.models import GraphErrorException
    profile = Profile()
    cred, _, tenant_id = profile.get_login_credentials(
        resource=CLOUD.endpoints.active_directory_graph_resource_id)
    graph_client = GraphRbacManagementClient(cred,
                                             tenant_id,
                                             base_url=CLOUD.endpoints.active_directory_graph_resource_id)  # pylint: disable=line-too-long
    subscription = profile.get_subscription()
    if no_self_perms:
        access_policies = []
    else:
        permissions = Permissions(keys=[
            KeyPermissions.get, KeyPermissions.create, KeyPermissions.delete,
            KeyPermissions.list, KeyPermissions.update,
            KeyPermissions.import_enum, KeyPermissions.backup,
            KeyPermissions.restore
        ],
                                  secrets=[SecretPermissions.all],
                                  certificates=[CertificatePermissions.all])
        try:
            object_id = _get_current_user_object_id(graph_client)
        except GraphErrorException:
            object_id = _get_object_id(graph_client, subscription=subscription)
        if not object_id:
            raise CLIError('Cannot create vault.\n'
                           'Unable to query active directory for information '\
                           'about the current user.\n'
                           'You may try the --no-self-perms flag to create a vault'\
                           ' without permissions.')
        access_policies = [
            AccessPolicyEntry(tenant_id=tenant_id,
                              object_id=object_id,
                              permissions=permissions)
        ]
    properties = VaultProperties(
        tenant_id=tenant_id,
        sku=Sku(name=sku),
        access_policies=access_policies,
        vault_uri=None,
        enabled_for_deployment=enabled_for_deployment,
        enabled_for_disk_encryption=enabled_for_disk_encryption,
        enabled_for_template_deployment=enabled_for_template_deployment)
    parameters = VaultCreateOrUpdateParameters(location=location,
                                               tags=tags,
                                               properties=properties)
    return client.create_or_update(resource_group_name=resource_group_name,
                                   vault_name=vault_name,
                                   parameters=parameters)
Ejemplo n.º 29
0
def logout(username=None):
    """Log out to remove access to Azure subscriptions"""
    profile = Profile()
    if not username:
        username = profile.get_current_account_user()
    profile.logout(username)
Ejemplo n.º 30
0
def _get_login_token(login_server, only_refresh_token=True, repository=None):
    """Obtains refresh and access tokens for an AAD-enabled registry.
    :param str login_server: The registry login server URL to log in to
    :param bool only_refresh_token: Whether to ask for only refresh token,
            or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    """
    login_server = login_server.rstrip('/')

    challenge = requests.get('https://' + login_server + '/v2/')
    if challenge.status_code not in [
            401
    ] or 'WWW-Authenticate' not in challenge.headers:
        raise CLIError(
            "Registry '{}' did not issue a challenge.".format(login_server))

    authenticate = challenge.headers['WWW-Authenticate']

    tokens = authenticate.split(' ', 2)
    if len(tokens) < 2 or tokens[0].lower() != 'bearer':
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    params = {
        y[0]: y[1].strip('"')
        for y in (x.strip().split('=', 2) for x in tokens[1].split(','))
    }
    if 'realm' not in params or 'service' not in params:
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    authurl = urlparse(params['realm'])
    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

    from azure.cli.core._profile import Profile
    profile = Profile()
    sp_id, refresh, access, tenant = profile.get_refresh_token()

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    if not sp_id:
        if not refresh:
            content = {
                'grant_type': 'access_token',
                'service': params['service'],
                'tenant': tenant,
                'access_token': access
            }
        else:
            content = {
                'grant_type': 'access_token_refresh_token',
                'service': params['service'],
                'tenant': tenant,
                'access_token': access,
                'refresh_token': refresh
            }
    else:
        content = {
            'grant_type': 'spn',
            'service': params['service'],
            'tenant': tenant,
            'username': sp_id,
            'password': refresh
        }

    response = requests.post(authhost, urlencode(content), headers=headers)

    if response.status_code not in [200]:
        raise CLIError(
            "Access to registry '{}' was denied. Response code: {}.".format(
                login_server, response.status_code))

    refresh_token = loads(response.content.decode("utf-8"))["refresh_token"]
    if only_refresh_token:
        return refresh_token, None

    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/token', '', '', ''))

    if repository is None:
        scope = 'registry:catalog:*'
    else:
        scope = 'repository:' + repository + ':*'

    content = {
        'grant_type': 'refresh_token',
        'service': login_server,
        'scope': scope,
        'refresh_token': refresh_token
    }
    response = requests.post(authhost, urlencode(content), headers=headers)
    access_token = loads(response.content.decode("utf-8"))["access_token"]

    return refresh_token, access_token