diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-11-09 16:46:51 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-11-09 16:46:51 (GMT) |
commit | 52a17becbcc8bba8d4750926c58f6ac6e41464b7 (patch) | |
tree | 3fe54eea69cba3a671c9d03d85d9ee179bc58b55 /Lib | |
parent | 6383c2d1a677f168ed2a4dfc9cb28f93ec327a0e (diff) | |
download | cpython-52a17becbcc8bba8d4750926c58f6ac6e41464b7.zip cpython-52a17becbcc8bba8d4750926c58f6ac6e41464b7.tar.gz cpython-52a17becbcc8bba8d4750926c58f6ac6e41464b7.tar.bz2 |
Fix SF bug 468948 & 451295: urllib2 authentication problems
Fix contributed by Jeffrey C. Ollie.
I haven't tested the fix because the situation is non-trivial to
reproduce.
The basic solution is to get rid of the __current_realm attribute of
authentication handlers. Instead, prevent infinite retries by
checking for the presence of an Authenticate: header in the request
object that exactly matches the Authenticate: header that would be
added.
The problem prevent authentication from working correctly in the
presence of retries.
Ollie mentioned that digest authentication has the same problem and I
applied the same solution there.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/urllib2.py | 40 |
1 files changed, 12 insertions, 28 deletions
diff --git a/Lib/urllib2.py b/Lib/urllib2.py index 3f01554..ffd73b8 100644 --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -578,11 +578,6 @@ class AbstractBasicAuthHandler: password_mgr = HTTPPasswordMgr() self.passwd = password_mgr self.add_password = self.passwd.add_password - self.__current_realm = None - # if __current_realm is not None, then the server must have - # refused our name/password and is asking for authorization - # again. must be careful to set it to None on successful - # return. def http_error_auth_reqed(self, authreq, host, req, headers): # XXX could be multiple headers @@ -595,26 +590,20 @@ class AbstractBasicAuthHandler: return self.retry_http_basic_auth(host, req, realm) def retry_http_basic_auth(self, host, req, realm): - if self.__current_realm is None: - self.__current_realm = realm - else: - self.__current_realm = realm - return None user,pw = self.passwd.find_user_password(realm, host) if pw: raw = "%s:%s" % (user, pw) - auth = base64.encodestring(raw).strip() - req.add_header(self.header, 'Basic %s' % auth) - resp = self.parent.open(req) - self.__current_realm = None - return resp + auth = 'Basic %s' % base64.encodestring(raw).strip() + if req.headers.get(self.auth_header, None) == auth: + return None + req.add_header(self.auth_header, auth) + return self.parent.open(req) else: - self.__current_realm = None return None class HTTPBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): - header = 'Authorization' + auth_header = 'Authorization' def http_error_401(self, req, fp, code, msg, headers): host = urlparse.urlparse(req.get_full_url())[1] @@ -624,7 +613,7 @@ class HTTPBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): - header = 'Proxy-Authorization' + auth_header = 'Proxy-Authorization' def http_error_407(self, req, fp, code, msg, headers): host = req.get_host() @@ -639,10 +628,9 @@ class AbstractDigestAuthHandler: passwd = HTTPPasswordMgr() self.passwd = passwd self.add_password = self.passwd.add_password - self.__current_realm = None def http_error_auth_reqed(self, authreq, host, req, headers): - authreq = headers.get(self.header, None) + authreq = headers.get(self.auth_header, None) if authreq: kind = authreq.split()[0] if kind == 'Digest': @@ -653,9 +641,11 @@ class AbstractDigestAuthHandler: chal = parse_keqv_list(parse_http_list(challenge)) auth = self.get_authorization(req, chal) if auth: - req.add_header(self.header, 'Digest %s' % auth) + auth_val = 'Digest %s' % auth + if req.headers.get(self.auth_header, None) == auth_val: + return None + req.add_header(self.auth_header, auth_val) resp = self.parent.open(req) - self.__current_realm = None return resp def get_authorization(self, req, chal): @@ -669,12 +659,6 @@ class AbstractDigestAuthHandler: except KeyError: return None - if self.__current_realm is None: - self.__current_realm = realm - else: - self.__current_realm = realm - return None - H, KD = self.get_algorithm_impls(algorithm) if H is None: return None |