Ejemplo n.º 1
0
    def test_get_raw_token(self, mock_get_token, mock_read_cred_file):
        some_token_type = 'Bearer'
        mock_read_cred_file.return_value = [Test_Profile.token_entry1]
        mock_get_token.return_value = (some_token_type, Test_Profile.raw_token1,
                                       Test_Profile.token_entry1)
        # setup
        storage_mock = {'subscriptions': None}
        profile = Profile(storage_mock, use_global_creds_cache=False)
        consolidated = Profile._normalize_properties(self.user1,
                                                     [self.subscription1],
                                                     False)
        profile._set_subscriptions(consolidated)
        # action
        creds, sub, tenant = profile.get_raw_token(resource='https://foo')

        # verify
        self.assertEqual(creds[0], self.token_entry1['tokenType'])
        self.assertEqual(creds[1], self.raw_token1)
        # the last in the tuple is the whole token entry which has several fields
        self.assertEqual(creds[2]['expiresOn'], self.token_entry1['expiresOn'])
        mock_get_token.assert_called_once_with(mock.ANY, self.user1, self.tenant_id,
                                               'https://foo')
        self.assertEqual(mock_get_token.call_count, 1)
        self.assertEqual(sub, '1')
        self.assertEqual(tenant, self.tenant_id)
Ejemplo n.º 2
0
def login_account(cmd, client, resource_group_name, account_name, shared_key_auth=False, show=False):
    account = client.get(resource_group_name=resource_group_name,
                         account_name=account_name)
    cmd.cli_ctx.config.set_value('batch', 'account', account.name)
    cmd.cli_ctx.config.set_value('batch', 'endpoint',
                                 'https://{}/'.format(account.account_endpoint))

    if shared_key_auth:
        keys = client.get_keys(resource_group_name=resource_group_name,
                               account_name=account_name)
        cmd.cli_ctx.config.set_value('batch', 'auth_mode', 'shared_key')
        cmd.cli_ctx.config.set_value('batch', 'access_key', keys.primary)
        if show:
            return {
                'account': account.name,
                'endpoint': 'https://{}/'.format(account.account_endpoint),
                'primaryKey': keys.primary,
                'secondaryKey': keys.secondary
            }
    else:
        cmd.cli_ctx.config.set_value('batch', 'auth_mode', 'aad')
        if show:
            resource = cmd.cli_ctx.cloud.endpoints.batch_resource_id
            profile = Profile(cli_ctx=cmd.cli_ctx)
            creds, subscription, tenant = profile.get_raw_token(resource=resource)
            return {
                'tokenType': creds[0],
                'accessToken': creds[1],
                'expiresOn': creds[2]['expiresOn'],
                'subscription': subscription,
                'tenant': tenant,
                'resource': resource
            }
Ejemplo n.º 3
0
def get_access_token(subscription=None, resource=None):
    '''
    get AAD token to access to a specified resource
    :param resource: Azure resource endpoints. Default to Azure Resource Manager
    Use 'az cloud show' command for other Azure resources
    '''
    resource = (resource or get_active_cloud().endpoints.active_directory_resource_id)
    profile = Profile()
    creds, subscription, tenant = profile.get_raw_token(resource, subscription=subscription)
    return {
        'tokenType': creds[0],
        'accessToken': creds[1],
        'expiresOn': creds[2]['expiresOn'],
        'subscription': subscription,
        'tenant': tenant
    }
Ejemplo n.º 4
0
def _get_aad_token(cmd, resource=None):
    '''
    get AAD token to access to a specified resource
    :param resource: Azure resource endpoints. Default to Azure Resource Manager
    Use 'az cloud show' command for other Azure resources
    '''
    resource = (resource
                or cmd.cli_ctx.cloud.endpoints.active_directory_resource_id)
    profile = Profile(cli_ctx=cmd.cli_ctx)
    creds, subscription, tenant = profile.get_raw_token(subscription=None,
                                                        resource=resource)
    return {
        'tokenType': creds[0],
        'accessToken': creds[1],
        'expiresOn': creds[2].get('expiresOn', 'N/A'),
        'subscription': subscription,
        'tenant': tenant
    }
Ejemplo n.º 5
0
def get_access_token(subscription=None, resource=None):
    '''
    get AAD token to access to a specified resource
    :param resource: Azure resource endpoints. Default to Azure Resource Manager
    Use 'az cloud show' command for other Azure resources
    '''
    resource = (resource
                or get_active_cloud().endpoints.active_directory_resource_id)
    profile = Profile()
    creds, subscription, tenant = profile.get_raw_token(
        resource, subscription=subscription)
    return {
        'tokenType': creds[0],
        'accessToken': creds[1],
        'expiresOn': creds[2]['expiresOn'],
        'subscription': subscription,
        'tenant': tenant
    }
Ejemplo n.º 6
0
def getTemplate(cmd, templateId, solutionStorageConnectionString=None):
    """Gets details about the specified template from the gallery.
    templateId: The unique id of the template.
    """
    profile = Profile(cli_ctx=cmd.cli_ctx)
    auth_token = profile.get_raw_token()
    creds = authentication.BasicTokenAuthentication(
        {'access_token': auth_token[0][1]})
    ciqsapi = ciqs_api.CiqsApi(creds=creds, base_url=api.getEndpoint())
    try:
        logger.info("Sending request.")
        template = ciqsapi.get_api_gallery_by_template_id(
            templateId,
            solution_storage_connection_string=solutionStorageConnectionString)
    except msrest.exceptions.HttpOperationError as e:
        message = e.response.json()
        raise CLIError(message)
    return template
Ejemplo n.º 7
0
def login_account(cmd,
                  client,
                  resource_group_name,
                  account_name,
                  shared_key_auth=False,
                  show=False):
    account = client.get(resource_group_name=resource_group_name,
                         account_name=account_name)
    cmd.cli_ctx.config.set_value('batch', 'account', account.name)
    cmd.cli_ctx.config.set_value(
        'batch', 'endpoint', 'https://{}/'.format(account.account_endpoint))

    if shared_key_auth:
        keys = client.get_keys(resource_group_name=resource_group_name,
                               account_name=account_name)
        cmd.cli_ctx.config.set_value('batch', 'auth_mode', 'shared_key')
        cmd.cli_ctx.config.set_value('batch', 'access_key', keys.primary)
        if show:
            return {
                'account': account.name,
                'endpoint': 'https://{}/'.format(account.account_endpoint),
                'primaryKey': keys.primary,
                'secondaryKey': keys.secondary
            }
    else:
        cmd.cli_ctx.config.set_value('batch', 'auth_mode', 'aad')
        if show:
            if in_cloud_console():
                resource = cmd.cli_ctx.cloud.endpoints.active_directory_resource_id
            else:
                resource = cmd.cli_ctx.cloud.endpoints.batch_resource_id
            profile = Profile(cli_ctx=cmd.cli_ctx)
            creds, subscription, tenant = profile.get_raw_token(
                resource=resource)
            return {
                'account': account.name,
                'endpoint': 'https://{}/'.format(account.account_endpoint),
                'tokenType': creds[0],
                'accessToken': creds[1],
                'expiresOn': creds[2]['expiresOn'],
                'subscription': subscription,
                'tenant': tenant,
                'resource': resource
            }
Ejemplo n.º 8
0
def _send_request(cmd,
                  resource_group_name,
                  grafana_name,
                  http_method,
                  path,
                  body=None,
                  raise_for_error_status=True):
    endpoint = grafana_endpoints.get(grafana_name)
    if not endpoint:
        grafana = show_grafana(cmd, grafana_name, resource_group_name)
        endpoint = grafana.properties.endpoint
        grafana_endpoints[grafana_name] = endpoint

    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cmd.cli_ctx)
    # this might be a cross tenant scenario, so pass subscription to get_raw_token
    subscription = get_subscription_id(cmd.cli_ctx)
    amg_first_party_app = ("7f525cdc-1f08-4afa-af7c-84709d42f5d3" if "-ppe."
                           in cmd.cli_ctx.cloud.endpoints.active_directory else
                           "ce34e7e5-485f-4d76-964f-b3d2b16d1e4f")
    creds, _, _ = profile.get_raw_token(subscription=subscription,
                                        resource=amg_first_party_app)

    headers = {
        "content-type": "application/json",
        "authorization": "Bearer " + creds[1]
    }

    # TODO: handle re-try on 429
    response = requests.request(
        http_method,
        url=endpoint + path,
        headers=headers,
        json=body,
        timeout=60,
        verify=(not should_disable_connection_verify()))
    if response.status_code >= 400:
        if raise_for_error_status:
            logger.warning(str(response.content))
            response.raise_for_status()
    # TODO: log headers, requests and response
    return response
Ejemplo n.º 9
0
def get_azure_cli_auth_token(resource):
    from adal import AuthenticationContext
    import os

    try:
        # this makes it cleaner, but in case azure cli is not present on virtual env,
        # but cli exists on computer, we can try and manually get the token from the cache
        from azure.cli.core._profile import Profile
        from azure.cli.core._session import ACCOUNT
        from azure.cli.core._environment import get_config_dir

        azure_folder = get_config_dir()
        ACCOUNT.load(os.path.join(azure_folder, "azureProfile.json"))
        profile = Profile(storage=ACCOUNT)
        token_data = profile.get_raw_token()[0][2]

        client_id = token_data["_clientId"]
        refresh_token = token_data["refreshToken"]

        logger.info(f"Found existing AZ CLI profile for {token_data[0]['userId']}")

    except ModuleNotFoundError:
        try:
            import os
            import json

            folder = os.getenv("AZURE_CONFIG_DIR", None) or os.path.expanduser(os.path.join("~", ".azure"))
            token_path = os.path.join(folder, "accessTokens.json")
            with open(token_path) as f:
                data = json.load(f)

            client_id = data[0]["_clientId"]
            refresh_token = data[0]["refreshToken"]

            logger.info(f"Found existing AZ CLI profile for {data[0]['userId']}")
        except Exception:
            return None

    return AuthenticationContext(f"https://login.microsoftonline.com/common").acquire_token_with_refresh_token(
        refresh_token, client_id, f"https://{resource}.kusto.windows.net"
    )["accessToken"]
Ejemplo n.º 10
0
def get_access_token(cmd, subscription=None, resource=None, resource_type=None):
    '''
    get AAD token to access to a specified resource
    :param resource: Azure resource endpoints. Default to Azure Resource Manager
    :param resource-type: Name of Azure resource endpoints. Can be used instead of resource.
    Use 'az cloud show' command for other Azure resources
    '''
    if resource is None and resource_type is not None:
        endpoints_attr_name = cloud_resource_type_mappings[resource_type]
        resource = getattr(cmd.cli_ctx.cloud.endpoints, endpoints_attr_name)
    else:
        resource = (resource or cmd.cli_ctx.cloud.endpoints.active_directory_resource_id)
    profile = Profile(cli_ctx=cmd.cli_ctx)
    creds, subscription, tenant = profile.get_raw_token(subscription=subscription, resource=resource)
    return {
        'tokenType': creds[0],
        'accessToken': creds[1],
        'expiresOn': creds[2].get('expiresOn', 'N/A'),
        'subscription': subscription,
        'tenant': tenant
    }
Ejemplo n.º 11
0
def deleteDeployment(cmd, deploymentId, subscription=None):
    """Deletes a deployment.
    deploymentId: The unique id created at the time the deployment was made.
    subscription[optional]: Provides an alternate subscripton 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)
    creds = authentication.BasicTokenAuthentication(
        {'access_token': auth_token[0][1]})
    ciqsapi = ciqs_api.CiqsApi(creds=creds, base_url=api.getEndpoint())
    try:
        logger.info("Sending request.")
        deleteResponse = ciqsapi.delete_api_deployments_by_subscription_id_by_deployment_id(
            subscription, deploymentId)
    except msrest.exceptions.HttpOperationError as e:
        message = e.response.json()
        raise CLIError(message)
    return deleteResponse
Ejemplo n.º 12
0
def get_access_token(cmd,
                     subscription=None,
                     resource=None,
                     resource_type=None,
                     tenant=None):
    """
    get AAD token to access to a specified resource
    :param resource: Azure resource endpoints. Default to Azure Resource Manager
    :param resource-type: Name of Azure resource endpoints. Can be used instead of resource.
    Use 'az cloud show' command for other Azure resources
    """
    if resource is None and resource_type is not None:
        endpoints_attr_name = cloud_resource_type_mappings[resource_type]
        resource = getattr(cmd.cli_ctx.cloud.endpoints, endpoints_attr_name)
    else:
        resource = (resource or
                    cmd.cli_ctx.cloud.endpoints.active_directory_resource_id)
    profile = Profile(cli_ctx=cmd.cli_ctx)
    creds, subscription, tenant = profile.get_raw_token(
        subscription=subscription, resource=resource, tenant=tenant)

    token_entry = creds[2]
    # MSIAuthentication's token entry has `expires_on`, while ADAL's token entry has `expiresOn`
    # Unify to ISO `expiresOn`, like "2020-06-30 06:14:41"
    if 'expires_on' in token_entry:
        from datetime import datetime
        # https://docs.python.org/3.8/library/datetime.html#strftime-and-strptime-format-codes
        token_entry['expiresOn'] = datetime.fromtimestamp(int(token_entry['expires_on']))\
            .strftime("%Y-%m-%d %H:%M:%S.%f")

    result = {
        'tokenType': creds[0],
        'accessToken': creds[1],
        'expiresOn': creds[2].get('expiresOn', 'N/A'),
        'tenant': tenant
    }
    if subscription:
        result['subscription'] = subscription
    return result
    def _get_azure_cli_auth_token() -> dict:
        """
        Try to get the az cli authenticated token
        :return: refresh token
        """
        import os

        try:
            # this makes it cleaner, but in case azure cli is not present on virtual env,
            # but cli exists on computer, we can try and manually get the token from the cache
            from azure.cli.core._profile import Profile
            from azure.cli.core._session import ACCOUNT
            from azure.cli.core._environment import get_config_dir

            azure_folder = get_config_dir()
            ACCOUNT.load(os.path.join(azure_folder, "azureProfile.json"))
            profile = Profile(storage=ACCOUNT)
            token_data = profile.get_raw_token()[0][2]

            return token_data

        except ModuleNotFoundError:
            try:
                import os
                import json

                folder = os.getenv("AZURE_CONFIG_DIR",
                                   None) or os.path.expanduser(
                                       os.path.join("~", ".azure"))
                token_path = os.path.join(folder, "accessTokens.json")
                with open(token_path) as f:
                    data = json.load(f)

                # TODO: not sure I should take the first
                return data[0]
            except Exception as e:
                raise KustoClientError(
                    "Azure cli token was not found. Please run 'az login' to setup account.",
                    e)
Ejemplo n.º 14
0
def listDeployments(cmd, subscription=None):
    """Lists the deployments for the supplied subscription. If no subscription
    is supplied, it will use the default subscription of the current logged in
    user of the Azure CLI.
    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)
    creds = authentication.BasicTokenAuthentication(
        {'access_token': auth_token[0][1]})
    ciqsapi = ciqs_api.CiqsApi(creds=creds, base_url=api.getEndpoint())
    try:
        logger.info("Sending request.")
        deployments = ciqsapi.get_api_deployments_by_subscription_id(
            subscription)
    except msrest.exceptions.HttpOperationError as e:
        message = e.response.json()
        raise CLIError(message)
    return deployments
Ejemplo n.º 15
0
    def _get_auth_token(self):
        profile = Profile(cli_ctx=self.cli_ctx)
        # Generate an Azure token with the VSTS resource app id
        auth_token, _, _ = profile.get_raw_token()
        content = {
            'resourceId': self.remote_host,
            'protocol': 'tcptunnel',
            'workloadHostPort': self.remote_port,
            'aztoken': auth_token[1],
            'token': self.last_token,
        }
        if self.node_id:
            custom_header = {'X-Node-Id': self.node_id}
        else:
            custom_header = {}

        web_address = 'https://{}/api/tokens'.format(self.bastion.dns_name)
        response = requests.post(
            web_address,
            data=content,
            headers=custom_header,
            verify=(not should_disable_connection_verify()))
        response_json = None

        if response.content is not None:
            response_json = json.loads(response.content.decode("utf-8"))

        if response.status_code not in [200]:
            if response_json is not None and response_json[
                    "message"] is not None:
                exp = CloudError(response, error=response_json["message"])
            else:
                exp = CloudError(response)
            raise exp

        self.last_token = response_json["authToken"]
        self.node_id = response_json["nodeId"]
        return self.last_token
Ejemplo n.º 16
0
def create_plan(cmd,
                client,
                resource_group_name,
                plan_name,
                location=None,
                tags=None,
                subnet_id=None,
                default_sku_name=None,
                default_autoshutdown_delay=None):
    import jwt  # pylint: disable=import-error
    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cmd.cli_ctx)
    creds, _, __ = profile.get_raw_token()
    tokenType = creds[0]
    accessToken = creds[1]
    if tokenType != "Bearer":
        logger.debug("Got unexpected token type: %s", tokenType)
        raise CLIError("Unable to create plan. Use --debug for details.")
    decoded_token = jwt.decode(accessToken, verify=False, algorithms=['RS256'])
    tid = decoded_token.get('tid')
    oid = decoded_token.get('oid')
    if not tid or not oid:
        logger.debug(
            "Unable to determine 'tid' and 'oid' from token claims: %s",
            decoded_token)
        raise CLIError("Unable to create plan. Use --debug for details.")
    user_id = f"{tid}_{oid}"
    vnet_props = VnetProperties(subnet_id=subnet_id) if subnet_id else None
    plan_props = VSOnlinePlanProperties(
        user_id=user_id,
        default_auto_suspend_delay_minutes=default_autoshutdown_delay,
        default_environment_sku=default_sku_name,
        vnet_properties=vnet_props)
    vsonline_plan = VSOnlinePlan(location=location,
                                 properties=plan_props,
                                 tags=tags)
    return client.create(resource_group_name, plan_name, vsonline_plan)
Ejemplo n.º 17
0
def get_access_token(cmd, subscription=None, resource=None, scopes=None, resource_type=None, tenant=None):
    """
    get AAD token to access to a specified resource.
    Use 'az cloud show' command for other Azure resources
    """
    if resource is None and resource_type:
        endpoints_attr_name = cloud_resource_type_mappings[resource_type]
        resource = getattr(cmd.cli_ctx.cloud.endpoints, endpoints_attr_name)

    profile = Profile(cli_ctx=cmd.cli_ctx)
    creds, subscription, tenant = profile.get_raw_token(subscription=subscription, resource=resource, scopes=scopes,
                                                        tenant=tenant)

    result = {
        'tokenType': creds[0],
        'accessToken': creds[1],
        # 'expires_on': creds[2].get('expires_on', None),
        'expiresOn': creds[2]['expiresOn'],
        'tenant': tenant
    }
    if subscription:
        result['subscription'] = subscription

    return result
Ejemplo n.º 18
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_rest_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

    endpoints = cli_ctx.cloud.endpoints
    # 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 = endpoints.resource_manager.rstrip('/') + url

    # 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(cli_ctx=cli_ctx)
    if '{subscriptionId}' in url:
        url = url.replace(
            '{subscriptionId}', cli_ctx.data['subscription_id']
            or profile.get_subscription_id())

    # Prepare the Bearer token for `Authorization` header
    if not skip_authorization_header and url.lower().startswith('https://'):
        # Prepare `resource` for `get_raw_token`
        if not resource:
            # If url starts with ARM endpoint, like `https://management.azure.com/`,
            # use `active_directory_resource_id` for resource, like `https://management.core.windows.net/`.
            # 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:
            # Prepare `subscription` for `get_raw_token`
            # If this is an ARM request, try to extract subscription ID from the URL.
            # But there are APIs which don't require subscription ID, like /subscriptions, /tenants
            # TODO: In the future when multi-tenant subscription is supported, we won't be able to uniquely identify
            #   the token from subscription anymore.
            token_subscription = None
            if url.lower().startswith(endpoints.resource_manager.rstrip('/')):
                token_subscription = _extract_subscription_id(url)
            if token_subscription:
                logger.debug(
                    'Retrieving token for resource %s, subscription %s',
                    resource, token_subscription)
                token_info, _, _ = profile.get_raw_token(
                    resource, subscription=token_subscription)
            else:
                logger.debug('Retrieving token for resource %s', resource)
                token_info, _, _ = profile.get_raw_token(resource)
            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"
            )

    # 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)

    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.º 19
0
def _get_aad_token_after_challenge(cli_ctx,
                                   token_params,
                                   login_server,
                                   only_refresh_token,
                                   repository,
                                   artifact_repository,
                                   permission,
                                   is_diagnostics_context):
    authurl = urlparse(token_params['realm'])
    authhost = urlunparse((authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cli_ctx)

    # this might be a cross tenant scenario, so pass subscription to get_raw_token
    subscription = get_subscription_id(cli_ctx)
    creds, _, tenant = profile.get_raw_token(subscription=subscription)

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    content = {
        'grant_type': 'access_token',
        'service': token_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]:
        from ._errors import CONNECTIVITY_REFRESH_TOKEN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_REFRESH_TOKEN_ERROR.format_error_message(login_server, response.status_code)
        raise CLIError(CONNECTIVITY_REFRESH_TOKEN_ERROR.format_error_message(login_server, response.status_code)
                       .get_error_message())

    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:
        scope = 'repository:{}:{}'.format(repository, permission)
    elif artifact_repository:
        scope = 'artifact-repository:{}:{}'.format(artifact_repository, permission)
    else:
        # catalog only has * as permission, even for a read operation
        scope = 'registry:catalog:*'

    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()))

    if response.status_code not in [200]:
        from ._errors import CONNECTIVITY_ACCESS_TOKEN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_ACCESS_TOKEN_ERROR.format_error_message(login_server, response.status_code)
        raise CLIError(CONNECTIVITY_ACCESS_TOKEN_ERROR.format_error_message(login_server, response.status_code)
                       .get_error_message())

    return loads(response.content.decode("utf-8"))["access_token"]
Ejemplo n.º 20
0
def _get_aad_token(cli_ctx,
                   login_server,
                   only_refresh_token,
                   repository=None,
                   artifact_repository=None,
                   permission=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
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    if repository and artifact_repository:
        raise ValueError(
            "Only one of repository and artifact_repository can be provided.")

    if (repository or
            artifact_repository) and permission not in ACCESS_TOKEN_PERMISSION:
        raise ValueError(
            "Permission is required for a repository or artifact_repository. Allowed access token permission: {}"
            .format(ACCESS_TOKEN_PERMISSION))

    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:
        scope = 'repository:{}:{}'.format(repository, permission)
    elif artifact_repository:
        scope = 'artifact-repository:{}:{}'.format(artifact_repository,
                                                   permission)
    else:
        # catalog only has * as permission, even for a read operation
        scope = 'registry:catalog:*'

    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()))

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

    return loads(response.content.decode("utf-8"))["access_token"]
Ejemplo n.º 21
0
def get_access_token():
    from azure.cli.core._profile import Profile
    profile = Profile()
    creds, subscription, _ = profile.get_raw_token()
    return (creds[1], subscription)
Ejemplo n.º 22
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.º 23
0
def _get_aad_token(cli_ctx,
                   login_server,
                   only_refresh_token,
                   repository=None,
                   artifact_repository=None,
                   permission=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
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    if repository and artifact_repository:
        raise ValueError("Only one of repository and artifact_repository can be provided.")

    if (repository or artifact_repository) and permission not in ACCESS_TOKEN_PERMISSION:
        raise ValueError(
            "Permission is required for a repository or artifact_repository. Allowed access token permission: {}"
            .format(ACCESS_TOKEN_PERMISSION))

    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:
        scope = 'repository:{}:{}'.format(repository, permission)
    elif artifact_repository:
        scope = 'artifact-repository:{}:{}'.format(artifact_repository, permission)
    else:
        # catalog only has * as permission, even for a read operation
        scope = 'registry:catalog:*'

    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()))

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

    return loads(response.content.decode("utf-8"))["access_token"]
Ejemplo n.º 24
0
def send_raw_request(
        cli_ctx,
        method,
        uri,
        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
    import requests
    from azure.cli.core.commands.client_factory import UA_AGENT

    result = {}
    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
    headers.update({
        'User-Agent': UA_AGENT,
    })
    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 '://' not in uri:
        uri = cli_ctx.cloud.endpoints.resource_manager + uri.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 uri:
        uri = uri.replace('{subscriptionId}', profile.get_subscription_id())

    if not skip_authorization_header and uri.lower().startswith('https://'):
        if not resource:
            endpoints = cli_ctx.cloud.endpoints
            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 uri.lower().startswith(
                                  value.lower()):
                    resource = value
                    break
        if resource:
            token_info, _, _ = profile.get_raw_token(resource)
            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:
        r = requests.request(method,
                             uri,
                             params=uri_parameters,
                             data=body,
                             headers=headers,
                             verify=not should_disable_connection_verify())
        logger.debug("Response Header : %s", r.headers if r else '')
    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.º 25
0
class MediaV2Client():
    """ Media V2 Client """
    def __init__(self, cli_ctx, resource_group_name, account_name):
        from azure.cli.core._profile import Profile
        self.profile = Profile(cli_ctx=cli_ctx)
        self._old_rp_api_version = '2015-10-01'
        self.v2_media_api_resource = cli_ctx.cloud.endpoints.media_resource_id
        self.api_endpoint = self._get_v2_api_endpoint(cli_ctx, resource_group_name, account_name)
        self.access_token = self._get_v2_access_token()

    def _get_v2_api_endpoint(self, cli_ctx, resource_group_name, account_name):
        from msrestazure.tools import resource_id
        from azure.cli.command_modules.ams._sdk_utils import (get_media_namespace, get_media_type)

        access_token = self.profile.get_raw_token()[0][2].get('accessToken')

        media_old_rp_url = resource_id(subscription=get_subscription_id(cli_ctx),
                                       resource_group=resource_group_name,
                                       namespace=get_media_namespace(), type=get_media_type(),
                                       name=account_name) + '?api-version={}'.format(self._old_rp_api_version)

        media_service_res = requests.get(cli_ctx.cloud.endpoints.resource_manager.rstrip('/') + media_old_rp_url,
                                         headers={'Authorization': 'Bearer {}'.format(access_token)})
        if not media_service_res.ok:
            err_info = 'Request to 2015-10-01 Media API failed.'
            res_text = json.loads(media_service_res.text)
            if res_text is not None and res_text.get('error') is not None:
                err_info = res_text.get('error').get('message')
            raise CLIError(err_info)

        media_service = media_service_res.json()
        api_endpoints = media_service.get('properties').get('apiEndpoints')
        api_endpoint = next((x for x in api_endpoints if x.get('majorVersion') == '2'), api_endpoints[0])
        if not api_endpoint:
            raise CLIError('v2 Media API endpoint was not found.')
        return api_endpoint

    def _get_v2_access_token(self):
        # pylint: disable=protected-access
        access_token = self.profile.get_raw_token(resource=self.v2_media_api_resource)[0][2].get('accessToken')
        return access_token

    def set_mru(self, account_id, count, type):
        headers = {}
        headers['Authorization'] = 'Bearer {}'.format(self.access_token)
        headers['Content-Type'] = 'application/json;odata=verbose'
        headers['Accept'] = 'application/json;odata=verbose'

        url_request_template = "{}EncodingReservedUnitTypes(guid'{}')?api-version=2.19"
        response = requests.put(url_request_template.format(self.api_endpoint.get('endpoint'), account_id),
                                headers=headers,
                                data='{{"ReservedUnitType":{}, "CurrentReservedUnits":{}}}'.format(type, count))

        if not response.ok:
            err_info = 'No error information available'
            if json.loads(response.text) is not None and json.loads(response.text).get('error') is not None:
                err_info = json.loads(response.text).get('error').get('message').get('value')
            raise CLIError('Request to EncodingReservedUnitTypes v2 API endpoint failed. ' + err_info)

    def get_mru(self):
        headers = {}
        headers['Authorization'] = 'Bearer {}'.format(self.access_token)
        headers['Content-Type'] = 'application/json;odata=minimalmetadata'
        headers['Accept'] = 'application/json;odata=minimalmetadata'
        headers['Accept-Charset'] = 'UTF-8'

        url_request_template = '{}EncodingReservedUnitTypes?api-version=2.19'
        response = requests.get(url_request_template.format(self.api_endpoint.get('endpoint')),
                                headers=headers)
        if not response.ok:
            raise CLIError('Request to EncodingReservedUnitTypes v2 API endpoint failed.')
        return response.json().get('value')[0]
Ejemplo n.º 26
0
 def token_provider():
     from azure.cli.core._profile import Profile
     profile = Profile(cli_ctx=target["cmd"].cli_ctx)
     creds, _, _ = profile.get_raw_token(resource=IOTHUB_RESOURCE_ID)
     access_token = AccessToken(f"{creds[0]} {creds[1]}", time() + 3599)
     return access_token