pydantic / pydantic/httpx2

Support DigestAuth with "x-www-authenticate" in first response header

Open Beginner friendly
#846 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.5k
Forks
78
Avg merge
8h 59m
Merged PRs (30d)
24

Description

Originally opened by @kiryph on 2024-09-19 14:21:02 in encode/httpx

The Fronius inverter for photovoltaic systems uses for its local REST API digest authentication.

It uses its initial response header "X-WWW-Authenticate" instead of "www-authenticate" and hence make the httpx request fail.

Here an initial curl command with the response header:

❯ curl -I "http://192.168.1.141/config/emrs"
HTTP/1.1 401 Unauthorized
X-WWW-Authenticate: Digest realm="Webinterface area", charset="UTF-8", algorithm=MD5, nonce="66ec2f8d:36a65537553cf788606762854336a0b3", qop="auth"
Content-Type: text/html
Content-Length: 347
Date: Thu, 19 Sep 2024 14:05:01 GMT
Server: webserver

httpx 0.27.2 fails to extract X-WWW-Authenticate with nonce, qop, algorithm, realm in

https://github.com/encode/httpx/blob/87713d2172053c4ad05efacf3ab7e0a5c15616fc/httpx/_auth.py#L201-L212

My script

import httpx

url = "http://192.168.1.141/config/emrs" # adjust IP to that one of your inverter
user = "technician"
pw = <INSERT PW>

auth = httpx.DigestAuth(user,pw)

with httpx.Client(auth=auth) as client:
    r = client.get(url)
    print(r.status_code)
    print(r.json()['priorities'])

    r = client.get(url)
    print(r.status_code)
    print(r.json()['priorities'])

runs only with following quick diff

❯ git diff
diff --git a/httpx/_auth.py b/httpx/_auth.py
index b03971a..fb6ad69 100644
--- a/httpx/_auth.py
+++ b/httpx/_auth.py
@@ -198,12 +198,22 @@ class DigestAuth(Auth):

         response = yield request

-        if response.status_code != 401 or "www-authenticate" not in response.headers:
+        auth_strings = [ "www-authenticate", "x-www-authenticate" ]
+        auth_string = False
+        for a in auth_strings:
+            if a in response.headers:
+                if auth_string == False:
+                    auth_string = a
+                else:
+                    message = "Malformed Digest WWW-Authenticate response header"
+                    raise ProtocolError(message, request=request)
+
+        if response.status_code != 401 or auth_string == False:
             # If the response is not a 401 then we don't
             # need to build an authenticated request.
             return

-        for auth_header in response.headers.get_list("www-authenticate"):
+        for auth_header in response.headers.get_list(auth_string):
             if auth_header.lower().startswith("digest "):
                 break
         else:

Note, this diff is only to show to me that it works. I did not follow any coding guidelines of this project.

For reference, here a couple of projects which have written their custom digest authorization to handle the Fronius reponse header using the request library:

I am not sure how common it is to use X-WWW-Authenticate. Google did not return many results:

https://community.smartbear.com/discussions/readyapi-questions/digest-authentication-with-x-www-authenticate/252961

However, I still think supporting this deviation might be acceptable. If Fronius screwed this up more heavily than I think, I understand that httpx cannot support all quirks of all digest implementations.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in httpx/_auth.py at the DigestAuth response handling referenced by the issue, then reproduce the supplied Python example or inspect the shown 401 response header. Done means DigestAuth can extract a Digest challenge from X-WWW-Authenticate as well as the standard www-authenticate header without breaking the existing flow.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
authentication
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.