From 573b5837f5ba71ba308a4ebd1de5b10da4a70322 Mon Sep 17 00:00:00 2001 From: Lucas Chang Date: Thu, 21 Dec 2023 19:31:30 +0800 Subject: [PATCH 1/3] suport custom sni for ssl connection --- .../clickhouse/client/ClickHouseConfig.java | 4 ++ .../com/clickhouse/client/ClickHouseNode.java | 3 +- .../client/config/ClickHouseClientOption.java | 2 + .../config/ClickhouseSSLSocketFactory.java | 66 +++++++++++++++++++ .../client/grpc/OkHttpChannelFactoryImpl.java | 4 +- .../client/http/HttpUrlConnectionImpl.java | 10 +-- 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseConfig.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseConfig.java index 60098dc9b..7f13370ee 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseConfig.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseConfig.java @@ -229,6 +229,7 @@ public static Map toClientOptions(Map prop private final String sslRootCert; private final String sslCert; private final String sslKey; + private final String serverHostName; private final String keyStoreType; private final String trustStore; private final String trustStorePassword; @@ -349,6 +350,7 @@ public ClickHouseConfig(Map options, ClickHouseC this.sslRootCert = getStrOption(ClickHouseClientOption.SSL_ROOT_CERTIFICATE); this.sslCert = getStrOption(ClickHouseClientOption.SSL_CERTIFICATE); this.sslKey = getStrOption(ClickHouseClientOption.SSL_KEY); + this.serverHostName = getStrOption(ClickHouseClientOption.SERVER_HOST_NAME); this.keyStoreType = getStrOption(ClickHouseClientOption.KEY_STORE_TYPE); this.trustStore = getStrOption(ClickHouseClientOption.TRUST_STORE); this.trustStorePassword = getStrOption(ClickHouseClientOption.KEY_STORE_PASSWORD); @@ -630,6 +632,8 @@ public String getSslKey() { return sslKey; } + public String getServerHostName() { return serverHostName; } + public String getKeyStoreType() { return keyStoreType; } diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNode.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNode.java index e5a874fa2..63be40aec 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNode.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNode.java @@ -34,6 +34,7 @@ import com.clickhouse.client.config.ClickHouseClientOption; import com.clickhouse.client.config.ClickHouseDefaults; import com.clickhouse.client.config.ClickHouseSslMode; +import com.clickhouse.client.config.ClickhouseSSLSocketFactory; import com.clickhouse.config.ClickHouseOption; import com.clickhouse.data.ClickHouseChecker; import com.clickhouse.data.ClickHouseUtils; @@ -620,7 +621,7 @@ static ClickHouseNode probe(String host, int port, ClickHouseSslMode mode, Strin return probe(host, port, timeout); } - SSLSocketFactory factory = sslContext.getSocketFactory(); + SSLSocketFactory factory = new ClickhouseSSLSocketFactory(sslContext.getSocketFactory(), config); ClickHouseDnsResolver resolver = ClickHouseDnsResolver.getInstance(); ClickHouseProtocol p = ClickHouseProtocol.HTTP; InetSocketAddress address = resolver != null diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java index c88963f20..39d99be41 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java @@ -343,6 +343,8 @@ public enum ClickHouseClientOption implements ClickHouseOption { * SSL key. */ SSL_KEY("sslkey", "", "RSA key in PKCS#8 format.", true), + + SERVER_HOST_NAME("server_host_name", "", "The ClickHouse server hostname as identified by the CN or SNI of its TLS certificate. Set this to avoid SSL errors when connecting through a proxy or tunnel with a different hostname"), /** * Key Store type. */ diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java new file mode 100644 index 000000000..c5544f432 --- /dev/null +++ b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java @@ -0,0 +1,66 @@ +package com.clickhouse.client.config; + +import com.clickhouse.client.ClickHouseConfig; + +import javax.net.ssl.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.List; + +public class ClickhouseSSLSocketFactory extends SSLSocketFactory { + private SSLSocketFactory delegate; + private ClickHouseConfig config; + + public ClickhouseSSLSocketFactory(SSLSocketFactory delegate, ClickHouseConfig config) { + this.delegate = delegate; + this.config = config; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + private void setServerNameIndication(SSLSocket socket) { + SSLParameters sslParams = socket.getSSLParameters(); + sslParams.setServerNames(List.of(new SNIHostName(this.config.getServerHostName()))); + socket.setSSLParameters(sslParams); + } + + private Socket setup(Socket socket) { + setServerNameIndication((SSLSocket) socket); + return socket; + } + + @Override + public Socket createSocket(Socket socket, final String host, int port, boolean autoClose) throws IOException { + return setup(delegate.createSocket(socket, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return setup(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return setup(delegate.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return setup(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return setup(delegate.createSocket(address, port, localAddress, localPort)); + } +} diff --git a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/OkHttpChannelFactoryImpl.java b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/OkHttpChannelFactoryImpl.java index 645d43ed8..d2ac0b790 100644 --- a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/OkHttpChannelFactoryImpl.java +++ b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/OkHttpChannelFactoryImpl.java @@ -4,6 +4,8 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; + +import com.clickhouse.client.config.ClickhouseSSLSocketFactory; import io.grpc.ManagedChannelBuilder; import io.grpc.okhttp.OkHttpChannelBuilder; import com.clickhouse.client.ClickHouseConfig; @@ -47,7 +49,7 @@ protected void setupSsl() { Optional sslContext = ClickHouseSslContextProvider.getProvider() .getSslContext(SSLContext.class, config); if (sslContext.isPresent()) { - builder.useTransportSecurity().sslSocketFactory(sslContext.get().getSocketFactory()); + builder.useTransportSecurity().sslSocketFactory(new ClickhouseSSLSocketFactory(sslContext.get().getSocketFactory(), config)); } } catch (SSLException e) { throw new IllegalStateException(e); diff --git a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java index cb0a95647..a627486d9 100644 --- a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java +++ b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java @@ -7,6 +7,7 @@ import com.clickhouse.client.ClickHouseSslContextProvider; import com.clickhouse.client.config.ClickHouseClientOption; import com.clickhouse.client.config.ClickHouseSslMode; +import com.clickhouse.client.config.ClickhouseSSLSocketFactory; import com.clickhouse.client.http.config.ClickHouseHttpOption; import com.clickhouse.data.ClickHouseChecker; import com.clickhouse.data.ClickHouseExternalTable; @@ -37,9 +38,7 @@ import java.util.Map.Entry; import java.util.concurrent.ExecutorService; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; +import javax.net.ssl.*; public class HttpUrlConnectionImpl extends ClickHouseHttpConnection { private static final Logger log = LoggerFactory.getLogger(HttpUrlConnectionImpl.class); @@ -122,7 +121,10 @@ private HttpURLConnection newConnection(String url, boolean post) throws IOExcep secureConn.setHostnameVerifier(verifier); if (sslContext != null) { - secureConn.setSSLSocketFactory(sslContext.getSocketFactory()); + if(c.getServerHostName() != null && !c.getServerHostName().isEmpty()) { + sslContext.getDefaultSSLParameters().setServerNames(List.of(new SNIHostName(c.getServerHostName()))); + } + secureConn.setSSLSocketFactory(new ClickhouseSSLSocketFactory(sslContext.getSocketFactory(), c)); } } From cadd3c337213cc78125271fc269803759fa0999a Mon Sep 17 00:00:00 2001 From: Lucas Chang Date: Thu, 21 Dec 2023 22:39:19 +0800 Subject: [PATCH 2/3] check null and empty --- .../client/config/ClickhouseSSLSocketFactory.java | 9 ++++++--- .../clickhouse/client/http/HttpUrlConnectionImpl.java | 3 --- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java index c5544f432..7cc6c7d41 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickhouseSSLSocketFactory.java @@ -29,9 +29,12 @@ public String[] getSupportedCipherSuites() { } private void setServerNameIndication(SSLSocket socket) { - SSLParameters sslParams = socket.getSSLParameters(); - sslParams.setServerNames(List.of(new SNIHostName(this.config.getServerHostName()))); - socket.setSSLParameters(sslParams); + String serverHostName = this.config.getServerHostName(); + if(serverHostName != null && !serverHostName.isEmpty()) { + SSLParameters sslParams = socket.getSSLParameters(); + sslParams.setServerNames(List.of(new SNIHostName(serverHostName))); + socket.setSSLParameters(sslParams); + } } private Socket setup(Socket socket) { diff --git a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java index a627486d9..65563c73b 100644 --- a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java +++ b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java @@ -121,9 +121,6 @@ private HttpURLConnection newConnection(String url, boolean post) throws IOExcep secureConn.setHostnameVerifier(verifier); if (sslContext != null) { - if(c.getServerHostName() != null && !c.getServerHostName().isEmpty()) { - sslContext.getDefaultSSLParameters().setServerNames(List.of(new SNIHostName(c.getServerHostName()))); - } secureConn.setSSLSocketFactory(new ClickhouseSSLSocketFactory(sslContext.getSocketFactory(), c)); } } From 1dabea33b283df5354481079110b99146186d40e Mon Sep 17 00:00:00 2001 From: Lucas Chang Date: Thu, 21 Dec 2023 22:40:40 +0800 Subject: [PATCH 3/3] update --- .../com/clickhouse/client/http/HttpUrlConnectionImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java index 65563c73b..0551b483a 100644 --- a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java +++ b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/HttpUrlConnectionImpl.java @@ -38,7 +38,9 @@ import java.util.Map.Entry; import java.util.concurrent.ExecutorService; -import javax.net.ssl.*; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; public class HttpUrlConnectionImpl extends ClickHouseHttpConnection { private static final Logger log = LoggerFactory.getLogger(HttpUrlConnectionImpl.class);