示例#1
0
    def _build_realm_token_url(self, response, repository, actions) -> str:
        www_authenticate_response = www_authenticate.parse(
            response.headers["WWW-Authenticate"]
        )

        if "bearer" in www_authenticate_response:
            if self.actions:
                scope = f"repository:{repository}:" + ",".join(actions)
            elif "scope" in www_authenticate_response["bearer"]:
                scope = www_authenticate_response["bearer"]["scope"]
            else:
                scope = ""

            url_parts = list(
                parse.urlparse(www_authenticate_response["bearer"]["realm"])
            )
            query = parse.parse_qs(url_parts[4])
            query.update(
                {
                    "service": www_authenticate_response["bearer"]["service"],
                    "scope": scope,
                }
            )
            url_parts[4] = parse.urlencode(query, True)
            url_parts[0] = "https"

            return parse.urlunparse(url_parts)
示例#2
0
    def _get_auth_token(self, credentials: str, endpoint: str,
                        scope: str) -> str:
        """
        Retrieves the registry auth token for a given scope.

        Args:
            credentials: The credentials to use to retrieve the auth token.
            endpoint: Registry endpoint for which to retrieve the token.
            scope: The scope of the auth token.

        Returns:
            The corresponding auth token, or None.
        """

        # https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md
        if not self.token:
            # Test using HTTP basic authentication to retrieve the www-authenticate response header ...
            headers = {"Authorization": "Basic {0}".format(credentials)}
            url = "https://{0}/v2/".format(endpoint)
            response = requests.get(url, headers=headers)

            auth_params = www_authenticate.parse(
                response.headers["Www-Authenticate"])
            bearer = auth_params["bearer"]

            url = RegistryV2ImageSource.DOCKERHUB_AUTH_URL_PATTERN.format(
                bearer["realm"], bearer["service"], scope)
            response = requests.get(url, headers=headers)
            # LOGGER.debug("Token Response: %s", response.content)
            must_be_equal(200, response.status_code,
                          "Failed to retrieve bearer token")

            self.token = response.json()["token"]

        return self.token
示例#3
0
 def _request(self, method, url, *, headers=None, **kwargs):
     headers = headers or {}
     response = yield from super()._request(method,
                                            url,
                                            headers=headers,
                                            **kwargs)
     challenges = self.get_challenges(response)
     if response.status == UNAUTHORIZED and 'negotiate' in challenges:
         host = self.get_hostname(response)
         ctx = self.get_context(host)
         out_token = self.negotiate_step(ctx)
         while True:
             response.close()
             if out_token:
                 headers['Authorization'] = 'Negotiate ' + out_token
                 response = yield from super()._request(method,
                                                        url,
                                                        headers=headers,
                                                        **kwargs)
             challenges = www_authenticate.parse(
                 response.headers.get('WWW-Authenticate'))
             in_token = challenges['negotiate']
             self.negotiate_step(ctx, in_token)
             if ctx.complete:
                 break
     return response
示例#4
0
    def _get_token_auth(self, res, repository):
        parsed = www_authenticate.parse(res.headers['www-authenticate'])
        if 'bearer' not in parsed:
            return

        challenge = parsed['bearer']
        realm = challenge.get('realm')
        service = challenge.get('service')
        scope = challenge.get('scope')
        if scope is None and repository:
            scope = f'repository:{repository}:pull'

        logger.info("Getting token auth, realm=%s, service=%s, scope=%s",
                    realm, service, scope)

        if not realm:
            return False

        self.auth = self.orig_auth

        params = []
        if service:
            params.append(('service', service))
        if scope:
            params.append(('scope', scope))

        url = realm + '?' + urlencode(params)
        res = self.session.get(url, **self._kwargs(dict()))
        if res.status_code != 200:
            return False

        token = res.json()['token']
        self.auth = BearerAuth(token)

        return True
示例#5
0
 def get_challenges(self, response):
     challenges = {}
     for k, v in response.headers.items():
         if k.lower() == 'www-authenticate':
             challenges.update(www_authenticate.parse(v))
     logger.debug('Server challenges: {}'.format(challenges))
     return challenges
示例#6
0
    def authenticate(self,
                     username=None, password=None,
                     actions=None, response=None):
        """
        Authenticate to the registry, using a username and password if supplied,
        otherwise as the anonymous user.

        :param username: User name to authenticate as.
        :type username: str

        :param password: User's password.
        :type password: str

        :param actions: If you know which types of operation you need to make on the registry, specify them here. Valid actions are ``pull``, ``push`` and ``*``.
        :type actions: list

        :param response: When the ``auth`` function you passed to :class:`DXFBase`'s constructor is called, it is passed a HTTP response object. Pass it back to :meth:`authenticate` to have it automatically detect which actions are required.
        :type response: requests.Response

        :rtype: str
        :returns: Authentication token, if the registry supports bearer tokens. Otherwise ``None``, and HTTP Basic auth is used.
        """
        if self._insecure:
            raise exceptions.DXFAuthInsecureError()
        if response is None:
            response = self._sessions[0].get(self._base_url)
        # pylint: disable=no-member
        if response.status_code != requests.codes.unauthorized:
            raise exceptions.DXFUnexpectedStatusCodeError(response.status_code,
                                                          requests.codes.unauthorized)
        parsed = www_authenticate.parse(response.headers['www-authenticate'])
        if username is not None and password is not None:
            headers = {
                'Authorization': 'Basic ' + base64.b64encode(_to_bytes_2and3(username + ':' + password)).decode('utf-8')
            }
        else:
            headers = {}
        if 'bearer' in parsed:
            info = parsed['bearer']
            if actions and self._repo:
                scope = 'repository:' + self._repo + ':' + ','.join(actions)
            else:
                scope = info['scope']
            url_parts = list(urlparse.urlparse(info['realm']))
            query = urlparse.parse_qs(url_parts[4])
            query.update({
                'service': info['service'],
                'scope': scope
            })
            url_parts[4] = urlencode(query, True)
            url_parts[0] = 'https'
            if self._auth_host:
                url_parts[1] = self._auth_host
            auth_url = urlparse.urlunparse(url_parts)
            r = self._sessions[0].get(auth_url, headers=headers)
            _raise_for_status(r)
            self.token = r.json()['token']
            return self._token
        else:
            self._headers = headers
 def get_challenges(self, response):
     challenges = {}
     for k, v in response.headers.items():
          if k.lower() == 'www-authenticate':
              challenges.update(www_authenticate.parse(v))
     logger.debug('Server challenges: {}'.format(challenges))
     return challenges
示例#8
0
    def bearer_request(self, method, url, auth, **kwargs):
        log.debug("bearer_request()")
        log.debug('[registry][request]: {0} {1}'.format(method, url))
        if 'Authorization' in kwargs['headers']:
            log.debug('[registry][request]: Authorization header:')

            token_parsed = kwargs['headers']['Authorization'].split('.')
            log.debug(
                pprint.pformat(json.loads(decode_base64(token_parsed[0]))))
            log.debug(
                pprint.pformat(json.loads(decode_base64(token_parsed[1]))))

        res = requests.request(method, url, **kwargs)
        if str(res.status_code)[0] == '2':
            log.debug("[registry] accepted")
            return res, kwargs['headers']['Authorization']

        if res.status_code == 401:
            log.debug("[registry] Access denied. Refreshing token...")
            oauth = www_authenticate.parse(res.headers['Www-Authenticate'])

            log.debug('[auth][answer] Auth header:')
            log.debug(pprint.pformat(oauth['bearer']))

            log.info('retreiving bearer token for {0}'.format(
                oauth['bearer']['scope']))
            # request_url = '{0}?service={1}&scope={2}'.format(oauth['bearer']['realm'],
            #     oauth['bearer']['service'],
            #     oauth['bearer']['scope'])
            request_url = '{0}?service={1}&scope={2}'.format(
                oauth['bearer']['realm'], oauth['bearer']['service'],
                oauth['bearer']['scope'])

            log.debug('[debug][auth][request] Refreshing auth token: POST {0}'.
                      format(request_url))

            try_oauth = requests.post(request_url, auth=auth, **kwargs)

            try:
                token = json.loads(try_oauth._content)['token']
                log.info(">>> token: {}".format(token))
            except SyntaxError:
                log.error("\n\ncouldn't accure token: {0}".format(
                    try_oauth._content))
                sys.exit(1)

            token_parsed = token.split('.')
            log.debug('[auth] token issued: ')
            log.debug(
                pprint.pformat(json.loads(decode_base64(token_parsed[0]))))
            log.debug(
                pprint.pformat(json.loads(decode_base64(token_parsed[1]))))

            kwargs['headers']['Authorization'] = 'Bearer {0}'.format(token)
        else:
            return res, kwargs['headers']['Authorization']

        res = requests.request(method, url, **kwargs)
        return res, kwargs['headers']['Authorization']
示例#9
0
    def bearer_request(self, method, url, auth, **kwargs):
        global DEBUG
        if DEBUG: print("[debug][funcname]: bearer_request()")

        if DEBUG:
            print('[debug][registry][request]: {0} {1}'.format(method, url))
            if 'Authorization' in kwargs['headers']:
                print('[debug][registry][request]: Authorization header:')

                token_parsed = kwargs['headers']['Authorization'].split('.')
                pprint.pprint(ast.literal_eval(decode_base64(token_parsed[0])))
                pprint.pprint(ast.literal_eval(decode_base64(token_parsed[1])))

        res = requests.request(method, url, **kwargs)
        if str(res.status_code)[0] == '2':
            if DEBUG: print("[debug][registry] accepted")
            return (res, kwargs['headers']['Authorization'])

        if res.status_code == 401:
            if DEBUG:
                print("[debug][registry] Access denied. Refreshing token...")
            oauth = www_authenticate.parse(res.headers['Www-Authenticate'])

            if DEBUG:
                print('[debug][auth][answer] Auth header:')
                pprint.pprint(oauth['bearer'])

            # print('[info] retreiving bearer token for {0}'.format(oauth['bearer']['scope']))
            request_url = '{0}?service={1}&scope={2}'.format(
                oauth['bearer']['realm'], oauth['bearer']['service'],
                oauth['bearer']['scope'])

            if DEBUG:
                print('[debug][auth][request] Refreshing auth token: POST {0}'.
                      format(request_url))

            try_oauth = requests.post(request_url, auth=auth, **kwargs)

            try:
                token = ast.literal_eval(try_oauth._content)['token']
            except SyntaxError:
                print('\n\n[ERROR] couldnt accure token: {0}'.format(
                    try_oauth._content))
                sys.exit(1)

            if DEBUG:
                print('[debug][auth] token issued: ')
                token_parsed = token.split('.')
                pprint.pprint(ast.literal_eval(decode_base64(token_parsed[0])))
                pprint.pprint(ast.literal_eval(decode_base64(token_parsed[1])))

            kwargs['headers']['Authorization'] = 'Bearer {0}'.format(token)
        else:
            return (res, kwargs['headers']['Authorization'])

        res = requests.request(method, url, **kwargs)
        return (res, kwargs['headers']['Authorization'])
示例#10
0
 def get_auth_header(url, method):
     r = getattr(requests, method)(url)
     if r.status_code == 401:
         try:
             r.headers['Www-Authenticate']
         except KeyError:
             raise 'could not fetch bearer info from registry endpoint'
         else:
             return www_authenticate.parse(r.headers['Www-Authenticate'])
     else:
         raise 'invalid auth_header response code' + str(r.status_code)
示例#11
0
    def bearer_request(self, method, url, auth, **kwargs):
        log.debug("bearer_request()")
        log.debug('[registry][request]: {0} {1}'.format(method, url))
        if 'Authorization' in kwargs['headers']:
            log.debug('[registry][request]: Authorization header:')

            token_parsed = kwargs['headers']['Authorization'].split('.')
            log.debug(pprint.pformat(json.loads(decode_base64(token_parsed[0]))))
            log.debug(pprint.pformat(json.loads(decode_base64(token_parsed[1]))))

        res = requests.request(method, url, **kwargs)
        if str(res.status_code)[0] == '2':
            log.debug("[registry] accepted")
            return res, kwargs['headers']['Authorization']

        if res.status_code == 401:
            log.debug("[registry] Access denied. Refreshing token...")
            oauth = www_authenticate.parse(res.headers['Www-Authenticate'])

            log.debug('[auth][answer] Auth header:')
            log.debug(pprint.pformat(oauth['bearer']))

            log.info('retreiving bearer token for {0}'.format(oauth['bearer']['scope']))
            # request_url = '{0}?service={1}&scope={2}'.format(oauth['bearer']['realm'],
            #     oauth['bearer']['service'],
            #     oauth['bearer']['scope'])
            request_url = '{0}?service={1}&scope={2}'.format(oauth['bearer']['realm'],
                                                             oauth['bearer']['service'],
                                                             oauth['bearer']['scope'])

            log.debug('[debug][auth][request] Refreshing auth token: POST {0}'.format(request_url))

            try_oauth = requests.post(request_url, auth=auth, **kwargs)

            try:
                token = json.loads(try_oauth._content)['token']
                log.info(">>> token: {}".format(token))
            except SyntaxError:
                log.error("\n\ncouldn't accure token: {0}".format(try_oauth._content))
                sys.exit(1)

            token_parsed = token.split('.')
            log.debug('[auth] token issued: ')
            log.debug(pprint.pformat(json.loads(decode_base64(token_parsed[0]))))
            log.debug(pprint.pformat(json.loads(decode_base64(token_parsed[1]))))

            kwargs['headers']['Authorization'] = 'Bearer {0}'.format(token)
        else:
            return res, kwargs['headers']['Authorization']

        res = requests.request(method, url, **kwargs)
        return res, kwargs['headers']['Authorization']
示例#12
0
    def authenticate(
        self,
        provider: str,
        creds: Optional[BasicAuthCreds] = None,
        cookies: Optional[Cookies] = None,
    ) -> None:
        """Authenticate against the specified provider.

        :param provider: Authorize against this provider.
        :param creds: The creds to use. If unspecified, assumes that creds are set in the netrc file.
        :param cookies: Store the auth cookies in this instance. If unspecified, uses the global instance.
        :raises pants.auth.basic_auth.BasicAuthException: If auth fails due to misconfiguration or
          rejection by the server.
        """
        cookies = cookies or Cookies.global_instance()

        if not provider:
            raise BasicAuthException("No basic auth provider specified.")

        provider_config = self.options.providers.get(provider)
        if not provider_config:
            raise BasicAuthException(
                f"No config found for provider {provider}.")

        url = provider_config.get("url")
        if not url:
            raise BasicAuthException(
                f"No url found in config for provider {provider}.")
        if not self.options.allow_insecure_urls and not url.startswith(
                "https://"):
            raise BasicAuthException(
                f"Auth url for provider {provider} is not secure: {url}.")

        auth = requests.auth.HTTPBasicAuth(creds.username,
                                           creds.password) if creds else None
        response = requests.get(url,
                                auth=auth,
                                headers={"User-Agent": f"pants/v{VERSION}"})

        if response.status_code != requests.codes.ok:
            if response.status_code == requests.codes.unauthorized:
                parsed = www_authenticate.parse(
                    response.headers.get("WWW-Authenticate", ""))
                if "Basic" in parsed:
                    raise Challenged(url, response.status_code,
                                     response.reason, parsed["Basic"]["realm"])
            raise BasicAuthException(url, response.status_code,
                                     response.reason)

        cookies.update(response.cookies)
示例#13
0
 def _execute_get_request(url, headers):
     response = requests.get(url, headers=headers)
     if response.status_code == requests.codes.unauthorized:
         # Get authentication details from headers
         # Registry should tell how to authenticate
         www_authenticate_details = response.headers['Www-Authenticate']
         log.debug(f'unauthorized: retrieving authentication details '
                   f'from response headers {www_authenticate_details}')
         bearer = www_authenticate.parse(www_authenticate_details)['bearer']
         token = AuthenticationService.get_token(**bearer)
         headers['Authorization'] = f'Bearer {token}'
         # Repeat request
         response = requests.get(url, headers=headers)
     return response
示例#14
0
    def authenticate(self, provider, creds=None, cookies=None):
        """Authenticate against the specified provider.

    :param str provider: Authorize against this provider.
    :param pants.auth.basic_auth.BasicAuthCreds creds: The creds to use.
      If unspecified, assumes that creds are set in the netrc file.
    :param pants.auth.cookies.Cookies cookies: Store the auth cookies in this instance.
      If unspecified, uses the global instance.
    :raises pants.auth.basic_auth.BasicAuthException: If auth fails due to misconfiguration or
      rejection by the server.
    """
        cookies = cookies or Cookies.global_instance()

        if not provider:
            raise BasicAuthException('No basic auth provider specified.')

        provider_config = self.get_options().providers.get(provider)
        if not provider_config:
            raise BasicAuthException(
                'No config found for provider {}.'.format(provider))

        url = provider_config.get('url')
        if not url:
            raise BasicAuthException(
                'No url found in config for provider {}.'.format(provider))
        if not self.get_options().allow_insecure_urls and not url.startswith(
                'https://'):
            raise BasicAuthException(
                'Auth url for provider {} is not secure: {}.'.format(
                    provider, url))

        if creds:
            auth = requests.auth.HTTPBasicAuth(creds.username, creds.password)
        else:
            auth = None  # requests will use the netrc creds.
        response = requests.get(url, auth=auth)

        if response.status_code != requests.codes.ok:
            if response.status_code == requests.codes.unauthorized:
                parsed = www_authenticate.parse(
                    response.headers.get('WWW-Authenticate', ''))
                if 'Basic' in parsed:
                    raise Challenged(url, response.status_code,
                                     response.reason, parsed['Basic']['realm'])
            raise BasicAuthException(url, response.status_code,
                                     response.reason)

        cookies.update(response.cookies)
示例#15
0
def get_auth_schemes(r, path):
    """
    Returns list of auth schemes(lowcased) if www-authenticate: header exists
         returns None if no header found
         - www-authenticate: basic
         - www-authenticate: bearer
    """

    try_oauth = requests.head('{0}{1}'.format(r.hostname, path), verify=not r.no_validate_ssl)

    if 'Www-Authenticate' in try_oauth.headers:
        oauth = www_authenticate.parse(try_oauth.headers['Www-Authenticate'])
        log.debug('[docker] Auth schemes found:{0}'.format([m for m in oauth]))
        return [m.lower() for m in oauth]
    else:
        log.debug('[docker] No Auth schemes found')
        return []
示例#16
0
 def testValid(self):
     for r in range(1, len(challenges) + 1):
         for permutation in itertools.permutations(challenges, r):
             # Skip those that have the same authentication scheme more than once.
             if len(set(challenge[1][0] for challenge in permutation)) != len(permutation):
                 continue
             # Skip any permutation that contains a Negotiate challenge
             # with a token, if it's not the only challenge.
             if len(permutation) > 1 and \
                any(challenge[1][0] == 'negotiate' and challenge[1][1] != None
                    for challenge in permutation):
                 continue
             full_challenge = ', '.join(challenge[0] for challenge in permutation)
             print(full_challenge)
             parsed = www_authenticate.parse(full_challenge)
             for left, right in zip(permutation, parsed):
                 self.assertEqual(left[1][0], right)
                 self.assertEqual(left[1][1], parsed[right])
 def _request(self, method, url, *, headers=None, **kwargs):
     headers = headers or {}
     response = yield from super()._request(method, url, headers=headers, **kwargs)
     challenges = self.get_challenges(response)
     if response.status == UNAUTHORIZED and 'negotiate' in challenges:
         host = self.get_hostname(response)
         ctx = self.get_context(host)
         out_token = self.negotiate_step(ctx)
         while True:
             response.close()
             if out_token:
                 headers['Authorization'] = 'Negotiate ' + out_token
                 response = yield from super()._request(method, url, headers=headers, **kwargs)
             challenges = www_authenticate.parse(response.headers.get('WWW-Authenticate'))
             in_token = challenges['negotiate']
             self.negotiate_step(ctx, in_token)
             if ctx.complete:
                 break
     return response
def get_auth_headers(docker_registry_secure: DockerRegistrySecure,
                     image_name: ImageName) -> Union[Dict[str, str], None]:
    # pylint: disable=protected-access
    """
    Retrieves the authentication headers for a given image.
    Args:
        docker_registry_secure: The secure docker registry from which to retrieve the authentication headers.
        image_name: The name of the image for which to retrieve the headers.

    Returns: The authentication headers, or None.
    """
    # Try to retrieve credentials first ...
    auth_header_src = None
    for endpoint in docker_registry_secure.docker_client.api._auth_configs.auths:
        if image_name.endpoint in endpoint:
            credentials = docker_registry_secure.docker_client.api._auth_configs.auths[
                endpoint]
            auth = b64encode(
                f"{credentials['username']}:{credentials['password']}".encode(
                    "utf-8")).decode("utf-8")
            auth_header_src = {"Authorization": f"Basic {auth}"}

    if not auth_header_src:
        return None

    # Try to retrieve an authentication token ...
    https_connection = HTTPSConnection(host=image_name.endpoint)
    https_connection.request("GET", url="/v2/", headers=auth_header_src)
    auth_params = www_authenticate.parse(
        https_connection.getresponse().headers["Www-Authenticate"])
    bearer = auth_params["bearer"]

    https_connection = HTTPSConnection(host=image_name.endpoint)
    https_connection.request(
        "GET",
        url=
        f"{bearer['realm']}?service={bearer['service']}&scope=repository:{image_name.image}:pull&"
        f"client_id=pytest-docker-registry-fixtures",
        headers=auth_header_src,
    )
    payload = loads(https_connection.getresponse().read())
    assert payload["token"]
    return {"Authorization": f"Bearer {payload['token']}"}
    def _call_docker_registry_api_auth(self, authenticate_header: str) -> str:
        parsed_hearder = www_authenticate.parse(authenticate_header)
        realm = parsed_hearder['bearer']['realm']
        auth_params = []

        for key in parsed_hearder['bearer']:
            if key != 'realm':
                auth_params.append('%s=%s' %
                                   (key, parsed_hearder['bearer'][key]))
        auth_url = '%s?%s' % (realm, '&'.join(auth_params))
        headers = {'Content-Type': 'application/json'}
        response = requests.get(auth_url, headers=headers)

        if response.status_code == 200:
            content = json.loads(response.content.decode('utf-8'))
            return content['token']
        else:
            raise WatchError("Authentication failed, response code %d" %
                             response.status_code)
示例#20
0
def get_auth_schemes(r, path):
    """ Returns list of auth schemes(lowcased) if www-authenticate: header exists
         returns None if no header found
         - www-authenticate: basic
         - www-authenticate: bearer
    """

    if DEBUG: print("[debug][funcname]: get_auth_schemes()")

    try_oauth = requests.head('{0}{1}'.format(r.hostname, path))

    if 'Www-Authenticate' in try_oauth.headers:
        oauth = www_authenticate.parse(try_oauth.headers['Www-Authenticate'])
        if DEBUG:
            print('[debug][docker] Auth schemes found:{0}'.format([m for m in oauth]))
        return [m.lower() for m in oauth]
    else:
        if DEBUG:
            print('[debug][docker] No Auth schemes found')
        return []
示例#21
0
文件: __init__.py 项目: treescale/dxf
    def authenticate(self,
                     username=None,
                     password=None,
                     actions=None,
                     response=None,
                     authorization=None,
                     user_agent='Docker-Client/19.03.2 (linux)'):
        # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
        """
        Authenticate to the registry using a username and password,
        an authorization header or otherwise as the anonymous user.

        :param username: User name to authenticate as.
        :type username: str

        :param password: User's password.
        :type password: str

        :param actions: If you know which types of operation you need to make on the registry, specify them here. Valid actions are ``pull``, ``push`` and ``*``.
        :type actions: list

        :param response: When the ``auth`` function you passed to :class:`DXFBase`'s constructor is called, it is passed a HTTP response object. Pass it back to :meth:`authenticate` to have it automatically detect which actions are required.
        :type response: requests.Response

        :param authorization: ``Authorization`` header value.
        :type authorization: str

        :param user_agent: ``User-Agent`` header value.
        :type user_agent: str

        :rtype: str
        :returns: Authentication token, if the registry supports bearer tokens. Otherwise ``None``, and HTTP Basic auth is used (if the registry requires authentication).
        """
        if response is None:
            with warnings.catch_warnings():
                _ignore_warnings(self)
                response = self._sessions[0].get(self._base_url,
                                                 verify=self._tlsverify)

        if response.ok:
            return None

        # pylint: disable=no-member
        if response.status_code != requests.codes.unauthorized:
            raise exceptions.DXFUnexpectedStatusCodeError(
                response.status_code, requests.codes.unauthorized)

        parsed = www_authenticate.parse(response.headers['www-authenticate'])

        if username is not None and password is not None:
            headers = {
                'Authorization':
                'Basic ' + base64.b64encode(
                    _to_bytes_2and3(username + ':' + password)).decode('utf-8')
            }
        elif authorization is not None:
            headers = {'Authorization': authorization}
        else:
            headers = {}
        headers["User-Agent"] = user_agent

        if 'bearer' in parsed:
            info = parsed['bearer']
            if actions and self._repo:
                scope = 'repository:' + self._repo + ':' + ','.join(actions)
            elif 'scope' in info:
                scope = info['scope']
            elif not self._repo:
                # Issue #28: gcr.io doesn't return scope for non-repo requests
                scope = 'registry:catalog:*'
            else:
                scope = ''
            url_parts = list(urlparse.urlparse(info['realm']))
            query = urlparse.parse_qs(url_parts[4])
            query.update({'service': info['service'], 'scope': scope})
            url_parts[4] = urlencode(query, True)
            if self._insecure:
                url_parts[0] = 'http'
            else:
                url_parts[0] = 'https'
            if self._auth_host:
                url_parts[1] = self._auth_host
            auth_url = urlparse.urlunparse(url_parts)
            with warnings.catch_warnings():
                _ignore_warnings(self)
                r = self._sessions[0].get(auth_url,
                                          headers=headers,
                                          verify=self._tlsverify)
            _raise_for_status(r)
            rjson = r.json()
            # Use 'access_token' value if present and not empty, else 'token' value.
            self.token = rjson.get('access_token') or rjson['token']
            return self._token

        self._headers = headers
        return None
示例#22
0
    def _authenticate(
        self,
        image_reference: str,
        scope: str,
    ):
        if self.token_cache.token(scope=scope):
            return  # no re-auth required, yet

        if 'push' in scope:
            privileges = oa.Privileges.READWRITE
        elif 'pull' in scope:
            privileges = oa.Privileges.READONLY
        else:
            privileges = None

        oci_creds = self.credentials_lookup(
            image_reference=image_reference,
            privileges=privileges,
            absent_ok=True,
        )

        if not oci_creds:
            logger.info(
                f'no credentials for {image_reference=} - attempting anonymous-auth'
            )

        url = base_api_url(image_reference=image_reference)
        res = self.session.get(url)

        auth_challenge = www_authenticate.parse(
            res.headers['www-authenticate'])
        bearer = auth_challenge['bearer']
        service = bearer['service']

        realm = bearer['realm'] + '?' + urllib.parse.urlencode(
            {
                'scope': scope,
                'service': service,
            })

        if oci_creds:
            auth = requests.auth.HTTPBasicAuth(
                username=oci_creds.username,
                password=oci_creds.password,
            )
        else:
            auth = None

        res = self.session.get(
            realm,
            auth=auth,
        )

        res.raise_for_status()

        token_dict = res.json()
        token_dict['scope'] = scope

        token = dacite.from_dict(
            data=token_dict,
            data_class=OauthToken,
        )

        self.token_cache.set_token(token)
示例#23
0
 def get_challenges(self, response):
     challenges = {}
     for k, v in response.headers.items():
          if k.lower() == 'www-authenticate':
              challenges.update(www_authenticate.parse(v))
     return challenges
示例#24
0
    if data:
        if isinstance(data, dict):
            data = urlencode(data)
    request = urllib2.Request(url, data=data, headers=headers)
    try:
        return urllib2.urlopen(request)
    except urllib2.HTTPError as e:
        return e


response = open_url(uri, headers=dict(authorization='bearer bad-token'))
if response.getcode() != 401:
    print "oops, expected 401"
    raise SystemExit(-1)

www_auth = www_authenticate.parse(
    response.headers['WWW-Authenticate'])['Bearer']
if not all([x in www_auth for x in ['nonce', 'scope', 'token_pop_endpoint']]) or \
  not all([x in www_auth['scope'].split() for x in ['openid', 'webid']]):
    print "oops, WWW-Authenticate isn't for webid-auth-protocol", response.headers[
        'WWW-Authenticate']
    raise SystemExit(-1)

jwk = make_jwk()

id_token = make_id_token(args.webid,
                         "cli-tool",
                         nonce=str(uuid.uuid4()),
                         lifetime=args.id_token_lifetime,
                         redirect_uri=args.app_id,
                         cnf=dict(jwk=jwk),
                         sub_jwk=jwk if is_self_issued else None)
示例#25
0
文件: __init__.py 项目: bjorand/dxf
    def authenticate(self,
                     username=None,
                     password=None,
                     actions=None,
                     response=None):
        """
        Authenticate to the registry, using a username and password if supplied,
        otherwise as the anonymous user.

        :param username: User name to authenticate as.
        :type username: str

        :param password: User's password.
        :type password: str

        :param actions: If you know which types of operation you need to make on the registry, specify them here. Valid actions are ``pull``, ``push`` and ``*``.
        :type actions: list

        :param response: When the ``auth`` function you passed to :class:`DXFBase`'s constructor is called, it is passed a HTTP response object. Pass it back to :meth:`authenticate` to have it automatically detect which actions are required.
        :type response: requests.Response

        :rtype: str
        :returns: Authentication token, if the registry supports bearer tokens. Otherwise ``None``, and HTTP Basic auth is used.
        """
        if self._insecure:
            raise exceptions.DXFAuthInsecureError()
        if response is None:
            response = self._sessions[0].get(self._base_url)
        # pylint: disable=no-member
        if response.status_code != requests.codes.unauthorized:
            raise exceptions.DXFUnexpectedStatusCodeError(
                response.status_code, requests.codes.unauthorized)
        parsed = www_authenticate.parse(response.headers['www-authenticate'])
        if username is not None and password is not None:
            headers = {
                'Authorization':
                'Basic ' + base64.b64encode(
                    _to_bytes_2and3(username + ':' + password)).decode('utf-8')
            }
        else:
            headers = {}
        if 'bearer' in parsed:
            info = parsed['bearer']
            if actions and self._repo:
                scope = 'repository:' + self._repo + ':' + ','.join(actions)
            else:
                scope = info['scope']
            url_parts = list(urlparse.urlparse(info['realm']))
            query = urlparse.parse_qs(url_parts[4])
            query.update({'service': info['service'], 'scope': scope})
            url_parts[4] = urlencode(query, True)
            url_parts[0] = 'https'
            if self._auth_host:
                url_parts[1] = self._auth_host
            auth_url = urlparse.urlunparse(url_parts)
            r = self._sessions[0].get(auth_url, headers=headers)
            _raise_for_status(r)
            self.token = r.json()['token']
            return self._token
        else:
            self._headers = headers
示例#26
0
    def _authenticate(
        self,
        image_reference: typing.Union[str, om.OciImageReference],
        scope: str,
    ):
        if isinstance(image_reference, om.OciImageReference):
            image_reference = str(image_reference)

        cached_auth_method = self.token_cache.auth_method(image_reference=image_reference)
        if cached_auth_method is AuthMethod.BASIC:
            return # basic-auth does not require any additional preliminary steps
        if cached_auth_method is AuthMethod.BEARER and self.token_cache.token(scope=scope):
            return # no re-auth required, yet

        if 'push' in scope:
            privileges = oa.Privileges.READWRITE
        elif 'pull' in scope:
            privileges = oa.Privileges.READONLY
        else:
            privileges = None

        oci_creds = self.credentials_lookup(
            image_reference=image_reference,
            privileges=privileges,
            absent_ok=True,
        )

        if not oci_creds:
            logger.warning(f'no credentials for {image_reference=} - attempting anonymous-auth')

        url = base_api_url(
            image_reference=str(image_reference),
        )
        res = self.session.get(
            url=url,
            verify=not self.disable_tls_validation,
        )

        auth_challenge = www_authenticate.parse(res.headers.get('www-authenticate'))

        # XXX HACK HACK: fallback to basic-auth if endpoints does not state what it wants
        if 'basic' in auth_challenge or not auth_challenge:
            self.token_cache.set_auth_method(
                image_reference=image_reference,
                auth_method=AuthMethod.BASIC,
            )
            return # no additional preliminary steps required for basic-auth
        elif 'bearer' in auth_challenge:
            bearer = auth_challenge['bearer']
            service = bearer['service']
            self.token_cache.set_auth_method(
                image_reference=image_reference,
                auth_method=AuthMethod.BEARER,
            )
        else:
            logger.warning(f'did not understand {auth_challenge=} - pbly a bug')

        realm = bearer['realm'] + '?' + urllib.parse.urlencode({
            'scope': scope,
            'service': service,
        })

        if oci_creds:
            auth = requests.auth.HTTPBasicAuth(
              username=oci_creds.username,
              password=oci_creds.password,
            )
        else:
            auth = None

        res = self.session.get(
            url=realm,
            verify=not self.disable_tls_validation,
            auth=auth,
        )

        if not res.ok:
            logger.warning(
                f'rq against {realm=} failed: {res.status_code=} {res.reason=} {res.content=}'
            )

        res.raise_for_status()

        token_dict = res.json()
        token_dict['scope'] = scope

        token = dacite.from_dict(
            data=token_dict,
            data_class=OauthToken,
        )

        self.token_cache.set_token(token)
示例#27
0
文件: __init__.py 项目: fiveai/aiodxf
    async def authenticate(self,
                           username: str = None,
                           password: str = None,
                           actions: list = None,
                           response: aiohttp.ClientResponse = None,
                           authorization: str = None) -> str:
        # pylint: disable=too-many-arguments,too-many-locals
        """
        Authenticate to the registry using a username and password,
        an authorization header or otherwise as the anonymous user.

        :param username: User name to authenticate as.
        :param password: User's password.
        :param actions: If you know which types of operation you need to make on the registry, specify them here. Valid actions are ``pull``, ``push`` and ``*``.
        :param response: When the ``auth`` function you passed to :class:`DXFBase`'s constructor is called, it is passed a HTTP response object. Pass it back to :meth:`authenticate` to have it automatically detect which actions are required.
        :param authorization: ``Authorization`` header value.
        :returns: Authentication token, if the registry supports bearer tokens. Otherwise ``None``, and HTTP Basic auth is used (if the registry requires authentication).
        """
        if response is None:
            response = await self._sessions[0].get(self._base_url,
                                                   ssl=self._tlsverify)

        if response.status == 200:
            return None

        # pylint: disable=no-member
        if response.status != aiohttp.web.HTTPUnauthorized.status_code:
            raise exceptions.DXFUnexpectedStatusCodeError(
                response.status, aiohttp.web.HTTPUnauthorized.status_code)

        if self._insecure:
            raise exceptions.DXFAuthInsecureError()

        parsed = www_authenticate.parse(response.headers['www-authenticate'])

        if username is not None and password is not None:
            headers = {
                'Authorization':
                'Basic ' + base64.b64encode(
                    _to_bytes_2and3(username + ':' + password)).decode('utf-8')
            }
        elif authorization is not None:
            headers = {'Authorization': authorization}
        else:
            headers = {}

        if 'bearer' in parsed:
            info = parsed['bearer']
            if actions and self._repo:
                scope = 'repository:' + self._repo + ':' + ','.join(actions)
            elif 'scope' in info:
                scope = info['scope']
            else:
                scope = ''
            url_parts = list(urlparse.urlparse(info['realm']))
            query = urlparse.parse_qs(url_parts[4])
            query.update({'service': info['service'], 'scope': scope})
            url_parts[4] = urlencode(query, True)
            url_parts[0] = 'https'
            if self._auth_host:
                url_parts[1] = self._auth_host
            auth_url = urlparse.urlunparse(url_parts)
            r = await self._sessions[0].get(auth_url,
                                            headers=headers,
                                            ssl=self._tlsverify)
            _raise_for_status(r)
            rjson = await r.json()
            # Use 'access_token' value if present and not empty, else 'token' value.
            self.token = rjson.get('access_token') or rjson['token']
            return self._token

        self._headers = headers
        return None
示例#28
0
 def get_challenges(self, response):
     challenges = {}
     for k, v in response.headers.items():
         if k.lower() == 'proxy-authenticate':
             challenges.update(www_authenticate.parse(v))
     return challenges