Skip to content

Commit

Permalink
Revert "Merge branch 'master' into master"
Browse files Browse the repository at this point in the history
This reverts commit 073df47, reversing
changes made to 7335950.
  • Loading branch information
karpetrosyan committed May 26, 2023
1 parent 073df47 commit 1ea85df
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 43 deletions.
22 changes: 5 additions & 17 deletions httpx/_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -356,4 +345,3 @@ class _DigestAuthChallenge(typing.NamedTuple):
algorithm: str
opaque: typing.Optional[bytes]
qop: typing.Optional[bytes]
entity: bytes
11 changes: 11 additions & 0 deletions tests/client/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
Expand Down
26 changes: 0 additions & 26 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 1ea85df

Please sign in to comment.