Skip to content

[3.15] gh-59515: Support multiple challenges in urllib Digest Auth (GH-160828) - #161160

Merged
orsenthil merged 1 commit into
python:3.15from
miss-islington:backport-529d66c-3.15
Nov 2, 2026
Merged

orsenthil merged 1 commit into
python:3.15from
miss-islington:backport-529d66c-3.15

Conversation

@miss-islington

@miss-islington miss-islington commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

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
(cherry picked from commit 529d66c)

Co-authored-by: Senthil Kumaran senthil@python.org

…thonGH-160828)

`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)
(cherry picked from commit 529d66c)

Co-authored-by: Senthil Kumaran <senthil@python.org>
@orsenthil
orsenthil enabled auto-merge (squash) November 2, 2026 08:15
@orsenthil
orsenthil merged commit 8e07118 into python:3.15 Nov 2, 2026
60 checks passed
@miss-islington
miss-islington deleted the backport-529d66c-3.15 branch November 2, 2026 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants