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'))
Exemple #2
0
 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'))
Exemple #4
0
 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
Exemple #5
0
 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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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