diff --git a/CHANGELOG.md b/CHANGELOG.md index 760c3671474..e6bae750e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### 7.8-SNAPSHOT #### Bugs +* Fix #7947: (kubernetes-client-api) Basic proxy credentials are decoded by splitting on the first colon only, preserving passwords that contain colons and preventing Jetty and Vert.x proxy auth from falling back to origin request headers * Fix #7953: (httpclient-jdk) bodyless requests now preserve the requested HTTP method instead of silently defaulting to `GET`. `JdkHttpClientImpl.requestBuilder` only called `HttpRequest.Builder.method(...)` inside the `body != null` branch, so a bodyless `DELETE`/`POST`/`PUT`/`PATCH` (such as `client.raw(uri, "DELETE", null)`) was sent as `GET` on the JDK backend; the method is now set with `BodyPublishers.noBody()` when there is no body, matching the OkHttp, Jetty and Vert.x backends * Fix #7435: (kubernetes-client) A `SharedIndexInformer`'s periodic resync no longer stops permanently and silently when a single resync cycle throws. `DefaultSharedIndexInformer.scheduleResync` runs the resync through `Utils.scheduleAtFixedRate`, whose self-rescheduling chain re-arms the next cycle only when the previous one completes normally; an uncaught exception completed the (unobserved) `resyncFuture` exceptionally and the resync was never scheduled again, with no log, while the independent watch kept `isWatching()` reporting `true` (a restart was required to recover). The resync command now catches and `WARN`-logs the failure so the schedule fires again at the next interval * Fix #7933: (kubernetes-client-api) Deterministic TLS trust failures (untrusted cert, expired cert, hostname mismatch) are now classified as terminal and fail fast instead of being retried by the shared `StandardHttpClient.shouldRetry` backoff loop (~19 s drain). The classifier walks both `getCause()` and `getSuppressed()` trees for `CertificateException`, `CertPathValidatorException`, `CertPathBuilderException`, and `SSLPeerUnverifiedException`. Affects all five HTTP client modules (jdk, jetty, okhttp, vertx-4, vertx-5) on both the HTTP request and WebSocket connect paths diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java index 3804a133ea6..3df90a59e5d 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/HttpClientUtils.java @@ -141,7 +141,7 @@ public static String[] decodeBasicCredentials(String basicCredentials) { final String encodedCredentials = basicCredentials.replaceFirst("Basic ", ""); final String decodedProxyAuthorization = new String(Base64.getDecoder().decode(encodedCredentials), StandardCharsets.UTF_8); - final String[] userPassword = decodedProxyAuthorization.split(":"); + final String[] userPassword = decodedProxyAuthorization.split(":", 2); if (userPassword.length == 2) { return userPassword; } diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/HttpClientUtilsTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/HttpClientUtilsTest.java index f50d47154ce..ea344a3f49c 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/HttpClientUtilsTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/HttpClientUtilsTest.java @@ -187,6 +187,14 @@ static Stream basicCredentialsInput() { arguments("username", "Þaßßword£", "Basic dXNlcm5hbWU6w55hw5/Dn3dvcmTCow==")); } + @Test + void testDecodeBasicCredentialsPreservesColonsInPassword() { + String[] userPassword = HttpClientUtils.decodeBasicCredentials(HttpClientUtils.basicCredentials("username", "pa:ss")); + + assertThat(userPassword) + .containsExactly("username", "pa:ss"); + } + @Nested @DisplayName("getProxyUrl") @TestInstance(PER_CLASS)