Skip to content

Commit b16a0d5

Browse files
authored
docs: state both transports do Basic-only proxy auth (#133)
PR: #133
1 parent b470df2 commit b16a0d5

4 files changed

Lines changed: 49 additions & 13 deletions

File tree

sdk-core/src/main/kotlin/org/dexpace/sdk/core/util/ProxyOptions.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,23 @@ import java.util.regex.Pattern
2727
*
2828
* ## Proxy authentication
2929
*
30-
* Proxy auth is driven by [username] / [password]. The shipped transports apply them as follows:
31-
* - OkHttp transport: sets up **Basic** proxy authentication from [username] / [password].
32-
* - JDK transport: passes [username] / [password] to the `java.net.http` stack, which negotiates
33-
* **Basic** or **Digest** with the proxy itself.
30+
* Proxy auth is driven by [username] / [password]. **Both shipped transports authenticate the
31+
* proxy with the Basic scheme only:**
32+
* - OkHttp transport: its `proxyAuthenticator` emits `Proxy-Authorization: Basic …` from
33+
* [username] / [password].
34+
* - JDK transport: installs a `java.net.Authenticator` on the `java.net.http` client. That
35+
* built-in integration answers Basic proxy challenges only; it does not implement Digest
36+
* proxy auth.
37+
*
38+
* Neither transport performs Digest (or any other non-Basic scheme) proxy authentication. To
39+
* authenticate against a Digest-only proxy, supply your own pre-configured client — a
40+
* `java.net.http.HttpClient` or `OkHttpClient` carrying your own authenticator — through the
41+
* transport's `create(...)` entry point; the SDK uses such a client as-is and does not override
42+
* its proxy authentication.
3443
*
3544
* [challengeHandler] is **currently not honoured by any shipped transport** — it is reserved for
3645
* a future pluggable proxy-auth mechanism. Setting it has no effect today (the transports ignore
37-
* it and log a warning), so supply [username] / [password] for proxy authentication.
46+
* it and log a warning), so supply [username] / [password] for Basic proxy authentication.
3847
*
3948
* ## Bypass-all semantics (breaking change from pre-v2 API)
4049
*

sdk-transport-jdkhttp/src/main/kotlin/org/dexpace/sdk/transport/jdkhttp/JdkHttpTransport.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,14 +376,18 @@ public class JdkHttpTransport private constructor(
376376
* [ProxyAuthenticator]. The JDK client picks up this authenticator at request
377377
* time; it answers **only** proxy (407) challenges whose host/port match the
378378
* configured proxy, returning `null` for origin-server (401) challenges so the
379-
* proxy credentials never leak to an origin host.
379+
* proxy credentials never leak to an origin host. The `java.net.http` client's
380+
* built-in handling of a registered `Authenticator` covers the **Basic** scheme
381+
* only — this transport does **not** perform Digest proxy authentication.
380382
*
381383
* A configured [ProxyOptions.challengeHandler] is **not** honoured by this transport:
382384
* `java.net.http.HttpClient` exposes no per-407 hook through which a custom
383385
* `ChallengeHandler` (e.g. Digest) could be invoked, so the handler is dropped with a
384-
* loud warning rather than silently ignored. Proxy authentication falls back to the
385-
* JDK's own username/password negotiation via [ProxyAuthenticator]. Consumers needing
386-
* Digest proxy auth should use the OkHttp transport.
386+
* loud warning rather than silently ignored. Proxy authentication falls back to Basic
387+
* auth derived from [ProxyOptions.username] / [ProxyOptions.password] via
388+
* [ProxyAuthenticator]. To authenticate against a Digest-only proxy, pass a
389+
* pre-configured `java.net.http.HttpClient` carrying your own `Authenticator` to
390+
* [create]; the SDK uses that client as-is.
387391
*
388392
* Credentials are deliberately never logged.
389393
*/
@@ -397,8 +401,9 @@ public class JdkHttpTransport private constructor(
397401
.log(
398402
"ProxyOptions.challengeHandler is set but the JDK transport cannot invoke a " +
399403
"custom ChallengeHandler: java.net.http.HttpClient exposes no per-407 hook. " +
400-
"The handler is ignored; proxy auth falls back to username/password via the " +
401-
"JDK's own auth negotiation. Use the OkHttp transport for Digest proxy auth.",
404+
"The handler is ignored; proxy auth falls back to Basic auth derived from " +
405+
"ProxyOptions.username / ProxyOptions.password. For Digest proxy auth, pass a " +
406+
"pre-configured java.net.http.HttpClient with your own Authenticator to create().",
402407
)
403408
}
404409
if (options.type != ProxyOptions.Type.HTTP) {

sdk-transport-jdkhttp/src/test/kotlin/org/dexpace/sdk/transport/jdkhttp/ProxyAuthenticatorTest.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,31 @@ class ProxyAuthenticatorTest {
6161
assertNull(auth, "a proxy challenge on a non-configured port must not receive credentials")
6262
}
6363

64+
/**
65+
* Pins the documented proxy-auth contract: the credentials this authenticator returns are
66+
* the raw username/password, with no scheme negotiation of its own. Whether a challenge is
67+
* actually satisfied is decided by the `java.net.http` client's built-in handling of a
68+
* registered `Authenticator`, which covers the **Basic** scheme only — it does not drive
69+
* Digest proxy auth through this hook. The authenticator therefore returns the same
70+
* credentials whether the proxy advertises `Basic` or `Digest`; a Digest-only proxy is not
71+
* authenticated end-to-end, matching the [JdkHttpTransport.Builder] KDoc.
72+
*/
73+
@Test
74+
fun `proxy challenge credentials carry no scheme of their own`() {
75+
val proxy = Authenticator.RequestorType.PROXY
76+
val basic = challenge(host = "proxy.example", port = 3128, type = proxy, scheme = "Basic")
77+
val digest = challenge(host = "proxy.example", port = 3128, type = proxy, scheme = "Digest")
78+
requireNotNull(basic) { "Basic proxy challenge must be answered" }
79+
requireNotNull(digest) { "the authenticator does not inspect the scheme string" }
80+
assertEquals(basic.userName, digest.userName)
81+
assertEquals(String(basic.password), String(digest.password))
82+
}
83+
6484
private fun challenge(
6585
host: String,
6686
port: Int,
6787
type: Authenticator.RequestorType,
88+
scheme: String = "Basic",
6889
): PasswordAuthentication? =
6990
Authenticator.requestPasswordAuthentication(
7091
authenticator,
@@ -73,7 +94,7 @@ class ProxyAuthenticatorTest {
7394
port,
7495
"http",
7596
"challenge",
76-
"Basic",
97+
scheme,
7798
URL("http://$host:$port/"),
7899
type,
79100
)

sdk-transport-okhttp/src/main/kotlin/org/dexpace/sdk/transport/okhttp/OkHttpTransport.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ public class OkHttpTransport private constructor(
369369
"The OkHttp transport does not honour ProxyOptions.challengeHandler; it is " +
370370
"ignored. Proxy authentication falls back to Basic auth derived from " +
371371
"ProxyOptions.username / ProxyOptions.password. Supply those credentials, " +
372-
"or use a transport that supports a custom proxy challenge handler.",
372+
"or for Digest proxy auth pass a pre-configured OkHttpClient with your own " +
373+
"proxyAuthenticator to create().",
373374
)
374375
}
375376
val javaType =

0 commit comments

Comments
 (0)