Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-128192: support HTTP sha-256 digest authentication as per RFC-7617 #128193

Merged
merged 15 commits into from
Dec 28, 2024
Merged
3 changes: 3 additions & 0 deletions Doc/library/urllib.request.rst
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ The following classes are provided:
:ref:`http-password-mgr` for information on the interface that must be
supported.

.. versionchanged:: 3.14
Added support for HTTP digest authentication algorithm ``SHA-256``.


.. class:: HTTPDigestAuthHandler(password_mgr=None)

Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,14 @@ unittest
(Contributed by Jacob Walls in :gh:`80958`.)


urllib
------

* Upgrade HTTP digest authentication algorithm for :mod:`urllib.request` by
supporting SHA-256 digest authentication as specified in :rfc:`7616`.
(Contributed by Calvin Bui in :gh:`128193`.)


uuid
----

Expand Down
25 changes: 22 additions & 3 deletions Lib/test/test_urllib2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1962,10 +1962,29 @@ def test_parse_proxy(self):

self.assertRaises(ValueError, _parse_proxy, 'file:/ftp.example.com'),

def test_unsupported_algorithm(self):
handler = AbstractDigestAuthHandler()

class TestDigestAlgorithms(unittest.TestCase):
calvinbui marked this conversation as resolved.
Show resolved Hide resolved
def setUp(self):
self.handler = AbstractDigestAuthHandler()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow-up PR (or this one), if you want/can, we can add tests for a full communication round where we request HTTP digest authentication.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, next time!


def test_md5_algorithm(self):
H, KD = self.handler.get_algorithm_impls('MD5')
self.assertEqual(H("foo"), "acbd18db4cc2f85cedef654fccc4a4d8")
self.assertEqual(KD("foo", "bar"), "4e99e8c12de7e01535248d2bac85e732")

def test_sha_algorithm(self):
H, KD = self.handler.get_algorithm_impls('SHA')
self.assertEqual(H("foo"), "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
self.assertEqual(KD("foo", "bar"), "54dcbe67d21d5eb39493d46d89ae1f412d3bd6de")

def test_sha256_algorithm(self):
H, KD = self.handler.get_algorithm_impls('SHA-256')
self.assertEqual(H("foo"), "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
self.assertEqual(KD("foo", "bar"), "a765a8beaa9d561d4c5cbed29d8f4e30870297fdfa9cb7d6e9848a95fec9f937")

def test_invalid_algorithm(self):
with self.assertRaises(ValueError) as exc:
handler.get_algorithm_impls('invalid')
self.handler.get_algorithm_impls('invalid')
self.assertEqual(
str(exc.exception),
"Unsupported digest authentication algorithm 'invalid'"
Expand Down
7 changes: 5 additions & 2 deletions Lib/urllib/request.py
calvinbui marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ def http_error_407(self, req, fp, code, msg, headers):


class AbstractDigestAuthHandler:
# Digest authentication is specified in RFC 2617.
# Digest authentication is specified in RFC 2617/7616.

# XXX The client does not inspect the Authentication-Info header
# in a successful response.
Expand Down Expand Up @@ -1176,11 +1176,14 @@ def get_authorization(self, req, chal):
return base

def get_algorithm_impls(self, algorithm):
# algorithm names taken from RFC 7616 Section 6.1
# lambdas assume digest modules are imported at the top level
if algorithm == 'MD5':
H = lambda x: hashlib.md5(x.encode("ascii")).hexdigest()
elif algorithm == 'SHA':
elif algorithm == 'SHA': # non-standard, retained for compatibility.
H = lambda x: hashlib.sha1(x.encode("ascii")).hexdigest()
elif algorithm == 'SHA-256':
calvinbui marked this conversation as resolved.
Show resolved Hide resolved
H = lambda x: hashlib.sha256(x.encode("ascii")).hexdigest()
# XXX MD5-sess
else:
raise ValueError("Unsupported digest authentication "
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ Colm Buckley
Erik de Bueger
Jan-Hein Bührman
Marc Bürg
Calvin Bui
Lars Buitinck
Artem Bulgakov
Dick Bulterman
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Upgrade HTTP digest authentication algorithm for :mod:`urllib.request` by
supporting SHA-256 digest authentication as specified in :rfc:`7616`.
Loading