From 1ea85dffd8eac04cd6eca38c56329e17b64ab3fe Mon Sep 17 00:00:00 2001 From: karosis88 Date: Fri, 26 May 2023 09:08:15 +0300 Subject: [PATCH] Revert "Merge branch 'master' into master" This reverts commit 073df47b07f25afed119c3a89acca147cc51d735, reversing changes made to 733595037ac26d272f74ee6d702150b017913d11. --- httpx/_auth.py | 22 +++++----------------- tests/client/test_auth.py | 11 +++++++++++ tests/test_auth.py | 26 -------------------------- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/httpx/_auth.py b/httpx/_auth.py index 26378c9ba0..1d7385d573 100644 --- a/httpx/_auth.py +++ b/httpx/_auth.py @@ -171,8 +171,6 @@ def _build_auth_header( class DigestAuth(Auth): - requires_response_body = True - _ALGORITHM_TO_HASH_FUNCTION: typing.Dict[str, typing.Callable[[bytes], "_Hash"]] = { "MD5": hashlib.md5, "MD5-SESS": hashlib.md5, @@ -230,7 +228,6 @@ def _parse_challenge( `Digest realm="realm@host.com",qop="auth,auth-int",nonce="abc",opaque="xyz"` """ scheme, _, fields = auth_header.partition(" ") - entity = response.content # This method should only ever have been called with a Digest auth header. assert scheme.lower() == "digest" @@ -247,12 +244,7 @@ def _parse_challenge( opaque = header_dict["opaque"].encode() if "opaque" in header_dict else None qop = header_dict["qop"].encode() if "qop" in header_dict else None return _DigestAuthChallenge( - realm=realm, - nonce=nonce, - algorithm=algorithm, - opaque=opaque, - qop=qop, - entity=entity, + realm=realm, nonce=nonce, algorithm=algorithm, opaque=opaque, qop=qop ) except KeyError as exc: message = "Malformed Digest WWW-Authenticate header" @@ -262,8 +254,6 @@ def _build_auth_header( self, request: Request, challenge: "_DigestAuthChallenge" ) -> str: hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()] - qop = self._resolve_qop(challenge.qop, request=request) - entity = challenge.entity def digest(data: bytes) -> bytes: return hash_func(data).hexdigest().encode() @@ -272,9 +262,7 @@ def digest(data: bytes) -> bytes: path = request.url.raw_path A2 = b":".join((request.method.encode(), path)) - if qop == b"auth-int": - A2 = b":".join((A2, digest(entity))) - + # TODO: implement auth-int HA2 = digest(A2) nc_value = b"%08x" % self._nonce_count @@ -285,6 +273,7 @@ def digest(data: bytes) -> bytes: if challenge.algorithm.lower().endswith("-sess"): HA1 = digest(b":".join((HA1, challenge.nonce, cnonce))) + qop = self._resolve_qop(challenge.qop, request=request) if qop is None: digest_data = [HA1, challenge.nonce, HA2] else: @@ -302,7 +291,7 @@ def digest(data: bytes) -> bytes: if challenge.opaque: format_args["opaque"] = challenge.opaque if qop: - format_args["qop"] = qop + format_args["qop"] = b"auth" format_args["nc"] = nc_value format_args["cnonce"] = cnonce @@ -344,7 +333,7 @@ def _resolve_qop( return b"auth" if qops == [b"auth-int"]: - return b"auth-int" + raise NotImplementedError("Digest auth-int support is not yet implemented") message = f'Unexpected qop value "{qop!r}" in digest auth' raise ProtocolError(message, request=request) @@ -356,4 +345,3 @@ class _DigestAuthChallenge(typing.NamedTuple): algorithm: str opaque: typing.Optional[bytes] qop: typing.Optional[bytes] - entity: bytes diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index 0f49b814c2..fee515058b 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -523,6 +523,17 @@ async def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str) assert len(response.history) == 1 +@pytest.mark.anyio +async def test_digest_auth_qop_auth_int_not_implemented() -> None: + url = "https://example.org/" + auth = httpx.DigestAuth(username="user", password="password123") + app = DigestApp(qop="auth-int") + + async with httpx.AsyncClient(transport=httpx.MockTransport(app)) as client: + with pytest.raises(NotImplementedError): + await client.get(url, auth=auth) + + @pytest.mark.anyio async def test_digest_auth_qop_must_be_auth_or_auth_int() -> None: url = "https://example.org/" diff --git a/tests/test_auth.py b/tests/test_auth.py index ea12493bda..a1997c2fe2 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -101,29 +101,3 @@ def test_digest_auth_with_401_nonce_counting(): response = httpx.Response(content=b"Hello, world!", status_code=200) with pytest.raises(StopIteration): flow.send(response) - - -def test_digest_auth_with_401_auth_int(): - auth = httpx.DigestAuth(username="user", password="pass") - request = httpx.Request("GET", "https://www.example.com") - - # The initial request should not include an auth header. - flow = auth.sync_auth_flow(request) - request = next(flow) - assert "Authorization" not in request.headers - - # If a 401 response is returned, then a digest auth request is made. - headers = { - "WWW-Authenticate": 'Digest realm="...", qop="auth-int", nonce="...", opaque="..."' - } - response = httpx.Response( - content=b"Auth required", status_code=401, headers=headers - ) - request = flow.send(response) - assert request.headers["Authorization"].startswith("Digest") - assert "qop=auth-int" in request.headers["Authorization"] - - # No other requests are made. - response = httpx.Response(content=b"Hello, world!", status_code=200) - with pytest.raises(StopIteration): - flow.send(response)