Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Lib/test/test_urllib2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1722,6 +1722,31 @@ def test_unsupported_auth_digest_handler(self):
opener.add_handler(http_handler)
self.assertRaises(ValueError, opener.open, "http://www.example.com")

def test_digest_auth_malformed_challenge(self):
# A malformed WWW-Authenticate digest challenge must make the handler
# decline (return None) rather than crash with a raw exception.
handler = urllib.request.HTTPDigestAuthHandler(None)
req = Request("http://www.example.com/")
for challenge in (
"Digest realm", # parse_keqv_list: no '=' -> ValueError
"Digest realm=", # parse_keqv_list: empty value -> IndexError
"Digest", # auth.split(' ', 1) -> ValueError
):
with self.subTest(challenge=challenge):
self.assertIsNone(handler.retry_http_digest_auth(req, challenge))

# Through the public opener.open() path the raw exception must not
# escape; the unhandled 401 surfaces as HTTPError instead.
opener = OpenerDirector()
opener.add_handler(urllib.request.HTTPDigestAuthHandler(None))
opener.add_handler(urllib.request.HTTPDefaultErrorHandler())
opener.add_handler(MockHTTPHandlerRedirect(
401, "WWW-Authenticate: Digest realm\r\n\r\n"))
with self.assertRaises(urllib.error.HTTPError) as cm:
opener.open("http://www.example.com/")
self.assertEqual(cm.exception.code, 401)
cm.exception.close()

def test_unsupported_auth_basic_handler(self):
# While using BasicAuthHandler
opener = OpenerDirector()
Expand Down
8 changes: 6 additions & 2 deletions Lib/urllib/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,8 +1093,12 @@ def http_error_auth_reqed(self, auth_header, host, req, headers):
" the following scheme: '%s'" % scheme)

def retry_http_digest_auth(self, req, auth):
token, challenge = auth.split(' ', 1)
chal = parse_keqv_list(filter(None, parse_http_list(challenge)))
try:
token, challenge = auth.split(' ', 1)
chal = parse_keqv_list(filter(None, parse_http_list(challenge)))
except (ValueError, IndexError):
# A malformed challenge cannot be used to authenticate.
return None
auth = self.get_authorization(req, chal)
if auth:
auth_val = 'Digest %s' % auth
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :class:`urllib.request.HTTPDigestAuthHandler` raising :exc:`ValueError` or
:exc:`IndexError` for a malformed ``WWW-Authenticate`` digest challenge. Patch
by tonghuaroot.
Loading