def login(wwwAuth, repository, host=None, forceCredential=False): authresp = wwwAuth realm = parse_keqv_list(parse_http_list(authresp[authresp.index(' ') + 1:])) realmurl = urlparse(realm['realm']) credentialHost = host if host is not None else realmurl.netloc with closing(httplib.HTTPSConnection(realmurl.netloc)) as authhttps: authhttps.request( 'GET', '%s?scope=repository:%s:pull&service=%s' % (realmurl.path, repository, realm['service']), None) resp = authhttps.getresponse() if forceCredential or resp.status == 401 or resp.status == 403: resp.read() basic = getCredential(credentialHost) if basic: account = base64.b64decode(basic).decode('utf-8').split(':')[0] authhttps.request( 'GET', '%s?account=%s&scope=repository:%s:pull&service=%s' % (realmurl.path, account, repository, realm['service']), None, {'Authorization': 'Basic ' + basic}) resp = authhttps.getresponse() if resp.status == 401: raise Exception( 'Credential is wrong (used "%s"). Please relogin to %s.' % (account, credentialHost)) else: raise Exception('`docker login %s` is required.' % (credentialHost)) token = json.load(resp)['token'] return {'Authorization': 'Bearer ' + token}
def authorization(self) -> Optional[Authorization]: header = self.headers.get("Authorization", "") try: type_, value = header.split(None, 1) type_ = type_.lower() except ValueError: return None else: if type_ == "basic": try: username, password = b64decode( value.encode()).decode().split(":", 1) except ValueError: return None else: return Authorization(username=username, password=password) elif type_ == "digest": items = parse_http_list(value) params = parse_keqv_list(items) for key in "username", "realm", "nonce", "uri", "response": if key not in params: return None if ("cnonce" in params or "nc" in params) and "qop" not in params: return None return Authorization(**params) return None
def process_request(self, url, body, headers): if not headers: headers = {} self.logger.debug("[%s] Process middleware on: %s", self.name, url) # First query - 401 code, resp_headers, result = fetch_sync( url, headers=None, request_timeout=60, follow_redirects=True, allow_proxy=False, validate_cert=False, eof_mark=self.eof_mark, ) self.logger.debug( "[%s] Response code %s, headers %s on: %s, body: %s", self.name, code, resp_headers, url, body, ) if "WWW-Authenticate" in resp_headers and resp_headers["WWW-Authenticate"].startswith( "Digest" ): items = parse_http_list(resp_headers["WWW-Authenticate"][7:]) digest_response = parse_keqv_list(items) headers["Authorization"] = self.build_digest_header(url, self.method, digest_response) self.logger.debug("[%s] Set headers, %s", self.name, headers) return url, body, headers
def parse_www_authenticate_header(header): """ Convert a WWW-Authentication header into a dict that can be used in a JSON response. """ items = parse_http_list(header) return parse_keqv_list(items)
def _get_auth_info(self, response): """Parse a 401 response and get the needed auth parameters.""" www_auth = response.headers["Www-Authenticate"] if not www_auth.startswith("Bearer "): raise ValueError("Bearer not found") info = parse_keqv_list(parse_http_list(www_auth[7:])) return info
def _fetch_oauth2_token(self, host, response_headers): www_auth = response_headers['WWW-Authenticate'] dockercfg = self.pull_secret.for_host(host) if not www_auth.startswith('Bearer ') or not dockercfg: return None items = parse_http_list(www_auth[7:]) opts = parse_keqv_list(items) # realm, scope, service realm = urlparse(opts['realm']) url = ('{path}' '?client_id=docker' '&offline_token=true' '&service={service}' '&scope={scope}').format(path=realm.path, **opts) c = http.client.HTTPSConnection(realm.netloc) c.request('GET', url, headers={ 'Authorization': "Basic {}".format(dockercfg['auth']) }) r = c.getresponse() if r.status != 200: return False data = json.loads(r.read()) self.headers['Authorization'] = 'Bearer {}'.format(data['token']) return True
def authorization(self) -> Optional[Authorization]: header = self.headers.get('Authorization', '') try: type_, value = header.split(None, 1) type_ = type_.lower() except ValueError: return None else: if type_ == 'basic': try: username, password = b64decode( value.encode()).decode().split(':', 1) except ValueError: return None else: return Authorization(username=username, password=password) elif type_ == 'digest': items = parse_http_list(value) params = parse_keqv_list(items) for key in 'username', 'realm', 'nonce', 'uri', 'response': if key not in params: return None if ('cnonce' in params or 'nc' in params) and 'qop' not in params: return None return Authorization(**params) return None
def __init__( self, auth_header, http_method, debug=False, accept_charset=DEFAULT_CHARSET[:], ): self.http_method = http_method self.debug = debug if not self.matches(auth_header): raise ValueError('Authorization scheme is not "Digest"') self.auth_header = _try_decode_header(auth_header, accept_charset) scheme, params = self.auth_header.split(' ', 1) # 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').upper() 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 wrapped(self): if not hasattr(self, 'authenticated'): self.authenticated = None auth = self.headers.get('Authorization') if not self.authenticated and auth is not None: token, fields = auth.split(' ', 1) if token == 'Digest': cred = parse_http_list(fields) cred = parse_keqv_list(cred) # The request must contain all these keys to # constitute a valid response. keys = 'realm username nonce uri response'.split() if not all(cred.get(key) for key in keys): self.authenticated = False elif cred['realm'] != realm or cred['username'] not in accounts: self.authenticated = False elif 'qop' in cred and ('nc' not in cred or 'cnonce' not in cred): self.authenticated = False else: location = '%s:%s' % (self.command, self.path) location = location.encode('utf8') location = md5hex(location) password = accounts.get_password(cred['username']) if 'qop' in cred: info = (cred['nonce'], cred['nc'], cred['cnonce'], cred['qop'], location) else: info = cred['nonce'], location expect = '%s:%s' % (password, ':'.join(info)) expect = md5hex(expect.encode('utf8')) self.authenticated = (expect == cred['response']) if self.authenticated: self.crunchy_username = cred['username'] if self.authenticated is None: msg = "You are not allowed to access this page. Please login first!" elif self.authenticated is False: msg = "Authenticated Failed" if not self.authenticated : self.send_response(401) nonce = ("%d:%s" % (time.time(), realm)).encode('utf8') self.send_header('WWW-Authenticate', 'Digest realm="%s",' 'qop="auth",' 'algorithm="MD5",' 'nonce="%s"' % (realm, nonce)) self.end_headers() self.wfile.write(msg.encode('utf8')) else: return func(self)
def wrapped(self): if not hasattr(self, 'authenticated'): self.authenticated = None if self.authenticated: return func(self) auth = self.headers.get('Authorization') if auth is None: msg = "You are not allowed to access this page. Please login first!" return _error_401(self, msg) token, fields = auth.split(' ', 1) if token != 'Digest': return _error_401(self, 'Unsupported authentication type') # Check the header fields of the request. cred = parse_http_list(fields) cred = parse_keqv_list(cred) keys = 'realm', 'username', 'nonce', 'uri', 'response' if not all(cred.get(key) for key in keys): return _error_401(self, 'Incomplete authentication header') if cred['realm'] != self.server.realm: return _error_401(self, 'Incorrect realm') if 'qop' in cred and ('nc' not in cred or 'cnonce' not in cred): return _error_401(self, 'qop with missing nc or cnonce') # Check the username. username = cred['username'] password = self.server.get_password(username) if not username or password is None: return _error_401(self, 'Invalid username or password') # Check the digest string. location = '%s:%s' % (self.command, self.path) location = md5hex(location.encode('utf8')) pwhash = md5hex('%s:%s:%s' % (username, self.server.realm, password)) if 'qop' in cred: info = (cred['nonce'], cred['nc'], cred['cnonce'], cred['qop'], location) else: info = cred['nonce'], location expect = '%s:%s' % (pwhash, ':'.join(info)) expect = md5hex(expect.encode('utf8')) if expect != cred['response']: return _error_401(self, 'Invalid username or password') # Success! self.authenticated = True return func(self)
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 = parse_keqv_list(parse_http_list(auth)) return tcs.digest_authorized(auth_dict, self.command) return False
def from_header( cls: Type['_CacheControl'], header: str, on_update: Optional[Callable] = None, ) -> '_CacheControl': cache_control = cls(on_update) for item in parse_http_list(header): if '=' in item: for key, value in parse_keqv_list([item]).items(): cache_control._directives[key] = value else: cache_control._directives[item] = True return cache_control
def wrapped(self): if not hasattr(self, 'authenticated'): self.authenticated = None if self.authenticated: return func(self) auth = self.headers.get(u'Authorization') if auth is None: msg = u"You are not allowed to access this page. Please login first!" return _error_401(self, msg) token, fields = auth.split(' ', 1) if token != 'Digest': return _error_401(self, 'Unsupported authentication type') # Check the header fields of the request. cred = parse_http_list(fields) cred = parse_keqv_list(cred) keys = u'realm', u'username', u'nonce', u'uri', u'response' if not all(cred.get(key) for key in keys): return _error_401(self, 'Incomplete authentication header') if cred['realm'] != self.server.realm: return _error_401(self, 'Incorrect realm') if 'qop' in cred and ('nc' not in cred or 'cnonce' not in cred): return _error_401(self, 'qop with missing nc or cnonce') # Check the username. username = cred['username'] password = self.server.get_password(username) if not username or password is None: return _error_401(self, 'Invalid username or password') # Check the digest string. location = u'%s:%s' % (self.command, self.path) location = md5hex(location.encode('utf8')) pwhash = md5hex('%s:%s:%s' % (username, self.server.realm, password)) if 'qop' in cred: info = (cred['nonce'], cred['nc'], cred['cnonce'], cred['qop'], location) else: info = cred['nonce'], location expect = u'%s:%s' % (pwhash, ':'.join(info)) expect = md5hex(expect.encode('utf8')) if expect != cred['response']: return _error_401(self, 'Invalid username or password') # Success! self.authenticated = True return func(self)
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 = AbstractDigestAuthHandler() auth.add_password(realm, path, username, password) (token, challenge) = challenge.split(' ', 1) chal = parse_keqv_list(parse_http_list(challenge)) class FakeRequest(object): if six.PY3: @property def full_url(self): return path selector = full_url @property def data(self): return None else: def get_full_url(self): return path get_selector = get_full_url def has_data(self): return False def get_method(self): return method or "GET" retval = "Digest %s" % auth.get_authorization(FakeRequest(), chal) return (retval, )
def get_opener(self): # The opener is yet build ? if self.opener is not None: return self.opener # Build a new opener opener = build_opener() headers = [ ('User-agent', 'restedit/%s' % __version__) ] # Add the "includes" for include in self.includes: headers.append(include) # An authentication ? auth_header = self.metadata.get('auth') if auth_header is not None: if auth_header.lower().startswith('basic'): cls_handler = HTTPBasicAuthHandler chal = auth_header[6:].strip() # Automatically find the username and the password username, password = decode_base64(chal).split(':', 1) elif auth_header.lower().startswith('digest'): cls_handler = HTTPDigestAuthHandler # Automatically find the username, but we must ask the password # XXX undocumented functions chal = parse_keqv_list(parse_http_list(auth_header[7:])) username = chal['username'] password = askPassword(chal['realm'], username) else: raise NotImplemented password_mgr = HTTPPasswordMgrWithDefaultRealm() password_mgr.add_password(realm=None, uri=self.url, user=username, passwd=password) auth_handler = cls_handler(password_mgr) opener.add_handler(auth_handler) # A cookie ? if self.metadata.get('cookie'): headers.append( ('Cookie', self.metadata['cookie']) ) # All OK opener.addheaders = headers self.opener = opener return opener
def parse_rtsp_header(data: bytes) -> Tuple[int, Dict[str, Any], bytes]: code, headers, msg = 200, {}, b"" for line in data.splitlines(): if line.startswith(b"RTSP/1.0"): _, code, msg = line.split(None, 2) elif b":" in line: h, v = line.split(b":", 1) h, v = smart_text(h), smart_text(v) if h in MULTIPLE_HEADER: if h not in headers: headers[h] = {} auth, line = v.split(None, 1) items = parse_http_list(line) headers[h][auth] = parse_keqv_list(items) continue headers[h] = v.strip() return int(code), headers, msg
def _parse_authorization_header(headers): """Parse an OAuth authorization header into a list of 2-tuples""" authorization_header = headers.get('Authorization') if not authorization_header: return [], None auth_scheme = 'oauth ' if authorization_header.lower().startswith(auth_scheme): items = parse_http_list(authorization_header[len(auth_scheme):]) try: items = parse_keqv_list(items).items() auth_params = [(unescape(k), unescape(v)) for k, v in items] realm = dict(auth_params).get('realm') return auth_params, realm except (IndexError, ValueError): pass raise ValueError('Malformed authorization header')
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: return if (auth_type == 'basic'): try: decoded = base64.b64decode(auth_info).decode( 'utf-8') # b64decode gives bytes in python3 (username, password) = decoded.split(':', 1) except (ValueError, TypeError): # py3, py2 return return {'type': 'basic', 'username': username, 'password': password} elif (auth_type == 'digest'): try: auth_map = parse_keqv_list(parse_http_list(auth_info)) except ValueError: return logging.debug(auth_map) for key in 'username', 'realm', 'nonce', 'uri', 'response': if key not in auth_map: return if 'qop' in auth_map and ('nc' not in auth_map or 'cnonce' not in auth_map): return auth_map['type'] = 'digest' return auth_map else: # unknown auth type return
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 = AbstractDigestAuthHandler() auth.add_password(realm, path, username, password) (token, challenge) = challenge.split(' ', 1) chal = parse_keqv_list(parse_http_list(challenge)) class FakeRequest(object): if six.PY3: @property def full_url(self): return path selector = full_url @property def data(self): return None else: def get_full_url(self): return path get_selector = get_full_url def has_data(self): return False def get_method(self): return method or "GET" retval = "Digest %s" % auth.get_authorization(FakeRequest(), chal) return (retval,)
def _parseDigestAuthorization(auth_params): # Convert the auth params to a dict items = parse_http_list(auth_params) params = parse_keqv_list(items) # Now validate the params # Check for required parameters required = ["username", "realm", "nonce", "uri", "response"] for k in required: if k not in params: return None # If qop is sent then cnonce and nc MUST be present if "qop" in params and not ("cnonce" in params and "nc" in params): return None # If qop is not sent, neither cnonce nor nc can be present if ("cnonce" in params or "nc" in params) and "qop" not in params: return None return params
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: decoded = base64.b64decode(auth_info).decode("utf-8") # b64decode gives bytes in python3 (username, password) = decoded.split(":", 1) except ValueError: # Exception as e: return return {"type": "basic", "username": username, "password": password} elif auth_type == "digest": auth_map = parse_keqv_list(parse_http_list(auth_info)) print(auth_map) for key in "username", "realm", "nonce", "uri", "response": if key not 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_dict_header(value): return parse_keqv_list(parse_http_list(value))
def get_components_from_bearer(header): _, _, value = header.partition("Bearer") opts = parse_keqv_list(parse_http_list(value)) if value else None return opts.get('realm', None), opts.get('service', None), opts.get('scope', None)
def process_request(self, req, resp): if self.debug: return # CORS Pre-flight if req.method == 'OPTIONS': resp.status = falcon.HTTP_204 return # http basic auth if self.config['server'].get('enable_basic_auth'): hdr_auth = req.get_header('AUTHORIZATION') if not hdr_auth: raise falcon.HTTPUnauthorized('Access denied', 'No auth header', []) auth = re.sub('^Basic ', '', hdr_auth) usr, pwd = decodestring(auth).split(':') if not equals(self.basic_auth.get(usr, ''), pwd): logger.warning('basic auth failure: %s', usr) raise falcon.HTTPUnauthorized('Access denied', 'Basic auth failure', []) segments = req.path.strip('/').split('/') if segments[0] == 'api': if len(segments) >= 3: # twilio validation if segments[2] == 'twilio': sig = req.get_header('X_TWILIO_SIGNATURE') if sig is None: logger.warning("no twilio signature found!") raise falcon.HTTPUnauthorized('Access denied', 'No Twilio signature', []) uri = [ req.protocol, '://', req.get_header('HOST'), self.config['server'].get('lb_routing_path', ''), req.path ] if req.query_string: uri.append('?') uri.append(req.query_string) post_body = req.context['body'] expected_sigs = [ compute_signature(t, ''.join(uri), post_body) for t in self.twilio_auth_token ] sig = sig.encode('utf8') if sig not in expected_sigs: logger.warning( 'twilio validation failure: %s not in possible sigs: %s', sig, expected_sigs) raise falcon.HTTPUnauthorized('Access denied', 'Twilio auth failure', []) return elif self.mobile and (segments[2] == 'mobile' or segments[2] == 'oncall'): # Only allow refresh tokens for /refresh, only access for all else table = 'refresh_token' if segments[ 3] == 'refresh' else 'access_token' key_query = '''SELECT `key`, `target`.`name` FROM `%s` JOIN `target` ON `user_id` = `target`.`id` WHERE `%s`.`id` = %%s AND `expiration` > %%s''' % (table, table) method = req.method auth = req.get_header('Authorization', required=True) items = urllib2.parse_http_list(auth) parts = urllib2.parse_keqv_list(items) if 'signature' not in parts or 'keyId' not in parts or 'timestamp' not in parts: raise falcon.HTTPUnauthorized( 'Authentication failure: invalid header') try: window = int(parts['timestamp']) time_diff = abs(time.time() - window) except ValueError: raise falcon.HTTPUnauthorized( 'Authentication failure: invalid header') client_digest = parts['signature'] key_id = parts['keyId'] body = req.context['body'].decode('utf8') path = req.env['PATH_INFO'] qs = req.env['QUERY_STRING'] if qs: path = path + '?' + qs text = '%s %s %s %s' % (window, method, path, body) text = text.encode('utf8') conn = db.connect() cursor = conn.cursor() cursor.execute(key_query, (key_id, time.time())) row = cursor.fetchone() conn.close() # make sure that there exists a row for the corresponding username if row is None: raise falcon.HTTPUnauthorized( 'Authentication failure: server') key = self.fernet.decrypt(str(row[0]).encode('utf8')) key = key req.context['user'] = row[1] HMAC = hmac.new(key, text, hashlib.sha512) digest = urlsafe_b64encode(HMAC.digest()) if hmac.compare_digest( client_digest.encode('utf8'), digest) and time_diff < self.time_window: return else: raise falcon.HTTPUnauthorized( 'Authentication failure: server') elif segments[2] == 'gmail' or segments[ 2] == 'gmail-oneclick' or segments[ 2] == 'slack' or segments[2] == 'ical': return elif len(segments) == 1: if segments[0] == 'health' or segments[0] == 'healthcheck': return elif segments[0] == self.config.get('gmail', {}).get('verification_code'): return elif segments[0] == 'saml': return raise falcon.HTTPUnauthorized('Access denied', 'Authentication failed', [])
def parse_dict_header(value): """ Parses a HTTP dict header value -- i.e. ``"foo=bar, spam=eggs"`` is parsed into ``{'foo': 'bar', 'spam': 'eggs'}``. """ return parse_keqv_list(parse_http_list(value))
def build_digest_response(self, fields, username, password): """ Takes a Proxy-Authenticate: Digest header and creates a response header :param fields: The string portion of the Proxy-Authenticate header after "Digest " :param username: The username to use for the response :param password: The password to use for the response :return: None if invalid Proxy-Authenticate header, otherwise the string of fields for the Proxy-Authorization: Digest header """ fields = parse_keqv_list(parse_http_list(fields)) realm = fields.get('realm') nonce = fields.get('nonce') qop = fields.get('qop') algorithm = fields.get('algorithm') if algorithm: algorithm = algorithm.lower() opaque = fields.get('opaque') if algorithm in ['md5', None]: def md5hash(string): return hashlib.md5(string).hexdigest() hash = md5hash elif algorithm == 'sha': def sha1hash(string): return hashlib.sha1(string).hexdigest() hash = sha1hash else: return None host_port = u"%s:%s" % (self.host, self.port) a1 = "%s:%s:%s" % (username, realm, password) a2 = "CONNECT:%s" % host_port ha1 = hash(a1) ha2 = hash(a2) if qop is None: response = hash(u"%s:%s:%s" % (ha1, nonce, ha2)) elif qop == 'auth': nc = '00000001' cnonce = hash(os.urandom(8))[:8] response = hash(u"%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)) else: return None response_fields = { 'username': username, 'realm': realm, 'nonce': nonce, 'response': response, 'uri': host_port } if algorithm: response_fields['algorithm'] = algorithm if qop == 'auth': response_fields['nc'] = nc response_fields['cnonce'] = cnonce response_fields['qop'] = qop if opaque: response_fields['opaque'] = opaque return ', '.join([ u"%s=\"%s\"" % (field, response_fields[field]) for field in response_fields ])
def build_digest_response(self, fields, username, password): """ Takes a Proxy-Authenticate: Digest header and creates a response header :param fields: The string portion of the Proxy-Authenticate header after "Digest " :param username: The username to use for the response :param password: The password to use for the response :return: None if invalid Proxy-Authenticate header, otherwise the string of fields for the Proxy-Authorization: Digest header """ fields = parse_keqv_list(parse_http_list(fields)) realm = fields.get('realm') nonce = fields.get('nonce') qop = fields.get('qop') algorithm = fields.get('algorithm') if algorithm: algorithm = algorithm.lower() opaque = fields.get('opaque') if algorithm in ['md5', None]: def md5hash(string): return hashlib.md5(string).hexdigest() hash = md5hash elif algorithm == 'sha': def sha1hash(string): return hashlib.sha1(string).hexdigest() hash = sha1hash else: return None host_port = u"%s:%s" % (self.host, self.port) a1 = "%s:%s:%s" % (username, realm, password) a2 = "CONNECT:%s" % host_port ha1 = hash(a1) ha2 = hash(a2) if qop == None: response = hash(u"%s:%s:%s" % (ha1, nonce, ha2)) elif qop == 'auth': nc = '00000001' cnonce = hash(os.urandom(8))[:8] response = hash(u"%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)) else: return None response_fields = { 'username': username, 'realm': realm, 'nonce': nonce, 'response': response, 'uri': host_port } if algorithm: response_fields['algorithm'] = algorithm if qop == 'auth': response_fields['nc'] = nc response_fields['cnonce'] = cnonce response_fields['qop'] = qop if opaque: response_fields['opaque'] = opaque return ', '.join([u"%s=\"%s\"" % (field, response_fields[field]) for field in response_fields])
def __eq__(self, authorization_header_value): auth_type, auth_value = authorization_header_value.split(maxsplit=1) assert auth_type.lower() == "digest" assert parse_keqv_list(parse_http_list(auth_value)) == self._parameters return True
def parse_keqv_list(l): """A unicode-safe version of urllib2.parse_keqv_list""" # With Python 2.6, parse_http_list handles unicode fine return urllib2.parse_keqv_list(l)