mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									ab14088141
								
							
						
					
					
						commit
						c216c48699
					
				
					 5 changed files with 53 additions and 0 deletions
				
			
		| 
						 | 
					@ -304,6 +304,17 @@ The following classes are provided:
 | 
				
			||||||
   presented with a wrong Authentication scheme.
 | 
					   presented with a wrong Authentication scheme.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. class:: HTTPBasicPriorAuthHandler(password_mgr=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   A variant of :class:`HTTPBasicAuthHandler` which automatically sends
 | 
				
			||||||
 | 
					   authorization credentials with the first request, rather than waiting to
 | 
				
			||||||
 | 
					   first receive a HTTP 401 "Unauthorised" error response. This allows
 | 
				
			||||||
 | 
					   authentication to sites that don't provide a 401 response when receiving
 | 
				
			||||||
 | 
					   a request without an Authorization header. Aside from this difference,
 | 
				
			||||||
 | 
					   this behaves exactly as :class:`HTTPBasicAuthHandler`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .. versionadded:: 3.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. class:: ProxyBasicAuthHandler(password_mgr=None)
 | 
					.. class:: ProxyBasicAuthHandler(password_mgr=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Handle authentication with the proxy. *password_mgr*, if given, should be
 | 
					   Handle authentication with the proxy. *password_mgr*, if given, should be
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -297,6 +297,15 @@ time
 | 
				
			||||||
* The :func:`time.monotonic` function is now always available.  (Contributed by
 | 
					* The :func:`time.monotonic` function is now always available.  (Contributed by
 | 
				
			||||||
  Victor Stinner in :issue:`22043`.)
 | 
					  Victor Stinner in :issue:`22043`.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					time
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* A new :class:`urllib.request.HTTPBasicPriorAuthHandler` allows HTTP Basic
 | 
				
			||||||
 | 
					  Authentication credentials to be sent unconditionally with the first HTTP
 | 
				
			||||||
 | 
					  request, rather than waiting for a HTTP 401 Unauthorized response from the
 | 
				
			||||||
 | 
					  server.
 | 
				
			||||||
 | 
					  (Contributed by Matej Cepl in :issue:`19494`.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wsgiref
 | 
					wsgiref
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1422,6 +1422,21 @@ def test_invalid_closed(self):
 | 
				
			||||||
            handler.do_open(conn, req)
 | 
					            handler.do_open(conn, req)
 | 
				
			||||||
        self.assertTrue(conn.fakesock.closed, "Connection not closed")
 | 
					        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):
 | 
					class MiscTests(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -916,6 +916,21 @@ def http_error_407(self, req, fp, code, msg, headers):
 | 
				
			||||||
        return response
 | 
					        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.
 | 
					# Return n random bytes.
 | 
				
			||||||
_randombytes = os.urandom
 | 
					_randombytes = os.urandom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,6 +183,9 @@ Core and Builtins
 | 
				
			||||||
Library
 | 
					Library
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #19494: Added urllib.request.HTTPBasicPriorAuthHandler. Patch by
 | 
				
			||||||
 | 
					  Matej Cepl.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #22578: Added attributes to the re.error class.
 | 
					- Issue #22578: Added attributes to the re.error class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #12728: Different Unicode characters having the same uppercase but
 | 
					- Issue #12728: Different Unicode characters having the same uppercase but
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue