Ejemplo n.º 1
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
Ejemplo n.º 2
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)
    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,
                             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.º 3
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(cli_ctx)

    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)
        from azure.cli.core.commands.client_factory import get_subscription_id

        refresh_token_obj = self.profile.get_refresh_token()
        access_token = refresh_token_obj[2]

        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[:-1] + 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, cli_ctx):
        from adal import AuthenticationContext

        refresh_token_obj = self.profile.get_refresh_token()

        refresh_token = refresh_token_obj[1]
        tenant = refresh_token_obj[3]
        # pylint: disable=protected-access
        client_id = self.profile.get_login_credentials()[0]._token_retriever()[2]['_clientId']

        authority = '{}/{}'.format(cli_ctx.cloud.endpoints.active_directory, tenant)
        context = AuthenticationContext(authority)
        return context.acquire_token_with_refresh_token(refresh_token,
                                                        client_id,
                                                        self.v2_media_api_resource).get('accessToken')

    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]