diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/NativeClient.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/NativeClient.java index 27da6776..986975e6 100644 --- a/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/NativeClient.java +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/NativeClient.java @@ -16,6 +16,7 @@ import com.github.housepower.buffer.SocketBuffedReader; import com.github.housepower.buffer.SocketBuffedWriter; +import com.github.housepower.client.ssl.SSLContextBuilder; import com.github.housepower.data.Block; import com.github.housepower.misc.Validate; import com.github.housepower.protocol.*; @@ -29,11 +30,14 @@ import com.github.housepower.stream.QueryResult; import com.github.housepower.stream.ClickHouseQueryResult; +import javax.net.ssl.*; import java.io.IOException; import java.io.Serializable; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; +import java.security.*; +import java.security.cert.CertificateException; import java.sql.SQLException; import java.time.Duration; import java.util.Map; @@ -44,23 +48,41 @@ public class NativeClient { private static final Logger LOG = LoggerFactory.getLogger(NativeClient.class); - public static NativeClient connect(ClickHouseConfig configure) throws SQLException { - return connect(configure.host(), configure.port(), configure); + public static NativeClient connect(ClickHouseConfig config) throws SQLException { + return connect(config.host(), config.port(), config); } - public static NativeClient connect(String host, int port, ClickHouseConfig configure) throws SQLException { + // TODO: Support proxy + // TODO: Move socket initialisation to separate factory (default & ssl) + public static NativeClient connect(String host, int port, ClickHouseConfig config) throws SQLException { try { SocketAddress endpoint = new InetSocketAddress(host, port); - // TODO support proxy - Socket socket = new Socket(); + Socket socket; + + boolean useSSL = config.ssl(); + if (useSSL) { + LOG.debug("Client works in SSL mode!"); + SSLContext context = new SSLContextBuilder(config).getSSLContext(); + SSLSocketFactory factory = context.getSocketFactory(); + socket = (SSLSocket) factory.createSocket(); + } else { + socket = new Socket(); + } socket.setTcpNoDelay(true); socket.setSendBufferSize(ClickHouseDefines.SOCKET_SEND_BUFFER_BYTES); socket.setReceiveBufferSize(ClickHouseDefines.SOCKET_RECV_BUFFER_BYTES); - socket.setKeepAlive(configure.tcpKeepAlive()); - socket.connect(endpoint, (int) configure.connectTimeout().toMillis()); + socket.setKeepAlive(config.tcpKeepAlive()); + socket.connect(endpoint, (int) config.connectTimeout().toMillis()); + + if (useSSL) ((SSLSocket) socket).startHandshake(); return new NativeClient(socket); - } catch (IOException ex) { + } catch (IOException | + NoSuchAlgorithmException | + KeyStoreException | + CertificateException | + UnrecoverableKeyException | + KeyManagementException ex) { throw new SQLException(ex.getMessage(), ex); } } diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/PermissiveTrustManager.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/PermissiveTrustManager.java new file mode 100644 index 00000000..0ca74bb8 --- /dev/null +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/PermissiveTrustManager.java @@ -0,0 +1,62 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.housepower.client.ssl; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +/** + * An implementation of X509TrustManager that trusts all certificates. + * This class is not secure and should only be used for debugging or + * in a completely isolated environment. + */ +public class PermissiveTrustManager implements X509TrustManager { + + /** + * Checks the client certificates but does nothing. + * It effectively trusts all client certificates. + * + * @param x509Certificates Array of client certificates to check + * @param s The auth type (e.g., "RSA", "DSS") + */ + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { + // Do nothing to bypass client checks + } + + /** + * Checks the server certificates but does nothing. + * It effectively trusts all server certificates. + * + * @param x509Certificates Array of server certificates to check + * @param s The auth type (e.g., "RSA", "DSS") + */ + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { + // Do nothing to bypass server checks + } + + /** + * Returns an empty array of certificate authorities, indicating + * that all certificates are trusted, subject to the + * verification done in the checkClientTrusted and checkServerTrusted methods. + * + * @return An empty X509Certificate array + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } +} diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/SSLContextBuilder.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/SSLContextBuilder.java new file mode 100644 index 00000000..14848169 --- /dev/null +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/client/ssl/SSLContextBuilder.java @@ -0,0 +1,83 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.housepower.client.ssl; + +import com.github.housepower.client.NativeClient; +import com.github.housepower.log.Logger; +import com.github.housepower.log.LoggerFactory; +import com.github.housepower.settings.ClickHouseConfig; +import com.github.housepower.settings.KeyStoreConfig; +import com.github.housepower.settings.SettingKey; + + +import javax.net.ssl.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.*; +import java.security.cert.CertificateException; + +public class SSLContextBuilder { + private static final Logger LOG = LoggerFactory.getLogger(NativeClient.class); + + private ClickHouseConfig config; + + private KeyStoreConfig keyStoreConfig; + + public SSLContextBuilder(ClickHouseConfig config) { + this.config = config; + this.keyStoreConfig = new KeyStoreConfig( + (String) config.settings().get(SettingKey.keyStoreType), + (String) config.settings().get(SettingKey.keyStorePath), + (String) config.settings().get(SettingKey.keyStorePassword) + ); + } + + public SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManager[] trustManager = null; + KeyManager[] keyManager = null; + SecureRandom secureRandom = new SecureRandom(); + String sslMode = config.sslMode(); + LOG.debug("Client SSL mode: '" + sslMode + "'"); + + switch (sslMode) { + case "disabled": + trustManager = new TrustManager[]{new PermissiveTrustManager()}; + keyManager = new KeyManager[]{}; + break; + case "verify_ca": + KeyStore keyStore = KeyStore.getInstance(keyStoreConfig.getKeyStoreType()); + keyStore.load(Files.newInputStream(Paths.get(keyStoreConfig.getKeyStorePath()).toFile().toPath()), + keyStoreConfig.getKeyStorePassword().toCharArray()); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, keyStoreConfig.getKeyStorePassword().toCharArray()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + + trustManager = trustManagerFactory.getTrustManagers(); + keyManager = keyManagerFactory.getKeyManagers(); + break; + default: + throw new IllegalArgumentException("Unknown SSL mode: '" + sslMode + "'"); + } + + sslContext.init(keyManager, trustManager, secureRandom); + return sslContext; + } + +} diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/ClickHouseConfig.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/ClickHouseConfig.java index cece71ec..6bb20b63 100644 --- a/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/ClickHouseConfig.java +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/ClickHouseConfig.java @@ -34,7 +34,6 @@ @Immutable public class ClickHouseConfig implements Serializable { - private final String host; private final List hosts; private final int port; @@ -46,11 +45,14 @@ public class ClickHouseConfig implements Serializable { private final String charset; // use String because Charset is not serializable private final Map settings; private final boolean tcpKeepAlive; + private final boolean ssl; + private final String sslMode; private final String clientName; private ClickHouseConfig(String host, int port, String database, String user, String password, Duration queryTimeout, Duration connectTimeout, boolean tcpKeepAlive, - String charset, String clientName, Map settings) { + boolean ssl, String sslMode, String charset, String clientName, + Map settings) { this.host = host; this.hosts = Arrays.asList(host.split(HOST_DELIMITER)); this.port = port; @@ -60,6 +62,8 @@ private ClickHouseConfig(String host, int port, String database, String user, St this.queryTimeout = queryTimeout; this.connectTimeout = connectTimeout; this.tcpKeepAlive = tcpKeepAlive; + this.ssl = ssl; + this.sslMode = sslMode; this.charset = charset; this.clientName = clientName; this.settings = settings; @@ -97,6 +101,14 @@ public Duration connectTimeout() { return this.connectTimeout; } + public boolean ssl() { + return this.ssl; + } + + public String sslMode() { + return this.sslMode; + } + public Charset charset() { return Charset.forName(charset); } @@ -162,6 +174,18 @@ public ClickHouseConfig withTcpKeepAlive(boolean enable) { .build(); } + public ClickHouseConfig withSSL(boolean enable) { + return Builder.builder(this) + .ssl(enable) + .build(); + } + + public ClickHouseConfig withSSLMode(String mode) { + return Builder.builder(this) + .sslMode(mode) + .build(); + } + public ClickHouseConfig withCharset(Charset charset) { return Builder.builder(this) .charset(charset) @@ -212,6 +236,8 @@ public static final class Builder { private Duration connectTimeout; private Duration queryTimeout; private boolean tcpKeepAlive; + private boolean ssl; + private String sslMode; private Charset charset; private String clientName; private Map settings = new HashMap<>(); @@ -234,6 +260,8 @@ public static Builder builder(ClickHouseConfig cfg) { .queryTimeout(cfg.queryTimeout()) .charset(cfg.charset()) .tcpKeepAlive(cfg.tcpKeepAlive()) + .ssl(cfg.ssl()) + .sslMode(cfg.sslMode()) .clientName(cfg.clientName()) .withSettings(cfg.settings()); } @@ -288,6 +316,16 @@ public Builder tcpKeepAlive(boolean tcpKeepAlive) { return this; } + public Builder ssl(boolean ssl) { + this.withSetting(SettingKey.ssl, ssl); + return this; + } + + public Builder sslMode(String sslMode) { + this.withSetting(SettingKey.ssl, ssl); + return this; + } + public Builder charset(String charset) { this.withSetting(SettingKey.charset, charset); return this; @@ -330,6 +368,8 @@ public ClickHouseConfig build() { this.connectTimeout = (Duration) this.settings.getOrDefault(SettingKey.connect_timeout, Duration.ZERO); this.queryTimeout = (Duration) this.settings.getOrDefault(SettingKey.query_timeout, Duration.ZERO); this.tcpKeepAlive = (boolean) this.settings.getOrDefault(SettingKey.tcp_keep_alive, false); + this.ssl = (boolean) this.settings.getOrDefault(SettingKey.ssl, false); + this.sslMode = (String) this.settings.getOrDefault(SettingKey.sslMode, "disabled"); this.charset = Charset.forName((String) this.settings.getOrDefault(SettingKey.charset, "UTF-8")); this.clientName = (String) this.settings.getOrDefault(SettingKey.client_name, String.format(Locale.ROOT, "%s %s", ClickHouseDefines.NAME, "client")); @@ -337,8 +377,8 @@ public ClickHouseConfig build() { revisit(); purgeSettings(); - return new ClickHouseConfig( - host, port, database, user, password, queryTimeout, connectTimeout, tcpKeepAlive, charset.name(), clientName, settings); + return new ClickHouseConfig(host, port, database, user, password, queryTimeout, connectTimeout, + tcpKeepAlive, ssl, sslMode, charset.name(), clientName, settings); } private void revisit() { @@ -360,6 +400,8 @@ private void purgeSettings() { this.settings.remove(SettingKey.query_timeout); this.settings.remove(SettingKey.connect_timeout); this.settings.remove(SettingKey.tcp_keep_alive); + this.settings.remove(SettingKey.ssl); + this.settings.remove(SettingKey.sslMode); this.settings.remove(SettingKey.charset); this.settings.remove(SettingKey.client_name); } diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/KeyStoreConfig.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/KeyStoreConfig.java new file mode 100644 index 00000000..3e3351c5 --- /dev/null +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/KeyStoreConfig.java @@ -0,0 +1,42 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.housepower.settings; + +public class KeyStoreConfig { + private String keyStoreType; + private String keyStorePath; + private String keyStorePassword; + + public KeyStoreConfig() { + } + + public KeyStoreConfig(String keyStoreType, String keyStorePath, String keyStorePassword) { + this.keyStoreType = keyStoreType; + this.keyStorePath = keyStorePath; + this.keyStorePassword = keyStorePassword; + } + + public String getKeyStorePath() { + return this.keyStorePath; + } + + public String getKeyStorePassword() { + return this.keyStorePassword; + } + + public String getKeyStoreType() { + return this.keyStoreType; + } +} diff --git a/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/SettingKey.java b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/SettingKey.java index 068fe3b6..47ed5720 100644 --- a/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/SettingKey.java +++ b/clickhouse-native-jdbc/src/main/java/com/github/housepower/settings/SettingKey.java @@ -803,7 +803,6 @@ public class SettingKey implements Serializable { .withDescription("identify who you are, it will record in system.query_log") .build(); - public static SettingKey port = SettingKey.builder() .withName("port") .withType(SettingType.Int32) @@ -830,6 +829,36 @@ public class SettingKey implements Serializable { .isSecret() .build(); + public static SettingKey ssl = SettingKey.builder() + .withName("ssl") + .withType(SettingType.Bool) + .withDescription("Establish secure connection: True or False") + .build(); + + public static SettingKey sslMode = SettingKey.builder() + .withName("ssl_mode") + .withType(SettingType.UTF8) + .withDescription("Verify or not certificate: disabled (don't verify), verify_ca (verify)") + .build(); + + public static SettingKey keyStoreType = SettingKey.builder() + .withName("key_store_type") + .withType(SettingType.UTF8) + .withDescription("Type of the KeyStore. Currently, only JKS is supported.") + .build(); + + public static SettingKey keyStorePath = SettingKey.builder() + .withName("key_store_path") + .withType(SettingType.UTF8) + .withDescription("Path to the KeyStore file.") + .build(); + + public static SettingKey keyStorePassword = SettingKey.builder() + .withName("key_store_password") + .withType(SettingType.UTF8) + .withDescription("Password for the KeyStore.") + .build(); + public static SettingKey query_timeout = SettingKey.builder() .withName("query_timeout") .withType(SettingType.Seconds) @@ -847,17 +876,17 @@ public class SettingKey implements Serializable { .build(); public static SettingKey allow_experimental_map_type = SettingKey.builder() - .withName("allow_experimental_map_type") - .withType(SettingType.Int32) - .withDescription("Allow Map field to be use") - .build(); + .withName("allow_experimental_map_type") + .withType(SettingType.Int32) + .withDescription("Allow Map field to be use") + .build(); public static SettingKey query_id = SettingKey.builder() .withName("query_id") .withType(SettingType.UTF8) .withDescription("set current session query") .build(); - + public static Builder builder() { return new Builder(); } diff --git a/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/AbstractITest.java b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/AbstractITest.java index 7175d06b..8438fd00 100644 --- a/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/AbstractITest.java +++ b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/AbstractITest.java @@ -41,27 +41,36 @@ public abstract class AbstractITest implements Serializable { protected static final String CLICKHOUSE_PASSWORD = SystemUtil.loadProp("CLICKHOUSE_PASSWORD", ""); protected static final String CLICKHOUSE_DB = SystemUtil.loadProp("CLICKHOUSE_DB", ""); - protected static final int CLICKHOUSE_GRPC_PORT = 9100; protected static final int CLICKHOUSE_HTTP_PORT = 8123; + protected static final int CLICKHOUSE_HTTPS_PORT = 8443; protected static final int CLICKHOUSE_NATIVE_PORT = 9000; + protected static final int CLICKHOUSE_NATIVE_SECURE_PORT = 9440; @Container public static ClickHouseContainer container = new ClickHouseContainer(CLICKHOUSE_IMAGE) .withEnv("CLICKHOUSE_USER", CLICKHOUSE_USER) .withEnv("CLICKHOUSE_PASSWORD", CLICKHOUSE_PASSWORD) .withEnv("CLICKHOUSE_DB", CLICKHOUSE_DB) - .withExposedPorts(CLICKHOUSE_HTTP_PORT, CLICKHOUSE_NATIVE_PORT, CLICKHOUSE_GRPC_PORT) - .withCopyFileToContainer(MountableFile.forClasspathResource("grpc_config.xml"), "/etc/clickhouse-server/config.d/grpc_config.xml"); + .withExposedPorts(CLICKHOUSE_HTTP_PORT, + CLICKHOUSE_HTTPS_PORT, + CLICKHOUSE_NATIVE_PORT, + CLICKHOUSE_NATIVE_SECURE_PORT) + .withCopyFileToContainer(MountableFile.forClasspathResource("clickhouse/config/config.xml"), + "/etc/clickhouse-server/config.xml") + .withCopyFileToContainer(MountableFile.forClasspathResource("clickhouse/config/users.xml"), + "/etc/clickhouse-server/users.xml") + .withCopyFileToContainer(MountableFile.forClasspathResource("clickhouse/server.key"), + "/etc/clickhouse-server/server.key") + .withCopyFileToContainer(MountableFile.forClasspathResource("clickhouse/server.crt"), + "/etc/clickhouse-server/server.crt"); protected static String CK_HOST; protected static int CK_PORT; - protected static int CK_GRPC_PORT; @BeforeAll public static void extractContainerInfo() { CK_HOST = container.getHost(); CK_PORT = container.getMappedPort(CLICKHOUSE_NATIVE_PORT); - CK_GRPC_PORT = container.getMappedPort(CLICKHOUSE_GRPC_PORT); } /** @@ -72,28 +81,39 @@ protected String getJdbcUrl() { } protected String getJdbcUrl(Object... params) { - StringBuilder sb = new StringBuilder(); - int port = container.getMappedPort(CLICKHOUSE_NATIVE_PORT); - sb.append("jdbc:clickhouse://").append(container.getHost()).append(":").append(port); - if (StrUtil.isNotEmpty(CLICKHOUSE_DB)) { - sb.append("/").append(container.getDatabaseName()); - } + StringBuilder settingsStringBuilder = new StringBuilder(); for (int i = 0; i + 1 < params.length; i++) { - sb.append(i == 0 ? "?" : "&"); - sb.append(params[i]).append("=").append(params[i + 1]); + settingsStringBuilder.append(i == 0 ? "?" : "&"); + settingsStringBuilder.append(params[i]).append("=").append(params[i + 1]); + } + + StringBuilder mainStringBuilder = new StringBuilder(); + int port = 0; + if (settingsStringBuilder.indexOf("ssl=true") == -1) { + port = container.getMappedPort(CLICKHOUSE_NATIVE_PORT); + } else { + port = container.getMappedPort(CLICKHOUSE_NATIVE_SECURE_PORT); } + mainStringBuilder.append("jdbc:clickhouse://").append(container.getHost()).append(":").append(port); + if (StrUtil.isNotEmpty(CLICKHOUSE_DB)) { + mainStringBuilder.append("/").append(container.getDatabaseName()); + } + + // Add settings + mainStringBuilder.append(settingsStringBuilder); + // Add user - sb.append(params.length < 2 ? "?" : "&"); - sb.append("user=").append(container.getUsername()); + mainStringBuilder.append(params.length < 2 ? "?" : "&"); + mainStringBuilder.append("user=").append(container.getUsername()); // Add password // ignore blank password if (!StrUtil.isBlank(CLICKHOUSE_PASSWORD)) { - sb.append("&password=").append(container.getPassword()); + mainStringBuilder.append("&password=").append(container.getPassword()); } - return sb.toString(); + return mainStringBuilder.toString(); } // this method should be synchronized diff --git a/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/ClickHouseConnectionITest.java b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/ClickHouseConnectionITest.java index 20bd3639..4db3fc9e 100644 --- a/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/ClickHouseConnectionITest.java +++ b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/ClickHouseConnectionITest.java @@ -14,13 +14,53 @@ package com.github.housepower.jdbc; +import com.github.housepower.jdbc.tool.LocalKeyStoreConfig; +import com.github.housepower.settings.KeyStoreConfig; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import java.sql.ResultSet; + +import static org.junit.jupiter.api.Assertions.*; public class ClickHouseConnectionITest extends AbstractITest { + @Test + void ping() throws Exception { + withNewConnection(connection -> { + withStatement(connection, stmt -> { + ResultSet resultSet = stmt.executeQuery("SELECT 1"); + assertTrue(resultSet.next()); + }); + }); + } + + @Test + void pingWithSecureConnection() throws Exception { + withNewConnection(connection -> { + withStatement(connection, stmt -> { + ResultSet resultSet = stmt.executeQuery("SELECT 1"); + assertTrue(resultSet.next()); + }); + }, "ssl", "true", + "ssl_mode", "disabled"); + } + + @Test + void pingWithSecureConnectionAndVerification() throws Exception { + KeyStoreConfig keyStoreConfig = new LocalKeyStoreConfig(); + + withNewConnection(connection -> { + withStatement(connection, stmt -> { + ResultSet resultSet = stmt.executeQuery("SELECT 1"); + assertTrue(resultSet.next()); + }); + }, "ssl", "true", + "ssl_mode", "verify_ca", + "key_store_type", keyStoreConfig.getKeyStoreType(), + "key_store_path", keyStoreConfig.getKeyStorePath(), + "key_store_password", keyStoreConfig.getKeyStorePassword()); + } + @Test public void testCatalog() throws Exception { withNewConnection(connection -> { diff --git a/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/tool/LocalKeyStoreConfig.java b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/tool/LocalKeyStoreConfig.java new file mode 100644 index 00000000..d0daead1 --- /dev/null +++ b/clickhouse-native-jdbc/src/test/java/com/github/housepower/jdbc/tool/LocalKeyStoreConfig.java @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.housepower.jdbc.tool; + +import com.github.housepower.settings.KeyStoreConfig; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; + +public class LocalKeyStoreConfig extends KeyStoreConfig { + @Override + public String getKeyStorePath() { + return getKeyStoreAbsolutePath(); + } + + @Override + public String getKeyStoreType() { + return KeyStore.getDefaultType(); + } + + @Override + public String getKeyStorePassword() { + return "mypassword"; + } + + private String getKeyStoreAbsolutePath() { + Path jksPath = Paths.get("src", "test", "resources", "clickhouse", "server.jks"); + return jksPath.toFile().getAbsolutePath(); + } +} diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/config/config.xml b/clickhouse-native-jdbc/src/test/resources/clickhouse/config/config.xml new file mode 100644 index 00000000..202070de --- /dev/null +++ b/clickhouse-native-jdbc/src/test/resources/clickhouse/config/config.xml @@ -0,0 +1,1198 @@ + + + + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + + 1000M + 10 + + + + + + + + + + + + + + 8123 + + + 9000 + + + 9004 + + + 9005 + + + 8443 + + + 9440 + + + + + + 9009 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4096 + + + 3 + + + + + false + + + /path/to/ssl_cert_file + /path/to/ssl_key_file + + + false + + + /path/to/ssl_ca_cert_file + + + deflate + + + medium + + + -1 + -1 + + + false + + + + + + + /etc/clickhouse-server/server.crt + /etc/clickhouse-server/server.key + + + none + true + true + sslv2,sslv3 + true + + + + true + true + sslv2,sslv3 + true + + + + RejectCertificateHandler + + + + + + + + + 100 + + + 0 + + + + 10000 + + + 0.9 + + + 4194304 + + + 0 + + + + + + 8589934592 + + + 5368709120 + + + + 1000 + + + 134217728 + + + /var/lib/clickhouse/ + + + /var/lib/clickhouse/tmp/ + + + + + + /var/lib/clickhouse/user_files/ + + + + + + + + + + + + + users.xml + + + + /var/lib/clickhouse/access/ + + + + + + + default + + + + + + + + + + + + default + + + + + + + + + true + + + false + + ' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + apt install --no-install-recommends -f ./clickhouse-jdbc-bridge_$PKG_VER-1_all.deb + clickhouse-jdbc-bridge & + + * [CentOS/RHEL] + export MVN_URL=https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc-bridge + export PKG_VER=$(curl -sL $MVN_URL/maven-metadata.xml | grep '' | sed -e 's|.*>\(.*\)<.*|\1|') + wget https://github.com/ClickHouse/clickhouse-jdbc-bridge/releases/download/v$PKG_VER/clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + yum localinstall -y clickhouse-jdbc-bridge-$PKG_VER-1.noarch.rpm + clickhouse-jdbc-bridge & + + Please refer to https://github.com/ClickHouse/clickhouse-jdbc-bridge#usage for more information. + ]]> + + + + + + + + + + + + + + + + localhost + 9000 + + + + + + + + + localhost + 9000 + + + + + localhost + 9000 + + + + + + + 127.0.0.1 + 9000 + + + + + 127.0.0.2 + 9000 + + + + + + true + + 127.0.0.1 + 9000 + + + + true + + 127.0.0.2 + 9000 + + + + + + + localhost + 9440 + 1 + + + + + + + localhost + 9000 + + + + + localhost + 1 + + + + + + + + + + + + + + + + + + + + + + + + 3600 + + + + 3600 + + + 60 + + + + + + + + + + + + + system + query_log
+ + toYYYYMM(event_date) + + + + + + 7500 +
+ + + + system + trace_log
+ + toYYYYMM(event_date) + 7500 +
+ + + + system + query_thread_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + query_views_log
+ toYYYYMM(event_date) + 7500 +
+ + + + system + part_log
+ toYYYYMM(event_date) + 7500 +
+ + + + + + system + metric_log
+ 7500 + 1000 +
+ + + + system + asynchronous_metric_log
+ + 7000 +
+ + + + + + engine MergeTree + partition by toYYYYMM(finish_date) + order by (finish_date, finish_time_us, trace_id) + + system + opentelemetry_span_log
+ 7500 +
+ + + + + system + crash_log
+ + + 1000 +
+ + + + + + + + + + + + + + + + + + + *_dictionary.xml + + + + + + + + + + + + + + /clickhouse/task_queue/ddl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + click_cost + any + + 0 + 3600 + + + 86400 + 60 + + + + max + + 0 + 60 + + + 3600 + 300 + + + 86400 + 3600 + + + + + + /var/lib/clickhouse/format_schemas/ + + + + + hide encrypt/decrypt arguments + ((?:aes_)?(?:encrypt|decrypt)(?:_mysql)?)\s*\(\s*(?:'(?:\\'|.)+'|.*?)\s*\) + + \1(???) + + + + + + + + + + false + + false + + + https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277 + + + + + + + +
\ No newline at end of file diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/config/users.xml b/clickhouse-native-jdbc/src/test/resources/clickhouse/config/users.xml new file mode 100644 index 00000000..c7cf0f5b --- /dev/null +++ b/clickhouse-native-jdbc/src/test/resources/clickhouse/config/users.xml @@ -0,0 +1,123 @@ + + + + + + + + + + 10000000000 + + + random + + + + + 1 + + + + + + + + + + + + + ::/0 + + + + default + + + default + + + + + + + + + + + + + + 3600 + + + 0 + 0 + 0 + 0 + 0 + + + + \ No newline at end of file diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/server.crt b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.crt new file mode 100644 index 00000000..ed279bd9 --- /dev/null +++ b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUGiof/tcvWR9ITSWwONatZC68ys0wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDgyNjIxMTczN1oXDTI0MDgy +NTIxMTczN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAmC1y+HO3QzDIk5DnK6ouUoxCIH6c/zeT/uYSCmvUQU1l +rEWQ5+U/iEAQkmIyK/7yvyHromp+ZfzoVlDANF/5d3OaRcXxLKjVBf1xxELlEzXR +Jw2Vx3KnrxO0P9RXwmuc+n8alYZwxIbt1IPlqGJzgUHd3cFcjXe7Z8dnhAO3zekr +UDRP028LdIrLPGpBanHNKiJv73o3QrNJKLw9l5kDPMlmrXb/9uot4xxYj6L3Kz84 +lACApL04tkH3+W6vadwdzWjPEvFwlLIoRBV1YXnzKUlgNwey6PLDo5jE+2AXR433 +6UPHZJ5XNTtJ1zSe+wiC8xqA5zgv2f/S6KNrGAZ4JQIDAQABo1MwUTAdBgNVHQ4E +FgQUucBNLF7S0DEqgJYTpD0Y6rKZx6kwHwYDVR0jBBgwFoAUucBNLF7S0DEqgJYT +pD0Y6rKZx6kwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAN9i6 +xLrh4DyJOV1KsIM1nrWq1P5wZjQny9i4TmU6doGXIiTIAipXyL8liX5/3qVGZkBb +WYWgQTdfjjZJENSawxUiIQnsvqO83dyzRaMg+yKRUPf6MZTQDxjgmK3BZ6qmMLbj +BhMYAA5r6b6oTW5pmqo+wQxP7doZOiX/Xcjw2iHBtL1jy4rEwsEoOYpH7u0ywWiQ +9WsaYNcm+b452MJBYWeRqxJx4gtvcBFAii2Win5AT/SUTtHQcQKrDxv+osGS5vZj +v+2LxCCNfTmJfIsGPSsyiqulvzzn4xcNE6ETzAcvudx+to9YfUogJYmhsQpc/CBa +7DYS2q7Uf7a7d7xZDw== +-----END CERTIFICATE----- diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/server.jks b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.jks new file mode 100644 index 00000000..a83d56c2 Binary files /dev/null and b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.jks differ diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/server.key b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.key new file mode 100644 index 00000000..357188fc --- /dev/null +++ b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCYLXL4c7dDMMiT +kOcrqi5SjEIgfpz/N5P+5hIKa9RBTWWsRZDn5T+IQBCSYjIr/vK/Ieuian5l/OhW +UMA0X/l3c5pFxfEsqNUF/XHEQuUTNdEnDZXHcqevE7Q/1FfCa5z6fxqVhnDEhu3U +g+WoYnOBQd3dwVyNd7tnx2eEA7fN6StQNE/Tbwt0iss8akFqcc0qIm/vejdCs0ko +vD2XmQM8yWatdv/26i3jHFiPovcrPziUAICkvTi2Qff5bq9p3B3NaM8S8XCUsihE +FXVhefMpSWA3B7Lo8sOjmMT7YBdHjffpQ8dknlc1O0nXNJ77CILzGoDnOC/Z/9Lo +o2sYBnglAgMBAAECggEAFJKXB48+jWb+brNOX+D5XdqCpA70iCzfepG9ivV0iUF+ +hxwT0MMgDs+OY05tdvTX+fk1eExfpcew3IkSeuImARKP9B0kPhky90TXSPo8KsKB +8dQh1V1NiFsoaTVP30OaF2Pwgu9dC7csAX4KoZ7G+7NHsbokGic/dB0JLwKA/4/v +vSAEpyZpoCEK9AjfqkFNYHTtuAmuIfBvHGcDdcDHsCh+c1MevqTlL5wBElr8RKJ7 +Vxb4eApwwWLB2aQnmcyCOpJQtb/XpuMNZ5/IsBNVmUDCRNYbKCFx4Ts/mwVbL1jz +e4YD1DKiEtZ9Wzy7saZFIM2L7k8JuUomGucuqUHaLwKBgQDWnFLtwB7Lcbmv3QWz +CDrNqFOTTrlLEbLgawXeCFyuL/QKSiI7VLGYo3FfCBMKE9bQf11AYKlP6dhW7f/G +z0iHuy4wKhPHPKDmsJT3lnJlshayxjyr5RfT29bfz0vw/UJ+U4bEs46rTkEi6ZyW +pCopD+az0BvyidkjQAMjbBW1HwKBgQC1hrOJ8eZkX5tCflRNVqmuX6QkINOLhErw +4I41i0oaJVD0KU3hLHtTD57bn36q8tWuaFrubUir9OSz9r1nLCc4uu2OUUn0t9sy +IvoG4JHWHkFdaOxGheWFdoCkTRnyU8mb4196h7C2MIQ6a6SwuaF9y9/p7l1/JjWu +PI6vq1kGOwKBgQCGWwWb7Iwa587NJ7z6sWtG91ujPETKl4D5+GaK84c6UbEhg/nc +VRB+M8y1JvPsejEhBKuXsywsaITVH1ji2UBaITgwVRdewzkkU2ZffmOOASkusOao +4trA+r+SDFBJxfQL7DTSDmuCGZKzzbcHpCz02gyfg+kLNXuoEtokIfWRFwKBgGFR +YOmgfTLsqrEgRxPbVUa90aLo0mDmwMKYsMT18vlHbjon9q+0iD1Ej5cQz/jYDUTe +f3l5r085EG+G5Y3tdu2MEZWN8Qc4llQvujl7pdPUDpkEij9Yw28k09zB1Ro8X0aq +xGJNYqiaJBmp4fY43uIxLc8dUpS7KGZL4vc89pJHAoGAET1i4vxlD6BMgwJCyCmc +afJ5Eh4WrrBYM+E4emGS0/pgeRkjRk5cCaKJ/IEO8x2uxr/EGmlZa+ki8ETc8/9m +LG9sX9za2lg9tiZW8A676hheVHe4IOIjkldey9ovxm8ar12PECwgkkJ6WXeG4uzJ +lqaPsbBiOzZvBiBBJLpydYY= +-----END PRIVATE KEY----- diff --git a/clickhouse-native-jdbc/src/test/resources/clickhouse/server.p12 b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.p12 new file mode 100644 index 00000000..eb7c886c Binary files /dev/null and b/clickhouse-native-jdbc/src/test/resources/clickhouse/server.p12 differ diff --git a/clickhouse-native-jdbc/src/test/resources/grpc_config.xml b/clickhouse-native-jdbc/src/test/resources/grpc_config.xml deleted file mode 100644 index a6416daf..00000000 --- a/clickhouse-native-jdbc/src/test/resources/grpc_config.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - 9100 - - false - - - /path/to/ssl_cert_file - /path/to/ssl_key_file - - - false - - - /path/to/ssl_ca_cert_file - - - deflate - - - medium - - - -1 - -1 - - - true - - diff --git a/clickhouse-native-jdbc/src/test/resources/keymanagement/bin/generate.sh b/clickhouse-native-jdbc/src/test/resources/keymanagement/bin/generate.sh new file mode 100644 index 00000000..eb93e96a --- /dev/null +++ b/clickhouse-native-jdbc/src/test/resources/keymanagement/bin/generate.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +# Versions: +# Windows 10 +# OpenSSL Version: OpenSSL 3.1.2 1 +# Keytool Version: openjdk-17.0.2 + +KEY_FILE=server.key +CRT_FILE=server.crt +PKCS12_FILE=server.p12 +JKS_FILE=server.jks +PASSWORD=mypassword +ALIAS=myalias + +echo "Generating the private key and certificate..." +openssl req -subj "//CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout ${KEY_FILE} -out ${CRT_FILE} +if [ $? -ne 0 ]; then + echo "Failed to generate the private key and certificate." + exit 1 +fi + +echo "Converting to PKCS12 format..." +openssl pkcs12 -export -in ${CRT_FILE} -inkey ${KEY_FILE} -out ${PKCS12_FILE} -name ${ALIAS} -password pass:${PASSWORD} +if [ $? -ne 0 ]; then + echo "Failed to convert to PKCS12 format." + exit 1 +fi + +echo "Importing keystore ${PKCS12_FILE} to ${JKS_FILE}..." +keytool -importkeystore\ + -srckeystore ${PKCS12_FILE}\ + -srcstoretype PKCS12\ + -srcstorepass ${PASSWORD}\ + -destkeystore ${JKS_FILE}\ + -deststoretype JKS\ + -deststorepass ${PASSWORD} +if [ $? -ne 0 ]; then + echo "Failed to import keystore." + exit 1 +fi + +echo "Done!" \ No newline at end of file