feat(http): SslContextBuilder supports system/trust-all/trust-paths modes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-19 15:54:15 +02:00
parent 2224f7d902
commit 262ee91684
3 changed files with 153 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
package com.cameleer.server.app.http;
import com.cameleer.server.core.http.OutboundHttpProperties;
import com.cameleer.server.core.http.OutboundHttpRequestContext;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SslContextBuilder {
public SSLContext build(OutboundHttpProperties systemProps, OutboundHttpRequestContext ctx) throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLS");
if (systemProps.trustAll() || ctx.trustMode() == com.cameleer.server.core.http.TrustMode.TRUST_ALL) {
sslContext.init(null, new TrustManager[]{new TrustAllManager()}, null);
return sslContext;
}
List<X509Certificate> extraCerts = new ArrayList<>();
List<String> paths = new ArrayList<>(systemProps.trustedCaPemPaths());
if (ctx.trustMode() == com.cameleer.server.core.http.TrustMode.TRUST_PATHS) {
paths.addAll(ctx.trustedCaPemPaths());
}
for (String p : paths) {
extraCerts.addAll(loadPem(p));
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
// Load JDK default trust roots
TrustManagerFactory defaultTmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
defaultTmf.init((KeyStore) null);
int i = 0;
for (TrustManager tm : defaultTmf.getTrustManagers()) {
if (tm instanceof X509TrustManager x509tm) {
for (X509Certificate cert : x509tm.getAcceptedIssuers()) {
ks.setCertificateEntry("default-" + (i++), cert);
}
}
}
// Add configured extras
for (X509Certificate cert : extraCerts) {
ks.setCertificateEntry("extra-" + (i++), cert);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
private Collection<? extends X509Certificate> loadPem(String path) throws IOException, java.security.cert.CertificateException {
Path p = Path.of(path);
if (!Files.exists(p)) {
throw new IllegalArgumentException("CA file not found: " + path);
}
try (var in = Files.newInputStream(p)) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
@SuppressWarnings("unchecked")
Collection<X509Certificate> certs = (Collection<X509Certificate>) cf.generateCertificates(in);
return certs;
}
}
private static final class TrustAllManager implements X509TrustManager {
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
}