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 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) 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 = {} 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) 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