def http_response(self, req, resp): # code for after-fetch, to know whether to save to hard-drive (if stiking to http headers' will) if resp.code == 304: return resp if ('cache-control' in resp.headers or 'pragma' in resp.headers) and self.force_min is None: cache_control = parse_http_list( resp.headers.get('cache-control', ())) cache_control += parse_http_list(resp.headers.get('pragma', ())) cc_list = [x for x in cache_control if '=' not in x] if 'no-cache' in cc_list or 'no-store' in cc_list or ( 'private' in cc_list and not self.private): # kindly follow web servers indications return resp if resp.headers.get('Morss') == 'from_cache': # it comes from cache, so no need to save it again return resp # save to disk data = resp.read() self._save(req.get_full_url(), resp.code, resp.msg, resp.headers, data, time.time()) fp = BytesIO(data) old_resp = resp resp = addinfourl(fp, old_resp.headers, old_resp.url, old_resp.code) resp.msg = old_resp.msg return resp
def http_response(self, req, resp): # code for after-fetch, to know whether to save to hard-drive (if stiking to http headers' will) # NB. It might re-save requests pulled from cache, which will re-set the time() to the latest, i.e. lenghten its useful life if resp.code == 304 and self.is_cached(resp.url): # we are hopefully the first after the HTTP handler, so no need # to re-run all the *_response # here: cached page, returning from cache return self.cached_response(req) elif ('cache-control' in resp.headers or 'pragma' in resp.headers) and self.force_min is None: cache_control = parse_http_list(resp.headers.get('cache-control', ())) cache_control += parse_http_list(resp.headers.get('pragma', ())) cc_list = [x for x in cache_control if '=' not in x] if 'no-cache' in cc_list or 'no-store' in cc_list or ('private' in cc_list and not self.private_cache): # kindly follow web servers indications (do not save & return) return resp else: # save return self.save_response(req, resp) else: return self.save_response(req, resp)
def http_response(self, req, resp): # code for after-fetch, to know whether to save to hard-drive (if stiking to http headers' will) if resp.code == 304: return resp if ('cache-control' in resp.headers or 'pragma' in resp.headers) and self.force_min is None: cache_control = parse_http_list(resp.headers.get('cache-control', ())) cache_control += parse_http_list(resp.headers.get('pragma', ())) cc_list = [x for x in cache_control if '=' not in x] if 'no-cache' in cc_list or 'no-store' in cc_list or ('private' in cc_list and not self.private): # kindly follow web servers indications return resp if resp.headers.get('Morss') == 'from_cache': # it comes from cache, so no need to save it again return resp # save to disk data = resp.read() self._save(req.get_full_url(), resp.code, resp.msg, resp.headers, data, time.time()) fp = BytesIO(data) old_resp = resp resp = addinfourl(fp, old_resp.headers, old_resp.url, old_resp.code) resp.msg = old_resp.msg return resp
def parse_oauth_header(header): type, rest = header.split(" ", 1) if type != "OAuth": raise ValueError("Authorization is not of OAuth type") return urllib2.parse_keqv_list(urllib2.parse_http_list(rest))
def parse_401_response_headers(response_headers): """ Parse the headers from a 401 response into a dictionary that contains the information necessary to retrieve a token. Example: Www-Authenticate: Bearer realm="https://auth.docker.io/token", service="registry.docker.io",scope="repository:library/nginx:pull,push" """ auth_header = response_headers.get("www-authenticate") if auth_header is None: raise IOError( "401 responses are expected to contain authentication information") auth_header = auth_header[len("Bearer "):] # The remaining string consists of comma separated key=value pairs # according to RFC 2617 try: items = request.parse_http_list(auth_header) return request.parse_keqv_list(items) except ValueError as e: six.raise_from( IOError( "401 responses are expected to contain authentication information" ), e, )
def test_parse_http_list(self): tests = [('a,b,c', ['a', 'b', 'c']), ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']), ('a, b, "c", "d", "e,f", g, h', ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']), ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"'])] for string, list in tests: self.assertEquals(urllib2.parse_http_list(string), list)
def compose(self, digest=None, basic=None, username=None, password=None, challenge=None, path=None, method=None): assert username and password if basic or not challenge: assert not digest userpass = "******" % (username.strip(), password.strip()) return "Basic %s" % userpass.encode('base64').strip() assert challenge and not basic path = path or "/" (_, realm) = challenge.split('realm="') (realm, _) = realm.split('"', 1) auth = urllib2.AbstractDigestAuthHandler() auth.add_password(realm, path, username, password) (token, challenge) = challenge.split(' ', 1) chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) class FakeRequest(object): def get_full_url(self): return path def has_data(self): return False def get_method(self): return method or "GET" get_selector = get_full_url retval = "Digest %s" % auth.get_authorization(FakeRequest(), chal) return (retval,)
def parse_authorization_header(value): """Parse the Authenticate header Returns nothing on failure, opts hash on success with type='basic' or 'digest' and other params. <http://nullege.com/codes/search/werkzeug.http.parse_authorization_header> <http://stackoverflow.com/questions/1349367/parse-an-http-request-authorization-header-with-python> <http://bugs.python.org/file34041/0001-Add-an-authorization-header-to-the-initial-request.patch> """ try: (auth_type, auth_info) = value.split(' ', 1) auth_type = auth_type.lower() except ValueError as e: return if (auth_type == 'basic'): try: (username, password) = base64.b64decode(auth_info).split(':', 1) except Exception as e: return return {'type':'basic', 'username': username, 'password': password} elif (auth_type == 'digest'): auth_map = urllib2.parse_keqv_list(urllib2.parse_http_list(auth_info)) print auth_map for key in 'username', 'realm', 'nonce', 'uri', 'response': if not key in auth_map: return if 'qop' in auth_map: if not auth_map.get('nc') or not auth_map.get('cnonce'): return auth_map['type']='digest' return auth_map else: # unknown auth type return
def parse_options_header(value): result = [] for item in urllib2.parse_http_list(value): if item[:1] == item[-1:] == '"': item = unquote_header_value(item[1:-1]) result.append(item) return result
def get(self): assert self.current_user origin = self.get_argument("origin", None) session = model.Session() actions_param = self.get_argument("actions", None) where = [model.UserConsent.user_id==self.current_user] if origin is not None: where.append(model.UserConsent.origin==origin) if actions_param is not None: actions = actions_param.split(",") where.append(model.UserConsent.operation.in_(actions)) existing = session.query(model.UserConsent).filter( and_(*where)).all() result = {} for e in existing: origin_result = result.setdefault(e.origin, {}) origin_result[e.operation] = e.allowed # work out if we are trying to serve up the html ui or just the data. accepts = urllib2.parse_http_list(self.request.headers.get("Accept", "")) try: json_ndx = accepts.index("application/json") except ValueError: json_ndx = 10000 try: html_ndx = accepts.index("text/html") except ValueError: html_ndx = 10000 if html_ndx < json_ndx: self.render("consent.html", consent_items=result) else: self.write(result)
def registry_get(self, api): url = "https://%s/v2/%s" % (self.registry, api) response = get( url, auth=(self.user, self.password), headers={ "Accept": 'application/vnd.docker.distribution.manifest.v2+json' }, verify=self.verify) if response.status_code == 401: challenge = response.headers['Www-Authenticate'] if challenge.startswith("Bearer "): challenge = challenge[7:] opts = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) authresp = get( "{realm}?service={service}&scope={scope}".format(**opts), auth=(self.user, self.password), verify=self.verify) if authresp.ok: token = authresp.json()['token'] response = get(url, headers={'Authorization': 'Bearer %s' % token}, verify=self.verify) else: raise TaskError( "problem authenticating with docker registry: [%s] %s" % (authresp.status_code, authresp.content)) return response
def check_auth(self, header, method='GET'): "Check a response to our auth challenge" from urllib2 import parse_http_list H, KD = self.get_algorithm_impls() resp = parse_keqv_list(parse_http_list(header)) algo = resp.get('algorithm', 'MD5').upper() if algo != self.algorithm: return False, "unknown algo %s"%algo user = resp['username'] realm = resp['realm'] nonce = resp['nonce'] # XXX Check the nonce is something we've issued HA1 = self._user_hashes.get((user,realm)) if not HA1: return False, "unknown user/realm %s/%s"%(user, realm) qop = resp.get('qop') if qop != 'auth': return False, "unknown qop %r"%(qop) cnonce, ncvalue = resp.get('cnonce'), resp.get('nc') if not cnonce or not ncvalue: return False, "failed to provide cnonce" # Check the URI is correct! A2 = '%s:%s'%(method, resp['uri']) noncebit = "%s:%s:%s:%s:%s" % (nonce,ncvalue,cnonce,qop,H(A2)) respdig = KD(HA1, noncebit) if respdig != resp['response']: return False, "response incorrect" print "all ok" return True, "OK"
def parse_authorization_header(header): """ Parse requests authorization header into list. Raise ValueError if some problem occurs. """ # digest is marked as part of header and causes problem # parsing, so remove its if not header.startswith('Digest '): raise ValueError("Header do not start with Digest") header = header[len('Digest '):] # Convert the auth params to a dict items = urllib2.parse_http_list(header) params = urllib2.parse_keqv_list(items) required = ["username", "realm", "nonce", "uri", "response"] for field in required: if not params.has_key(field): raise ValueError("Required field %s not found" % field) # check for qop companions (sect. 3.2.2) if params.has_key( "qop") and not params.has_key("cnonce") and params.has_key("cn"): raise ValueError("qop sent without cnonce and cn") return params
def parse_authorization_header(header): """ Parse requests authorization header into list. Raise ValueError if some problem occurs. """ # digest is marked as part of header and causes problem # parsing, so remove its if not header.startswith("Digest "): raise ValueError("Header do not start with Digest") header = header[len("Digest ") :] # Convert the auth params to a dict items = urllib2.parse_http_list(header) params = urllib2.parse_keqv_list(items) required = ["username", "realm", "nonce", "uri", "response"] for field in required: if not params.has_key(field): raise ValueError("Required field %s not found" % field) # check for qop companions (sect. 3.2.2) if params.has_key("qop") and not params.has_key("cnonce") and params.has_key("cn"): raise ValueError("qop sent without cnonce and cn") return params
def check_auth(self, header, method='GET'): "Check a response to our auth challenge" from urllib2 import parse_http_list H, KD = self.get_algorithm_impls() resp = parse_keqv_list(parse_http_list(header)) algo = resp.get('algorithm', 'MD5').upper() if algo != self.algorithm: return False, "unknown algo %s" % algo user = resp['username'] realm = resp['realm'] nonce = resp['nonce'] # XXX Check the nonce is something we've issued HA1 = self._user_hashes.get((user, realm)) if not HA1: return False, "unknown user/realm %s/%s" % (user, realm) qop = resp.get('qop') if qop != 'auth': return False, "unknown qop %r" % (qop) cnonce, ncvalue = resp.get('cnonce'), resp.get('nc') if not cnonce or not ncvalue: return False, "failed to provide cnonce" # Check the URI is correct! A2 = '%s:%s' % (method, resp['uri']) noncebit = "%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, H(A2)) respdig = KD(HA1, noncebit) if respdig != resp['response']: return False, "response incorrect" print "all ok" return True, "OK"
def _parseHeader(self, authheader, request): n = 7 # n = len("Digest ") try: authheader = authheader[n:].strip() items = urllib2.parse_http_list(authheader) request.env['__DIGEST_PARAMS__'] = urllib2.parse_keqv_list(items) except Exception, e: request.env['__DIGEST_PARAMS__'] = {}
def parse_auth_header(self, authorization): values = {} for value in urllib2.parse_http_list(authorization): n, v = value.split("=", 1) if v[0] == '"' and v[-1] == '"': values[n] = v[1:-1] else: values[n] = v return values
def test_parse_http_list(self): tests = [ ("a,b,c", ["a", "b", "c"]), ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', "example"]), ('a, b, "c", "d", "e,f", g, h', ["a", "b", '"c"', '"d"', '"e,f"', "g", "h"]), ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"']), ] for string, list in tests: self.assertEqual(urllib2.parse_http_list(string), list)
def parse_auth_header(self, authorization): values = {} for value in urllib2.parse_http_list(authorization): n, v = value.split('=', 1) if v[0] == '"' and v[-1] == '"': values[n] = v[1:-1] else: values[n] = v return values
def parse_authorization_header(authorization_header): """Parse an OAuth authorization header into a list of 2-tuples""" auth_scheme = 'OAuth ' if authorization_header.startswith(auth_scheme): authorization_header = authorization_header.replace(auth_scheme, '', 1) items = urllib2.parse_http_list(authorization_header) try: return urllib2.parse_keqv_list(items).items() except ValueError: raise ValueError('Malformed authorization header')
def parse_list_header(value): """ Parse lists as described by RFC 2068 Section 2. """ result = [] for item in urllib2.parse_http_list(value): if item[:1] == item[-1:] == '"': item = unquote_header_value(item[1:-1]) result.append(item) return result
def _parse(self, authorization): scheme, rest = authorization.split(None, 1) args = urllib2.parse_keqv_list(urllib2.parse_http_list(rest)) challengeType = { 'basic': BasicChallenge, 'digest': DigestChallenge, }.get(scheme.lower()) if challengeType is None: return "", None return scheme.lower(), challengeType(**args)
def __init__(self, auth_header, http_method, debug=False): self.http_method = http_method self.debug = debug scheme, params = auth_header.split(" ", 1) self.scheme = scheme.lower() if self.scheme != 'digest': raise ValueError('Authorization scheme is not "Digest"') self.auth_header = auth_header # make a dict of the params items = parse_http_list(params) paramsd = parse_keqv_list(items) self.realm = paramsd.get('realm') self.username = paramsd.get('username') self.nonce = paramsd.get('nonce') self.uri = paramsd.get('uri') self.method = paramsd.get('method') self.response = paramsd.get('response') # the response digest self.algorithm = paramsd.get('algorithm', 'MD5') self.cnonce = paramsd.get('cnonce') self.opaque = paramsd.get('opaque') self.qop = paramsd.get('qop') # qop self.nc = paramsd.get('nc') # nonce count # perform some correctness checks if self.algorithm not in valid_algorithms: raise ValueError( self.errmsg("Unsupported value for algorithm: '%s'" % self.algorithm)) has_reqd = self.username and \ self.realm and \ self.nonce and \ self.uri and \ self.response if not has_reqd: raise ValueError( self.errmsg("Not all required parameters are present.")) if self.qop: if self.qop not in valid_qops: raise ValueError( self.errmsg("Unsupported value for qop: '%s'" % self.qop)) if not (self.cnonce and self.nc): raise ValueError( self.errmsg( "If qop is sent then cnonce and nc MUST be present")) else: if self.cnonce or self.nc: raise ValueError( self.errmsg( "If qop is not sent, neither cnonce nor nc can be present" ))
def _digest_login_callback(self, response): self._update_session_cookie(response) if response.code == 200: self._authenticated = True self._alive = True print response.headers print 'yay' return elif response.code == 401: print 'meh' else: print 'boo' return #If 401 if not 'WWW-Authenticate' in response.headers: raise InterfaceError() if not 'Digest' in response.headers['WWW-Authenticate']: raise InterfaceError() param_string = response.headers.get('WWW-Authenticate').partition( 'Digest')[2] param_list = parse_http_list(param_string) params = parse_keqv_list(param_list) path = urlsplit( response.effective_url) #asterisk throws query into hash digest_path = "%s?%s" % (path.path, path.query) digest_cnonce = uuid.uuid1().hex digest_nc = '%08d' % self._digest_nc digest_qop = "auth" digest_response = md5(":".join([ md5(":".join( (self._username, params['realm'], self._secret))).hexdigest(), params['nonce'], digest_nc, digest_cnonce, digest_qop, md5(":".join(('GET', digest_path))).hexdigest() ])).hexdigest() headers = {} headers[ 'Authorization'] = 'Digest username="******", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop="%s", response="%s", opaque="%s", algorithm="%s"' % ( self._username, params['realm'], params['nonce'], digest_path, digest_cnonce, digest_nc, digest_qop, digest_response, params['opaque'], params['algorithm']) self._digest_nc += 1 self.command(self._authentication_request, headers=headers)
def retry_http_digest_auth(self, req, resp, host, auth): _token, challenge = auth.split(' ', 1) chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) auth = self.get_authorization(req, chal) if auth: auth_val = 'Digest %s' % auth if req.headers.get(self.auth_header, None) == auth_val: return None req.add_unredirected_header(self.auth_header, auth_val) return 'request', req return None
def retry_http_digest_auth(self, req, auth): token, challenge = auth.split(' ', 1) chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) auth = self.get_authorization(req, chal) if auth: auth_val = 'X-Digest %s' % auth if req.headers.get(self.auth_header, None) == auth_val: return None req.add_unredirected_header(self.auth_header, auth_val) resp = self.parent.open(req, timeout=req.timeout) return resp
def retry_http_digest_auth(self, req, auth): token, challenge = auth.split(' ', 1) chal = parse_keqv_list(parse_http_list(challenge)) auth = self.get_authorization(req, chal) if auth: auth_val = 'Digest %s' % auth if req.headers.get(self.auth_header, None) == auth_val: return None newreq = copy.copy(req) newreq.add_unredirected_header(self.auth_header, auth_val) newreq.visit = False return self.parent.open(newreq)
def retry_http_digest_auth(self, req, resp, host, auth): _token, challenge = auth.split(" ", 1) chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) auth = self.get_authorization(req, chal) if auth: auth_val = "Digest %s" % auth if req.headers.get(self.auth_header, None) == auth_val: return None req.add_unredirected_header(self.auth_header, auth_val) return "request", req return None
def _authenticate_quay(self, headers): """ Attempt to perform an authentication with registry's authentication server. Once authentication is complete, add the token to the Session object. Specifics can be found at https://docs.docker.com/registry/spec/auth/token/ Args: headers (dict): Headers of the 401 response received from the registry. Raises: RegistryAuthError: When there's an issue with the authentication procedure. """ if "WWW-Authenticate" not in headers: raise RegistryAuthError( "'WWW-Authenticate' is not in the 401 response's header. " "Authentication cannot continue.") if "Bearer " not in headers["WWW-Authenticate"]: raise RegistryAuthError( "Different than the Bearer authentication type was requested. " "Only Bearer is supported.") # parse header to get a dictionary params = request.parse_keqv_list( request.parse_http_list( headers["WWW-Authenticate"][len("Bearer "):]) # noqa: E203 ) host = params.pop("realm") session = requests.Session() retry = Retry( total=3, read=3, connect=3, backoff_factor=2, status_forcelist=set(range(500, 512)), ) adapter = requests.adapters.HTTPAdapter(max_retries=retry) session.mount("http://", adapter) session.mount("https://", adapter) # Make an authentication request to the specified realm with the provided REST parameters. # Basic username + password authentication is expected. r = session.get(host, params=params, auth=(self.username, self.password), timeout=10) r.raise_for_status() if "token" not in r.json(): raise RegistryAuthError( "Authentication server response doesn't contain a token.") self.session.set_auth_token(r.json()["token"])
def authorized(self): tcs = self.server.test_case_server auth_header = self.headers.get(tcs.auth_header_recv, None) if auth_header is None: return False scheme, auth = auth_header.split(None, 1) if scheme.lower() == tcs.auth_scheme: auth_dict = urllib2.parse_keqv_list(urllib2.parse_http_list(auth)) return tcs.digest_authorized(auth_dict, self.command) return False
def parse_dict_header(value): """Parse key=value pairs from value list """ result = {} for item in parse_http_list(value): if "=" not in item: result[item] = None continue name, value = item.split('=', 1) if value[:1] == value[-1:] == '"': value = urllib.unquote(value[1:-1]) # strip " and unquote result[name] = value return result
def createAuthObject(authHeader): """ Returns the authentication mechanism, or None if not implemented. """ authType, challenge = authHeader.split(' ', 1) _authType_lower = authType.lower() challenge = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) assert _authType_lower in ('digest', 'ssl'), \ repr(_authType_lower) # "basic" authentication is not supported return DigestAuthentication(challenge) if _authType_lower == 'digest' \ else None
def _parse(self, authorization): try: scheme, rest = authorization.split(None, 1) except ValueError: # Probably "negotiate", which we don't support scheme = authorization rest = "" args = urllib2.parse_keqv_list(urllib2.parse_http_list(rest)) challengeType = { 'basic': BasicChallenge, 'digest': DigestChallenge, }.get(scheme.lower()) if challengeType is None: return "", None return scheme.lower(), challengeType(**args)
def parse_dict_header(value): """Parse key=value pairs from value list :param value: header string :return: params dict """ result = {} for item in parse_http_list(value): if "=" not in item: result[item] = None continue name, value = item.split('=', 1) if value[:1] == value[-1:] == '"': value = value[1:-1] # strip " result[name] = value return result
def __init__(self, auth_header, http_method, debug=False): self.http_method = http_method self.debug = debug scheme, params = auth_header.split(" ", 1) self.scheme = scheme.lower() if self.scheme != 'digest': raise ValueError('Authorization scheme is not "Digest"') self.auth_header = auth_header # make a dict of the params items = parse_http_list(params) paramsd = parse_keqv_list(items) self.realm = paramsd.get('realm') self.username = paramsd.get('username') self.nonce = paramsd.get('nonce') self.uri = paramsd.get('uri') self.method = paramsd.get('method') self.response = paramsd.get('response') # the response digest self.algorithm = paramsd.get('algorithm', 'MD5') self.cnonce = paramsd.get('cnonce') self.opaque = paramsd.get('opaque') self.qop = paramsd.get('qop') # qop self.nc = paramsd.get('nc') # nonce count # perform some correctness checks if self.algorithm not in valid_algorithms: raise ValueError(self.errmsg("Unsupported value for algorithm: '%s'" % self.algorithm)) has_reqd = self.username and \ self.realm and \ self.nonce and \ self.uri and \ self.response if not has_reqd: raise ValueError(self.errmsg("Not all required parameters are present.")) if self.qop: if self.qop not in valid_qops: raise ValueError(self.errmsg("Unsupported value for qop: '%s'" % self.qop)) if not (self.cnonce and self.nc): raise ValueError(self.errmsg("If qop is sent then cnonce and nc MUST be present")) else: if self.cnonce or self.nc: raise ValueError(self.errmsg("If qop is not sent, neither cnonce nor nc can be present"))
def _parseDigestAuthorization (auth_params): # Convert the auth params to a dict items = urllib2.parse_http_list (auth_params) params = urllib2.parse_keqv_list (items) # Now validate the params # Check for required parameters required = ["username", "realm", "nonce", "uri", "response"] for k in required: if not params.has_key(k): return None # If qop is sent then cnonce and cn MUST be present if params.has_key("qop") and not params.has_key("cnonce") \ and params.has_key("cn"): return None return params
def dr(self, url, expected=(), user=None, password=None): user = user or self.user password = password or self.password response = self.get(url, auth=(user, password), expected=expected + (401, )) if response.status_code == 401: challenge = response.headers['Www-Authenticate'] if challenge.startswith("Bearer "): challenge = challenge[7:] opts = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) token = self.get( "{realm}?service={service}&scope={scope}".format(**opts), auth=(user, password)).json()['token'] response = self.get(url, headers={'Authorization': 'Bearer %s' % token}, expected=expected) return response
def get_proxy_authorization_line(auth_type, auth_details, method, url, proxy_username, proxy_password): if auth_type.lower() == 'basic': response = base64.encodestring('%s:%s' % (proxy_username, proxy_password)).strip() elif auth_type.lower() == 'digest': class Passwd: def __init__(self, user, passwd): self.user, self.passwd = user, passwd def add_password(self, user, passwd): pass def find_user_password(self, realm, url): return (self.user, self.passwd) def get_full_url(self): return '' class DummyRequest: def __init__(self, method, url): self.method, self.url = method, url def get_method(self): return self.method def get_selector(self): return self.url def get_full_url(self): return self.url def has_data(self): return False digest_auth_handler = urllib2.AbstractDigestAuthHandler(passwd=Passwd(proxy_username or '', proxy_password or '')) chal = urllib2.parse_keqv_list(urllib2.parse_http_list(auth_details)) response = digest_auth_handler.get_authorization(DummyRequest(method, url), chal) else: raise ValueError('Invalid proxy-authenticate line %r' % auth_type) return 'Proxy-Authorization: %s %s' % (auth_type, response)
def http_error_401(self, req, fp, code, msg, headers): host = urllib2.urlparse.urlparse(req.get_full_url())[1] authreq = headers.get('www-authenticate', None) if authreq == None: return None authreq = authreq.split(' ', 1) if authreq[0].lower() != 'basic': return None chal = urllib2.parse_keqv_list(urllib2.parse_http_list(authreq[1])) realm = chal['realm'] self.auth = (host, realm) self.retried += 1 if self.retried >= 3: self.f.delkey(proto="pass", host=host, realm=realm, role="client") self.f.start(proto="pass", host=host, realm=realm, role="client") pw = self.f.read().replace(' ', ':', 1) val = 'Basic %s' % base64.b64encode(pw).strip() if req.headers.get('Authorization', None) == val: return None req.add_header('Authorization', val) result = self.parent.open(req) self.retried = 0 return result
def _parse_auth_info(auth_info): method, info_str = auth_info.split(' ', 1) if method != "Digest": raise ProviderError("Unknown authentication method: %s" % method) items = parse_http_list(info_str) info = parse_keqv_list(items) try: qop = info["qop"] realm = info["realm"] nonce = info["nonce"] except KeyError as e: raise ProviderError( "Authentication request missing required key: %s" % e) algorithm = info.get("algorithm", "MD5") if algorithm != "MD5": raise ProviderError("Unsupported digest algorithm: %s" % algorithm) if "auth" not in qop.split(","): raise ProviderError("Unsupported quality-of-protection: %s" % qop) return realm, nonce, "auth", algorithm
def _parse_auth_info(auth_info): method, info_str = auth_info.split(' ', 1) if method != "Digest": raise ProviderError("Unknown authentication method: %s" % method) items = parse_http_list(info_str) info = parse_keqv_list(items) try: qop = info["qop"] realm = info["realm"] nonce = info["nonce"] except KeyError as e: raise ProviderError("Authentication request missing required key: %s" % e) algorithm = info.get("algorithm", "MD5") if algorithm != "MD5": raise ProviderError("Unsupported digest algorithm: %s" % algorithm) if "auth" not in qop.split(","): raise ProviderError("Unsupported quality-of-protection: %s" % qop) return realm, nonce, "auth", algorithm
def parse_list_header(value): """Parse lists as described by RFC 2068 Section 2. In particular, parse comma-separated lists where the elements of the list may include quoted-strings. A quoted-string could contain a comma. A non-quoted string could have quotes in the middle. Quotes are removed automatically after parsing. The return value is a standard :class:`list`: >>> parse_list_header('token, "quoted value"') ['token', 'quoted value'] :param value: a string with a list header. :return: :class:`list` """ result = [] for item in urllib2.parse_http_list(value): if item[:1] == item[-1:] == '"': item = unquote_header_value(item[1:-1]) result.append(item) return result
def http_error_401(self, req, fp, code, msg, headers): self.retried += 1 host = urllib2.urlparse.urlparse(req.get_full_url())[1] authreq = headers.get('www-authenticate', None) if authreq == None: return None authreq = authreq.split(' ', 1) if authreq[0].lower() != 'digest': return None chal = urllib2.parse_keqv_list(urllib2.parse_http_list(authreq[1])) realm = chal['realm'] nonce = chal['nonce'] if self.retried >= 6: self.f.delkey(proto="httpdigest", realm=realm, host=host) self.f.start(proto="httpdigest", role="client", realm=realm, host=host) self.f.write(nonce + ' ' + req.get_method() + ' ' + req.get_selector()) resp = self.f.read() user = self.f.attr()["user"] self.f.close() val = 'Digest username="******", realm="%s", nonce="%s", uri="%s", response="%s", algorithm=MD5' % (user, realm, nonce, req.get_selector(), resp) if req.headers.get('Authorization', None) == val: return None req.add_unredirected_header('Authorization', val) result = self.parent.open(req) self.retried = 0 return result
def http_error_401(self, req, fp, code, msg, headers): self.retried += 1 host = urllib2.urlparse.urlparse(req.get_full_url())[1] authreq = headers.get('www-authenticate', None) if authreq == None: return None authreq = authreq.split(' ', 1) if authreq[0].lower() != 'digest': return None chal = urllib2.parse_keqv_list(urllib2.parse_http_list(authreq[1])) realm = chal['realm'] nonce = chal['nonce'] if self.retried >= 6: self.f.delkey(proto="httpdigest", realm=realm, host=host) self.f.start(proto="httpdigest", role="client", realm=realm, host=host) self.f.write(nonce + ' ' + req.get_method() + ' ' + req.get_selector()) resp = self.f.read() user = self.f.attr()["user"] self.f.close() val = 'Digest username="******", realm="%s", nonce="%s", uri="%s", response="%s", algorithm=MD5' % ( user, realm, nonce, req.get_selector(), resp) if req.headers.get('Authorization', None) == val: return None req.add_unredirected_header('Authorization', val) result = self.parent.open(req) self.retried = 0 return result