keep method and digest-uri in A2 for qop=auth-int - #2269
Merged
Conversation
hyperxpro
pushed a commit
that referenced
this pull request
Jul 23, 2026
## Summary - pass the auth-int entity-body hash to the request-specific `Realm.Builder` - build the preemptive Digest realm once for origin and proxy authentication - remove the duplicate digest-response implementation that was recalculating HA1 and whose result was overwritten by the final build - verify the emitted origin and proxy responses against an independent MD5 calculation This follows the entity-body-hash flow already used by the 401 and 407 interceptors. It does not modify `Realm.java`, so it remains compatible with #2269. ## Verification - `./mvnw -pl client -Dtest=org.asynchttpclient.util.AuthenticatorUtilsTest,org.asynchttpclient.RealmTest,org.asynchttpclient.DigestAuthTest,org.asynchttpclient.DigestAuthRfc7616Test test` (53 tests passed) - `./mvnw -B -ntp -pl client -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true verify` (Revapi passed) The full JDK 11 `./mvnw clean verify` gate was not run because this environment provides JDK 21 only. Codex on behalf of Pavel Ptashyts Co-authored-by: Codex <codex@openai.com>
hyperxpro
approved these changes
Jul 25, 2026
hyperxpro
pushed a commit
that referenced
this pull request
Jul 25, 2026
Realm.Builder.ha2 writes A2 into the recycled StringBuilder that newResponse took from StringBuilderPool, but on the auth-int branch with no precomputed entity-body hash it called StringUtils.toHexString, which takes that same thread-local builder and resets it. The "POST:/secret:" already written was discarded and A2 came out as the empty-body hash twice, so the Digest response no longer bound the request method or the target URI. Appending with appendBase16 keeps the hash in the buffer already being built, which is what ha1 and newResponse already do for HA1 and HA2. The two encoders emit identical lowercase, zero-padded hex, so the digest is unchanged everywhere the branch was already correct. Latent since #2148 replaced the EMPTY_ENTITY_MD5 constant with a computed hash. The null-entityBodyHash branch is no longer reachable from the request pipeline: #2276 wired setEntityBodyHash into perRequestAuthorizationHeader and computeBodyHash never returns null, so no wrong header reaches the wire today. It is still reached by the nextnonce rotation in Interceptors and by Realms built through the public API. The added RealmTest case checks the response against the RFC 7616 A2 and fails on the current code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Realm.Builder.ha2 writes A2 into the recycled StringBuilder that newResponse took from StringBuilderPool, but on the auth-int branch with no precomputed entity-body hash it calls toHexString, which takes that same thread-local builder and resets it, so the "POST:/secret:" already written is discarded. A2 comes out as the empty-body hash twice and the Digest response no longer binds the request method or the target URI. A server reaches this by answering with qop="auth-int" in WWW-Authenticate or Proxy-Authenticate, since parseRawQop picks auth-int when that is the only value offered.
Appending with appendBase16 keeps the hash in the buffer already being built, which is what newResponse does for HA1 and HA2 a few lines below. The added RealmTest case checks the response against the RFC 7616 A2 and fails on the current code.