Skip to content

Commit 560ada0

Browse files
committed
fix: Restore original "auth" DigestAuth test cases with corrections to
match RFC-7616 example more closely, adding dedicated unit tests for "auth-int" scenarios
1 parent 3d75c91 commit 560ada0

1 file changed

Lines changed: 122 additions & 8 deletions

File tree

tests/test_auth.py

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
208208
headers = {
209209
"WWW-Authenticate": (
210210
'Digest realm="http-auth@example.org", '
211-
'qop="auth, auth-int", '
211+
"qop=auth, "
212212
"algorithm=MD5, "
213213
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", '
214214
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
@@ -232,14 +232,13 @@ def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
232232
'cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"'
233233
in request.headers["Authorization"]
234234
)
235-
assert "qop=auth" in request.headers["Authorization"]
235+
assert "qop=auth," in request.headers["Authorization"]
236236
assert (
237237
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
238238
in request.headers["Authorization"]
239239
)
240240
assert (
241-
# 'response="8ca523f5e9506fed4657c9700eebdbec"'
242-
'response="7d2b5599cc59f94b525f726e44474803"'
241+
'response="8ca523f5e9506fed4657c9700eebdbec"'
243242
in request.headers["Authorization"]
244243
)
245244

@@ -269,7 +268,7 @@ def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
269268
headers = {
270269
"WWW-Authenticate": (
271270
'Digest realm="http-auth@example.org", '
272-
'qop="auth, auth-int", '
271+
"qop=auth, "
273272
"algorithm=SHA-256, "
274273
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", '
275274
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
@@ -293,14 +292,129 @@ def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
293292
'cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"'
294293
in request.headers["Authorization"]
295294
)
296-
assert "qop=auth-int" in request.headers["Authorization"]
295+
assert "qop=auth," in request.headers["Authorization"]
297296
assert (
298297
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
299298
in request.headers["Authorization"]
300299
)
301300
assert (
302-
# 'response="753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1"'
303-
'response="a2274700215378a04e1a528e3706c7aab17a3fe7a988900a6c439c9509209acf"'
301+
'response="753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1"'
302+
in request.headers["Authorization"]
303+
)
304+
305+
# No other requests are made.
306+
response = httpx.Response(content=b"Hello, world!", status_code=200)
307+
with pytest.raises(StopIteration):
308+
flow.send(response)
309+
310+
311+
def test_digest_auth_int_rfc_7616_md5(monkeypatch):
312+
def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
313+
return "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ".encode()
314+
315+
auth = httpx.DigestAuth(username="Mufasa", password="Circle of Life")
316+
monkeypatch.setattr(auth, "_get_client_nonce", mock_get_client_nonce)
317+
318+
request = httpx.Request("GET", "https://www.example.com/dir/index.html")
319+
320+
# The initial request should not include an auth header.
321+
flow = auth.sync_auth_flow(request)
322+
request = next(flow)
323+
assert "Authorization" not in request.headers
324+
325+
# If a 401 response is returned, then a digest auth request is made.
326+
headers = {
327+
"WWW-Authenticate": (
328+
'Digest realm="http-auth@example.org", '
329+
"qop=auth-int, "
330+
"algorithm=MD5, "
331+
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", '
332+
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
333+
)
334+
}
335+
response = httpx.Response(
336+
content=b"Auth required", status_code=401, headers=headers, request=request
337+
)
338+
request = flow.send(response)
339+
assert request.headers["Authorization"].startswith("Digest")
340+
assert 'username="Mufasa"' in request.headers["Authorization"]
341+
assert 'realm="http-auth@example.org"' in request.headers["Authorization"]
342+
assert 'uri="/dir/index.html"' in request.headers["Authorization"]
343+
assert "algorithm=MD5" in request.headers["Authorization"]
344+
assert (
345+
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v"'
346+
in request.headers["Authorization"]
347+
)
348+
assert "nc=00000001" in request.headers["Authorization"]
349+
assert (
350+
'cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"'
351+
in request.headers["Authorization"]
352+
)
353+
assert "qop=auth-int," in request.headers["Authorization"]
354+
assert (
355+
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
356+
in request.headers["Authorization"]
357+
)
358+
assert (
359+
'response="8804a53d3640a40a4f73cea12c5ba451"'
360+
in request.headers["Authorization"]
361+
)
362+
363+
# No other requests are made.
364+
response = httpx.Response(content=b"Hello, world!", status_code=200)
365+
with pytest.raises(StopIteration):
366+
flow.send(response)
367+
368+
369+
def test_digest_auth_int_rfc7616_sha256(monkeypatch):
370+
def mock_get_client_nonce(nonce_count: int, nonce: bytes) -> bytes:
371+
return "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ".encode()
372+
373+
auth = httpx.DigestAuth(username="Mufasa", password="Circle of Life")
374+
monkeypatch.setattr(auth, "_get_client_nonce", mock_get_client_nonce)
375+
376+
request = httpx.Request("GET", "https://www.example.com/dir/index.html")
377+
378+
# The initial request should not include an auth header.
379+
flow = auth.sync_auth_flow(request)
380+
request = next(flow)
381+
assert "Authorization" not in request.headers
382+
383+
# If a 401 response is returned, then a digest auth request is made.
384+
headers = {
385+
"WWW-Authenticate": (
386+
'Digest realm="http-auth@example.org", '
387+
"qop=auth-int, "
388+
"algorithm=SHA-256, "
389+
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", '
390+
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
391+
)
392+
}
393+
response = httpx.Response(
394+
content=b"Auth required", status_code=401, headers=headers, request=request
395+
)
396+
request = flow.send(response)
397+
assert request.headers["Authorization"].startswith("Digest")
398+
assert 'username="Mufasa"' in request.headers["Authorization"]
399+
assert 'realm="http-auth@example.org"' in request.headers["Authorization"]
400+
assert 'uri="/dir/index.html"' in request.headers["Authorization"]
401+
assert "algorithm=SHA-256" in request.headers["Authorization"]
402+
assert (
403+
'nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v"'
404+
in request.headers["Authorization"]
405+
)
406+
assert "nc=00000001" in request.headers["Authorization"]
407+
assert (
408+
'cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ"'
409+
in request.headers["Authorization"]
410+
)
411+
assert "qop=auth-int," in request.headers["Authorization"]
412+
assert (
413+
'opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"'
414+
in request.headers["Authorization"]
415+
)
416+
assert (
417+
'response="8bdf6f15638e260831e905028de5450562816d093c9bfc5c13d3a46adcdde940"'
304418
in request.headers["Authorization"]
305419
)
306420

0 commit comments

Comments
 (0)