diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2014-11-12 13:33:50 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2014-11-12 13:33:50 (GMT) |
commit | c216c4869921cb9ade491704f945d6f1401ccbcc (patch) | |
tree | 4f72aacd2ea44a4a9fba3312d62873f7ff611602 /Lib | |
parent | ab14088141ab749763e35b7a49e79c368940e12d (diff) | |
download | cpython-c216c4869921cb9ade491704f945d6f1401ccbcc.zip cpython-c216c4869921cb9ade491704f945d6f1401ccbcc.tar.gz cpython-c216c4869921cb9ade491704f945d6f1401ccbcc.tar.bz2 |
Close #19494: add urrlib.request.HTTPBasicPriorAuthHandler
This auth handler adds the Authorization header to the first
HTTP request rather than waiting for a HTTP 401 Unauthorized
response from the server as the default HTTPBasicAuthHandler
does.
This allows working with websites like https://api.github.com which do
not follow the strict interpretation of RFC, but more the dicta in the
end of section 2 of RFC 2617:
> A client MAY preemptively send the corresponding Authorization
> header with requests for resources in that space without receipt
> of another challenge from the server. Similarly, when a client
> sends a request to a proxy, it may reuse a userid and password in
> the Proxy-Authorization header field without receiving another
> challenge from the proxy server. See section 4 for security
> considerations associated with Basic authentication.
Patch by Matej Cepl.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_urllib2.py | 15 | ||||
-rw-r--r-- | Lib/urllib/request.py | 15 |
2 files changed, 30 insertions, 0 deletions
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 9ea39a4..823890e 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1422,6 +1422,21 @@ class HandlerTests(unittest.TestCase): handler.do_open(conn, req) self.assertTrue(conn.fakesock.closed, "Connection not closed") + def test_auth_prior_handler(self): + pwd_manager = MockPasswordManager() + pwd_manager.add_password(None, 'https://example.com', + 'somebody', 'verysecret') + auth_prior_handler = urllib.request.HTTPBasicPriorAuthHandler( + pwd_manager) + http_hand = MockHTTPSHandler() + + opener = OpenerDirector() + opener.add_handler(http_hand) + opener.add_handler(auth_prior_handler) + + req = Request("https://example.com") + opener.open(req) + self.assertNotIn('Authorization', http_hand.httpconn.req_headers) class MiscTests(unittest.TestCase): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index e0c8116..36ae1ef 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -916,6 +916,21 @@ class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): return response +class HTTPBasicPriorAuthHandler(HTTPBasicAuthHandler): + handler_order = 400 + + def http_request(self, req): + if not req.has_header('Authorization'): + user, passwd = self.passwd.find_user_password(None, req.host) + credentials = '{0}:{1}'.format(user, passwd).encode() + auth_str = base64.standard_b64encode(credentials).decode() + req.add_unredirected_header('Authorization', + 'Basic {}'.format(auth_str.strip())) + return req + + https_request = http_request + + # Return n random bytes. _randombytes = os.urandom |