Пример #1
0
    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
Пример #2
0
    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)
Пример #3
0
    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
Пример #4
0
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))
Пример #5
0
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,
        )
Пример #6
0
 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)
Пример #7
0
 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)
Пример #8
0
 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,)
Пример #9
0
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
Пример #10
0
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)
Пример #12
0
 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
Пример #13
0
 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"
Пример #14
0
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
Пример #15
0
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
Пример #16
0
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
Пример #17
0
 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"
Пример #18
0
 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__'] = {}
Пример #19
0
 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__'] = {}
Пример #20
0
 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
Пример #21
0
 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)
Пример #22
0
 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
Пример #23
0
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')
Пример #24
0
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
Пример #25
0
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
Пример #26
0
 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)
Пример #27
0
    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"
                    ))
Пример #28
0
    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)
Пример #29
0
    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
Пример #30
0
    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
Пример #31
0
 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)
Пример #32
0
    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
Пример #33
0
    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
Пример #34
0
 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 _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"])
Пример #36
0
    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
Пример #37
0
    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
Пример #38
0
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
Пример #39
0
    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
Пример #40
0
 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)
Пример #41
0
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
Пример #42
0
 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)
Пример #43
0
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
Пример #44
0
    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"))
Пример #45
0
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
Пример #46
0
    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)
Пример #48
0
	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
Пример #49
0
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
Пример #50
0
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
Пример #51
0
 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
Пример #52
0
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
Пример #53
0
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
Пример #54
0
	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
Пример #55
0
 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