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 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 __init__( self, auth_header, http_method, debug=False, accept_charset=DEFAULT_CHARSET[:], ): 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) paramsd = {k: unquote_to_bytes(v) for k, v in paramsd.items()} paramsd = _try_decode_map_values(paramsd, accept_charset) 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 parse_rtsp_header(data): code, msg, headers = 200, "", {} for line in data.splitlines(): if line.startswith("RTSP/1.0"): _, code, msg = line.split(None, 2) elif ":" in line: h, v = line.split(":", 1) 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), msg, headers
def process_request(self, url, body, headers): if not headers: headers = {} # First query - 401 code, resp_headers, result = fetch_sync( url, headers=None, request_timeout=60, follow_redirects=True, allow_proxy=False, validate_cert=False, ) 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) return url, body, headers
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 extract_oauth_error(www_authenticate_header): # Exchange fact #234265 - when using Office365 with an expired access token, # Exchange will simply raise a 401 error and return an HTML error page. However, # if you dig into the `WWW-Authenticate` header, you'll see something like this: # `'Bearer client_id="*", trusted_issuers="*", token_types="app_asserted_user_v1 service_asserted_app_v1", # authorization_uri="https://login.windows.net/common/oauth2/authorize", error="invalid_token"` # This function extracts this error field. if www_authenticate_header.startswith('Bearer') is False: return None _, _, value = www_authenticate_header.partition('Bearer') items = parse_http_list(value) # Sometime Exchange returns elements which aren't key-values, # e.g: `Bearer Realm="",Negotiate,Basic Realm=""` filtered_items = [item for item in items if '=' in item] filtered_options = parse_keqv_list(filtered_items) if 'error' in filtered_options: return filtered_options['error'] return None