https://github.com/python/cpython/commit/270a30ab307d03ece8f93722eb402ce92883ac37 commit: 270a30ab307d03ece8f93722eb402ce92883ac37 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: orsenthil <[email protected]> date: 2026-10-29T13:30:35-07:00 summary:
[3.14] gh-53852 Proxy Auth failure to raise 407 instead of 401 (GH-160917) (#160920) gh-53852 Proxy Auth failure to raise 407 instead of 401 (GH-160917) Proxy Auth failure to raise 407 instead of 401 https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/407 is the correct status code to raise for the Proxy Authentication. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401 is the generic code that can be raised for unauthorized response. (cherry picked from commit 2e1666f1f24c128a9a85bd39680c59aee90f2275) Co-authored-by: Senthil Kumaran <[email protected]> files: A Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst M Lib/test/test_urllib2.py M Lib/test/test_urllib2_localnet.py M Lib/urllib/request.py diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 16123842235a15..80a56759d61e18 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1854,6 +1854,25 @@ 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_failure_code(self): + # gh-53852: a failed proxy digest auth must report 407, not 401. + headers = http.client.HTTPMessage() + for handler_class, auth_header, code in [ + (urllib.request.HTTPDigestAuthHandler, + 'www-authenticate', 401), + (urllib.request.ProxyDigestAuthHandler, + 'proxy-authenticate', 407)]: + with self.subTest(handler=handler_class.__name__): + handler = handler_class() + handler.retried = 6 + req = Request("http://www.example.com/") + with self.assertRaises(urllib.error.HTTPError) as cm: + handler.http_error_auth_reqed(auth_header, + "www.example.com", + req, headers) + self.assertEqual(cm.exception.code, code) + cm.exception.close() + def test_unsupported_auth_basic_handler(self): # While using BasicAuthHandler opener = OpenerDirector() diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py index c2646b9448f297..8f93ee74252f5c 100644 --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -368,12 +368,14 @@ def test_proxy_with_bad_password_raises_httperror(self): self.digest_auth_handler.set_qop("auth") with self.assertRaises(urllib.error.HTTPError) as cm: self.opener.open(self.URL) + self.assertEqual(cm.exception.code, 407) cm.exception.close() def test_proxy_with_no_password_raises_httperror(self): self.digest_auth_handler.set_qop("auth") with self.assertRaises(urllib.error.HTTPError) as cm: self.opener.open(self.URL) + self.assertEqual(cm.exception.code, 407) cm.exception.close() def test_proxy_qop_auth_works(self): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index e44691a169275a..ebbb4010abdf06 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1091,7 +1091,11 @@ def http_error_auth_reqed(self, auth_header, host, req, headers): # prompting for the information. Crap. This isn't great # but it's better than the current 'repeat until recursion # depth exceeded' approach <wink> - raise HTTPError(req.full_url, 401, "digest auth failed", + if auth_header.lower() == 'proxy-authenticate': + code = 407 + else: + code = 401 + raise HTTPError(req.full_url, code, "digest auth failed", headers, None) else: self.retried += 1 diff --git a/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst b/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst new file mode 100644 index 00000000000000..6b6c7fa1e17513 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-28-12-00-00.gh-issue-53852.Pr0xy4.rst @@ -0,0 +1,3 @@ +:class:`urllib.request.ProxyDigestAuthHandler` now raises +:exc:`~urllib.error.HTTPError` with status code 407 (Proxy Authentication +Required) instead of 401 when proxy authentication fails. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
