From c165d8f5ddcd06fe4e72cd3ee0f688241aff0180 Mon Sep 17 00:00:00 2001 From: mohammed adib Date: Mon, 20 Jul 2026 13:23:55 +0530 Subject: [PATCH] keep method and digest-uri in A2 for qop=auth-int --- .../main/java/org/asynchttpclient/Realm.java | 6 +++-- .../java/org/asynchttpclient/RealmTest.java | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/client/src/main/java/org/asynchttpclient/Realm.java b/client/src/main/java/org/asynchttpclient/Realm.java index cf770dafe..a2be55835 100644 --- a/client/src/main/java/org/asynchttpclient/Realm.java +++ b/client/src/main/java/org/asynchttpclient/Realm.java @@ -667,8 +667,10 @@ private byte[] ha2(StringBuilder sb, String digestUri, MessageDigest md) { if (entityBodyHash != null) { sb.append(entityBodyHash); } else { - // Hash of empty body using the current algorithm - sb.append(toHexString(md.digest())); + // Hash of empty body using the current algorithm. Must append in place: + // toHexString() would take the same recycled builder and reset it, dropping + // the method and digest-uri already written above. + appendBase16(sb, md.digest()); } } else if (qop != null && !"auth".equals(qop)) { throw new UnsupportedOperationException("Digest qop not supported: " + qop); diff --git a/client/src/test/java/org/asynchttpclient/RealmTest.java b/client/src/test/java/org/asynchttpclient/RealmTest.java index eceb5a351..395b18f83 100644 --- a/client/src/test/java/org/asynchttpclient/RealmTest.java +++ b/client/src/test/java/org/asynchttpclient/RealmTest.java @@ -106,6 +106,32 @@ public void testStrongDigest() throws Exception { assertEquals(orig.getResponse(), expectedResponse); } + @RepeatedIfExceptionsTest(repeats = 5) + public void testAuthIntDigestKeepsMethodAndUriInA2() throws Exception { + String user = "user"; + String pass = "pass"; + String realm = "realm"; + String nonce = "nonce"; + String method = "POST"; + Uri uri = Uri.create("http://ahc.io/foo"); + String qop = "auth-int"; + Realm orig = digestAuthRealm(user, pass) + .setNonce(nonce) + .setUri(uri) + .setMethodName(method) + .setRealmName(realm) + .setQop(qop) + .build(); + + String nc = orig.getNc(); + String cnonce = orig.getCnonce(); + String ha1 = getMd5(user + ':' + realm + ':' + pass); + String ha2 = getMd5(method + ':' + uri.getPath() + ':' + getMd5("")); + String expectedResponse = getMd5(ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2); + + assertEquals(expectedResponse, orig.getResponse()); + } + // Phase 1: matchParam tests @Test public void testMatchParamUnquotedAlgorithm() {