[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2433?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Oleg Kalnichevski updated HTTPCLIENT-2433:
------------------------------------------
    Fix Version/s: 5.6.5
                   5.7-alpha2

> Async HTTP/2 authentication challenge replay corrupts repeatable 
> FileEntityProducer request body
> ------------------------------------------------------------------------------------------------
>
>                 Key: HTTPCLIENT-2433
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2433
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient (async)
>    Affects Versions: 5.6.1
>         Environment: Apache HttpClient: 5.6.1
> Apache HttpCore: 5.4
> Java: Eclipse Temurin 17.0.20
> Maven: 3.9.16
> Operating system: Linux
> Transport: clear-text HTTP/2 over loopback using the asynchronous client
> Request entity: repeatable FileEntityProducer containing 2,000,000 bytes
> Authentication: HTTP Basic after a 401 challenge
>            Reporter: Matthias
>            Priority: Major
>              Labels: authentication, http2
>             Fix For: 5.6.5, 5.7-alpha2
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> h2. Summary
> When the asynchronous HttpClient sends a PUT containing a repeatable 
> {{FileEntityProducer}} over HTTP/2 and the server immediately responds with a 
> {{401 Unauthorized}} Basic-authentication challenge, the authenticated replay 
> can contain a corrupted request body.
> The client receives {{200 OK}}, even though the body received for the 
> authenticated request is truncated. The original unauthenticated HTTP/2 
> stream can simultaneously receive more bytes than the complete entity.
> The equivalent HTTP/1.1 authentication replay works correctly. Sending the 
> Authorization header preemptively over HTTP/2 also works correctly.
> h2. Minimal reproducer
> A standalone Java/Maven reproducer is available here:
> [https://github.com/mkurz/apache-httpclient5-h2-auth-replay-reproducer|https://github.com/mkurz/apache-httpclient5-h2-auth-replay-reproducer]
> It directly uses Apache HttpClient 5.6.1 and its transitive HttpCore 5.4 
> dependency. It does not use sbt, Gigahorse, Sonatype, or any external server.
> {code:bash}
> git clone 
> https://github.com/mkurz/apache-httpclient5-h2-auth-replay-reproducer.git
> cd apache-httpclient5-h2-auth-replay-reproducer
> mvn test
> {code}
> The test starts an in-process loopback server and sends a deterministic 
> 2,000,000-byte file using {{FileEntityProducer}}.
> Three cases are tested:
> # HTTP/2 with preemptive Basic authentication: passes.
> # HTTP/1.1 with a Basic-authentication challenge: passes.
> # HTTP/2 with the same authentication challenge: fails.
> h2. Representative result
> {code}
> status=200 expected-length=2000000 
> expected-sha1=b694f093d9545edaf64a849bf7e6fc2864a23a0f
>   1: auth=false protocol=HTTP/2.0 length=3229953 exact=false 
> sha1=6e23e0988c6d247aa984573ea4f40ee677b0ee0a event=end
>   2: auth=true protocol=HTTP/2.0 length=999423 exact=false 
> sha1=60d7a5d13f025e3a10080a71b6c36164b8520a2c event=end
> Tests run: 3, Failures: 1, Errors: 0, Skipped: 0
> {code}
> The precise corrupted lengths and checksums vary between runs, but the HTTP/2 
> challenge case consistently fails while both controls pass.
> h2. Expected behavior
> The authenticated replay should contain exactly the original 2,000,000 bytes 
> with SHA-1:
> {code}
> b694f093d9545edaf64a849bf7e6fc2864a23a0f
> {code}
> A repeatable entity producer must be reset or reproduced independently for 
> the authentication retry, without bytes leaking between the original and 
> replayed HTTP/2 streams.
> h2. Actual behavior
> The server receives an oversized body on the original unauthenticated stream 
> and a truncated body on the authenticated stream. It sends {{200 OK}} after 
> consuming the authenticated stream, so the client reports a successful 
> request despite the corrupted upload.
> h2. Real-world occurrence
> This was originally observed while sbt, through Gigahorse's Apache HttpClient 
> backend, published Twirl snapshot artifacts to Sonatype Central snapshots. 
> Publishing appeared to succeed, but subsequent dependency resolution failed 
> because the downloaded artifact did not match its published checksum.
> * Downstream checksum failure:
>   
> [https://github.com/playframework/play-doc/actions/runs/34967229654/job/104374507676|https://github.com/playframework/play-doc/actions/runs/34967229654/job/104374507676]
> * Twirl commit whose snapshot publication reproduced the corruption:
>   
> [https://github.com/playframework/twirl/commit/e8c94e68fdb69fc1e4bef9b2689596cced5ac2f3|https://github.com/playframework/twirl/commit/e8c94e68fdb69fc1e4bef9b2689596cced5ac2f3]
> * Original sbt investigation:
>   [https://github.com/sbt/sbt/pull/9772|https://github.com/sbt/sbt/pull/9772]
> Gigahorse 0.9.6 works around this for known credentials by sending Basic 
> authentication preemptively, and sbt adopted that release in:
> [https://github.com/sbt/sbt/pull/9775|https://github.com/sbt/sbt/pull/9775]
> That workaround avoids the challenge/replay path. It does not fix 
> challenge-based HTTP/2 authentication replay inside HttpClient.
> h2. Implementation
> [apache/httpcomponents-client#884|https://github.com/apache/httpcomponents-client/pull/884]



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to