From 99e2a8354f84651916866e51d8f24622924bf548 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:51:49 +0200 Subject: [PATCH] fix: handle HTTPS redirects in InsecureTlsHelper for OIDC discovery Java's automatic redirect following creates new connections that do NOT inherit custom SSLSocketFactory/HostnameVerifier. This caused the OIDC discovery fetch to fail on redirect even with TLS_SKIP_VERIFY=true. Now disables auto-redirect and follows manually with SSL on each hop. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/security/InsecureTlsHelper.java | 32 ++++++++++++++++--- .../app/security/OidcTokenExchanger.java | 3 ++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/InsecureTlsHelper.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/InsecureTlsHelper.java index 4b8c8730..35aa33e3 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/InsecureTlsHelper.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/InsecureTlsHelper.java @@ -10,6 +10,8 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.security.SecureRandom; @@ -59,13 +61,33 @@ final class InsecureTlsHelper { /** * Opens an {@link InputStream} from the given URL, applying trust-all TLS * if the connection is HTTPS and {@code skipVerify} is true. + *

+ * Handles redirects manually because Java's automatic redirect following + * creates new connections that do NOT inherit custom SSLSocketFactory / + * HostnameVerifier settings. */ static InputStream openStream(URL url, boolean skipVerify) throws Exception { - URLConnection conn = url.openConnection(); - if (skipVerify && conn instanceof HttpsURLConnection https) { - https.setSSLSocketFactory(socketFactory()); - https.setHostnameVerifier(hostnameVerifier()); + URL current = url; + for (int i = 0; i < 5; i++) { + HttpURLConnection conn = (HttpURLConnection) current.openConnection(); + if (skipVerify && conn instanceof HttpsURLConnection https) { + https.setSSLSocketFactory(socketFactory()); + https.setHostnameVerifier(hostnameVerifier()); + } + conn.setInstanceFollowRedirects(false); + int code = conn.getResponseCode(); + if (code >= 300 && code < 400) { + String location = conn.getHeaderField("Location"); + conn.disconnect(); + if (location == null) { + throw new java.io.IOException("Redirect with no Location header from " + current); + } + current = new URI(location).toURL(); + log.debug("Following OIDC redirect -> {}", current); + continue; + } + return conn.getInputStream(); } - return conn.getInputStream(); + throw new java.io.IOException("Too many redirects from " + url); } } diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java index bf9d2b49..1f41816d 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcTokenExchanger.java @@ -61,6 +61,9 @@ public class OidcTokenExchanger { SecurityProperties securityProperties) { this.configRepository = configRepository; this.tlsSkipVerify = securityProperties.isOidcTlsSkipVerify(); + if (tlsSkipVerify) { + log.warn("OIDC TLS skip-verify enabled for token exchanger"); + } } public record OidcUserInfo(String subject, String email, String name, List roles, String idToken) {}