Skip to content

gh-59515: Support multiple challenges in urllib Digest Auth - #160828

Open
orsenthil wants to merge 2 commits into
python:mainfrom
orsenthil:issues/59515
Open

orsenthil wants to merge 2 commits into
python:mainfrom
orsenthil:issues/59515

Conversation

@orsenthil

@orsenthil orsenthil commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

HTTPDigestAuthHandler and ProxyDigestAuthHandler only looked at the first WWW-Authenticate / Proxy-Authenticate header and took its first word as the scheme. As a result:

  • A Digest challenge was ignored if a Basic challenge came first, in the same header or in an earlier one.

  • An unsupported scheme listed first (for example Kerberos, Basic realm="x") raised ValueError. Because the Digest handler runs before the Basic handler, that also blocked HTTPBasicAuthHandler.

This PR changes only AbstractDigestAuthHandler.
AbstractBasicAuthHandler already handles multiple challenges since GH-18284 and is not modified.

  • http_error_auth_reqed() now reads all headers (get_all()) and uses the first Digest challenge found. It raises ValueError only when neither Digest nor Basic is offered; otherwise it returns None so the next handler can try.

  • A new private _parse_challenges() splits a header into challenges per RFC 9110 §11.6.1. A comma-separated element that starts with a word not followed by = begins a new challenge. Its quote/escape handling matches parse_http_list(). It makes a single linear pass with no regex.

  • retry_http_digest_auth() is unchanged. It receives the original text of the Digest challenge, so escapes are not processed twice. For a single-challenge header the string is the same as before.

🤖 Generated with Claude Code


I have reviewed the logic and changes done by claude. This is the most compact way to address requirement in the long pending issue gh-59515

`HTTPDigestAuthHandler` and `ProxyDigestAuthHandler` only looked at the
first `WWW-Authenticate` / `Proxy-Authenticate` header and took its
first word as the scheme. As a result:

* A Digest challenge was ignored if a Basic challenge came first, in the
  same header or in an earlier one.

* An unsupported scheme listed first (for example `Kerberos, Basic
  realm="x"`) raised `ValueError`. Because the Digest handler runs
  before the Basic handler, that also blocked `HTTPBasicAuthHandler`.

This PR changes only `AbstractDigestAuthHandler`.
`AbstractBasicAuthHandler` already handles multiple challenges since
pythonGH-18284 and is not modified.

* `http_error_auth_reqed()` now reads all headers (`get_all()`) and uses
  the first Digest challenge found. It raises `ValueError` only when
  neither Digest nor Basic is offered; otherwise it returns `None` so
  the next handler can try.

* A new private `_parse_challenges()` splits a header into challenges
  per RFC 9110 §11.6.1. A comma-separated element that starts with a
  word not followed by `=` begins a new challenge. Its quote/escape
  handling matches `parse_http_list()`. It makes a single linear pass
  with no regex.

* `retry_http_digest_auth()` is unchanged. It receives the original text
  of the Digest challenge, so escapes are not processed twice. For a
  single-challenge header the string is the same as before.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant