mirror of https://github.com/python/cpython
Fix closes Issue #11799: urllib.request Authentication Handlers will raise a
ValueError when presented with an unsupported Authentication Scheme.
This commit is contained in:
parent
cc99528d87
commit
4de00a2e87
|
@ -240,10 +240,11 @@ The following classes are provided:
|
||||||
|
|
||||||
.. class:: HTTPBasicAuthHandler(password_mgr=None)
|
.. class:: HTTPBasicAuthHandler(password_mgr=None)
|
||||||
|
|
||||||
Handle authentication with the remote host. *password_mgr*, if given, should be
|
Handle authentication with the remote host. *password_mgr*, if given, should
|
||||||
something that is compatible with :class:`HTTPPasswordMgr`; refer to section
|
be something that is compatible with :class:`HTTPPasswordMgr`; refer to
|
||||||
:ref:`http-password-mgr` for information on the interface that must be
|
section :ref:`http-password-mgr` for information on the interface that must
|
||||||
supported.
|
be supported. HTTPBasicAuthHandler will raise a :exc:`ValueError` when
|
||||||
|
presented with a wrong Authentication scheme.
|
||||||
|
|
||||||
|
|
||||||
.. class:: ProxyBasicAuthHandler(password_mgr=None)
|
.. class:: ProxyBasicAuthHandler(password_mgr=None)
|
||||||
|
@ -265,10 +266,19 @@ The following classes are provided:
|
||||||
|
|
||||||
.. class:: HTTPDigestAuthHandler(password_mgr=None)
|
.. class:: HTTPDigestAuthHandler(password_mgr=None)
|
||||||
|
|
||||||
Handle authentication with the remote host. *password_mgr*, if given, should be
|
Handle authentication with the remote host. *password_mgr*, if given, should
|
||||||
something that is compatible with :class:`HTTPPasswordMgr`; refer to section
|
be something that is compatible with :class:`HTTPPasswordMgr`; refer to
|
||||||
:ref:`http-password-mgr` for information on the interface that must be
|
section :ref:`http-password-mgr` for information on the interface that must
|
||||||
supported.
|
be supported. When both Digest Authentication Handler and Basic
|
||||||
|
Authentication Handler are both added, Digest Authentication is always tried
|
||||||
|
first. If the Digest Authentication returns a 40x response again, it is sent
|
||||||
|
to Basic Authentication handler to Handle. This Handler method will raise a
|
||||||
|
:exc:`ValueError` when presented with an authentication scheme other than
|
||||||
|
Digest or Basic.
|
||||||
|
|
||||||
|
..versionchanged:: 3.3
|
||||||
|
Raise ValueError on unsupported Authentication Scheme.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. class:: ProxyDigestAuthHandler(password_mgr=None)
|
.. class:: ProxyDigestAuthHandler(password_mgr=None)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import os
|
||||||
import io
|
import io
|
||||||
import socket
|
import socket
|
||||||
import array
|
import array
|
||||||
|
import sys
|
||||||
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
# The proxy bypass method imported below has logic specific to the OSX
|
# The proxy bypass method imported below has logic specific to the OSX
|
||||||
|
@ -1162,6 +1163,8 @@ class HandlerTests(unittest.TestCase):
|
||||||
self.assertEqual(req.get_host(), "proxy.example.com:3128")
|
self.assertEqual(req.get_host(), "proxy.example.com:3128")
|
||||||
self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
|
self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
|
||||||
|
|
||||||
|
# TODO: This should be only for OSX
|
||||||
|
@unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
|
||||||
def test_osx_proxy_bypass(self):
|
def test_osx_proxy_bypass(self):
|
||||||
bypass = {
|
bypass = {
|
||||||
'exclude_simple': False,
|
'exclude_simple': False,
|
||||||
|
@ -1265,6 +1268,26 @@ class HandlerTests(unittest.TestCase):
|
||||||
# _test_basic_auth called .open() twice)
|
# _test_basic_auth called .open() twice)
|
||||||
self.assertEqual(opener.recorded, ["digest", "basic"]*2)
|
self.assertEqual(opener.recorded, ["digest", "basic"]*2)
|
||||||
|
|
||||||
|
def test_unsupported_auth_digest_handler(self):
|
||||||
|
opener = OpenerDirector()
|
||||||
|
# While using DigestAuthHandler
|
||||||
|
digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
|
||||||
|
http_handler = MockHTTPHandler(
|
||||||
|
401, 'WWW-Authenticate: Kerberos\r\n\r\n')
|
||||||
|
opener.add_handler(digest_auth_handler)
|
||||||
|
opener.add_handler(http_handler)
|
||||||
|
self.assertRaises(ValueError,opener.open,"http://www.example.com")
|
||||||
|
|
||||||
|
def test_unsupported_auth_basic_handler(self):
|
||||||
|
# While using BasicAuthHandler
|
||||||
|
opener = OpenerDirector()
|
||||||
|
basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
|
||||||
|
http_handler = MockHTTPHandler(
|
||||||
|
401, 'WWW-Authenticate: NTLM\r\n\r\n')
|
||||||
|
opener.add_handler(basic_auth_handler)
|
||||||
|
opener.add_handler(http_handler)
|
||||||
|
self.assertRaises(ValueError,opener.open,"http://www.example.com")
|
||||||
|
|
||||||
def _test_basic_auth(self, opener, auth_handler, auth_header,
|
def _test_basic_auth(self, opener, auth_handler, auth_header,
|
||||||
realm, http_handler, password_manager,
|
realm, http_handler, password_manager,
|
||||||
request_url, protected_url):
|
request_url, protected_url):
|
||||||
|
@ -1302,6 +1325,7 @@ class HandlerTests(unittest.TestCase):
|
||||||
self.assertEqual(len(http_handler.requests), 1)
|
self.assertEqual(len(http_handler.requests), 1)
|
||||||
self.assertFalse(http_handler.requests[0].has_header(auth_header))
|
self.assertFalse(http_handler.requests[0].has_header(auth_header))
|
||||||
|
|
||||||
|
|
||||||
class MiscTests(unittest.TestCase):
|
class MiscTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_build_opener(self):
|
def test_build_opener(self):
|
||||||
|
|
|
@ -825,14 +825,20 @@ class AbstractBasicAuthHandler:
|
||||||
self.retried += 1
|
self.retried += 1
|
||||||
|
|
||||||
if authreq:
|
if authreq:
|
||||||
mo = AbstractBasicAuthHandler.rx.search(authreq)
|
scheme = authreq.split()[0]
|
||||||
if mo:
|
if not scheme.lower() == 'basic':
|
||||||
scheme, quote, realm = mo.groups()
|
raise ValueError("AbstractBasicAuthHandler does not"
|
||||||
if scheme.lower() == 'basic':
|
" support the following scheme: '%s'" %
|
||||||
response = self.retry_http_basic_auth(host, req, realm)
|
scheme)
|
||||||
if response and response.code != 401:
|
else:
|
||||||
self.retried = 0
|
mo = AbstractBasicAuthHandler.rx.search(authreq)
|
||||||
return response
|
if mo:
|
||||||
|
scheme, quote, realm = mo.groups()
|
||||||
|
if scheme.lower() == 'basic':
|
||||||
|
response = self.retry_http_basic_auth(host, req, realm)
|
||||||
|
if response and response.code != 401:
|
||||||
|
self.retried = 0
|
||||||
|
return response
|
||||||
|
|
||||||
def retry_http_basic_auth(self, host, req, realm):
|
def retry_http_basic_auth(self, host, req, realm):
|
||||||
user, pw = self.passwd.find_user_password(realm, host)
|
user, pw = self.passwd.find_user_password(realm, host)
|
||||||
|
@ -918,6 +924,9 @@ class AbstractDigestAuthHandler:
|
||||||
scheme = authreq.split()[0]
|
scheme = authreq.split()[0]
|
||||||
if scheme.lower() == 'digest':
|
if scheme.lower() == 'digest':
|
||||||
return self.retry_http_digest_auth(req, authreq)
|
return self.retry_http_digest_auth(req, authreq)
|
||||||
|
elif not scheme.lower() == 'basic':
|
||||||
|
raise ValueError("AbstractDigestAuthHandler does not support"
|
||||||
|
" the following scheme: '%s'" % scheme)
|
||||||
|
|
||||||
def retry_http_digest_auth(self, req, auth):
|
def retry_http_digest_auth(self, req, auth):
|
||||||
token, challenge = auth.split(' ', 1)
|
token, challenge = auth.split(' ', 1)
|
||||||
|
|
|
@ -143,6 +143,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #11799: urllib.request Authentication Handlers will raise a ValueError
|
||||||
|
when presented with an unsupported Authentication Scheme. Patch contributed
|
||||||
|
by Yuval Greenfield.
|
||||||
|
|
||||||
- Issue #10419, #6011: build_scripts command of distutils handles correctly
|
- Issue #10419, #6011: build_scripts command of distutils handles correctly
|
||||||
non-ASCII path (path to the Python executable). Open and write the script in
|
non-ASCII path (path to the Python executable). Open and write the script in
|
||||||
binary mode, but ensure that the shebang is decodable from UTF-8 and from the
|
binary mode, but ensure that the shebang is decodable from UTF-8 and from the
|
||||||
|
|
Loading…
Reference in New Issue