diff --git a/external-service-impl/rest/pom.xml b/external-service-impl/rest/pom.xml
index fbc02b6dfb86c..5287a25440cc8 100644
--- a/external-service-impl/rest/pom.xml
+++ b/external-service-impl/rest/pom.xml
@@ -38,13 +38,6 @@
org.glassfish.jersey.inject
jersey-hk2
runtime
-
-
-
- jakarta.annotation
- jakarta.annotation-api
-
-
org.apache.iotdb
@@ -87,11 +80,6 @@
jakarta.validation
jakarta.validation-api
-
-
- jakarta.annotation
- jakarta.annotation-api
-
diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java
index acba4e3039009..506facdb4ce25 100644
--- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java
+++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java
@@ -21,6 +21,7 @@
import org.apache.iotdb.externalservice.api.IExternalService;
import org.apache.iotdb.rest.i18n.RestMessages;
import org.apache.iotdb.rest.protocol.filter.ApiOriginFilter;
+import org.apache.iotdb.rpc.RpcSslUtils;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
@@ -52,6 +53,7 @@ private void startSSL(
String trustStorePath,
String keyStorePwd,
String trustStorePwd,
+ String sslProtocol,
int idleTime,
boolean clientAuth) {
server = new Server();
@@ -61,6 +63,7 @@ private void startSSL(
httpsConfig.addCustomizer(new SecureRequestCustomizer());
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
+ configureSSL(sslContextFactory, sslProtocol);
sslContextFactory.setKeyStorePath(keyStorePath);
sslContextFactory.setKeyStorePassword(keyStorePwd);
if (clientAuth) {
@@ -125,6 +128,7 @@ public void start() {
config.getTrustStorePath(),
config.getKeyStorePwd(),
config.getTrustStorePwd(),
+ config.getSslProtocol(),
config.getIdleTimeoutInSeconds(),
config.isClientAuth());
} else {
@@ -142,4 +146,9 @@ public void stop() {
server.destroy();
}
}
+
+ private void configureSSL(SslContextFactory.Server sslContextFactory, String sslProtocol) {
+ String protocol = RpcSslUtils.normalizeProtocol(sslProtocol);
+ sslContextFactory.setProtocol(protocol);
+ }
}
diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppBaseConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppBaseConfig.java
index e0758de70c952..69b2e540e9682 100644
--- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppBaseConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppBaseConfig.java
@@ -120,6 +120,10 @@ protected final void setProperty(@NotNull String key, String value) {
}
}
+ public final String getProperty(@NotNull String key, String defaultValue) {
+ return properties.getProperty(key, defaultValue);
+ }
+
/** Create an instance but with empty properties. */
public abstract MppBaseConfig emptyClone();
}
diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java
index c7ff02002dc58..dc6dda073169c 100644
--- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java
@@ -635,6 +635,12 @@ public CommonConfig setEnforceStrongPassword(boolean enforceStrongPassword) {
return this;
}
+ @Override
+ public CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL) {
+ setProperty("enable_thrift_ssl", String.valueOf(enableThriftClientSSL));
+ return this;
+ }
+
@Override
public CommonConfig setEnableInternalSSL(boolean enableInternalSSL) {
setProperty("enable_internal_ssl", String.valueOf(enableInternalSSL));
@@ -665,6 +671,12 @@ public CommonConfig setTrustStorePwd(String trustStorePwd) {
return this;
}
+ @Override
+ public CommonConfig setSslProtocol(String sslProtocol) {
+ setProperty("ssl_protocol", sslProtocol);
+ return this;
+ }
+
@Override
public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion) {
setProperty("datanode_memory_proportion", datanodeMemoryProportion);
diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java
index 5ed27b2f5024e..67774979d28ee 100644
--- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java
@@ -659,6 +659,13 @@ public CommonConfig setEnforceStrongPassword(boolean enforceStrongPassword) {
return this;
}
+ @Override
+ public CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL) {
+ cnConfig.setEnableThriftClientSSL(enableThriftClientSSL);
+ dnConfig.setEnableThriftClientSSL(enableThriftClientSSL);
+ return this;
+ }
+
@Override
public CommonConfig setEnableInternalSSL(boolean enableInternalSSL) {
cnConfig.setEnableInternalSSL(enableInternalSSL);
@@ -694,6 +701,13 @@ public CommonConfig setTrustStorePwd(String trustStorePwd) {
return this;
}
+ @Override
+ public CommonConfig setSslProtocol(String sslProtocol) {
+ cnConfig.setSslProtocol(sslProtocol);
+ dnConfig.setSslProtocol(sslProtocol);
+ return this;
+ }
+
@Override
public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion) {
dnConfig.setDatanodeMemoryProportion(datanodeMemoryProportion);
diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java
index 0e7eefb3a4188..7bcee29be6e91 100644
--- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java
+++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java
@@ -614,6 +614,83 @@ public void cleanClusterEnvironment() {
clusterConfig = new MppClusterConfig();
}
+ private boolean isThriftClientSSLEnabled() {
+ return Boolean.parseBoolean(getDataNodeCommonConfigProperty("enable_thrift_ssl", "false"));
+ }
+
+ private String getDataNodeCommonConfigProperty(final String key, final String defaultValue) {
+ return ((MppCommonConfig) clusterConfig.getDataNodeCommonConfig())
+ .getProperty(key, defaultValue);
+ }
+
+ private String getClientSSLProtocol() {
+ return getDataNodeCommonConfigProperty("ssl_protocol", SessionConfig.DEFAULT_SSL_PROTOCOL);
+ }
+
+ private Properties constructConnectionProperties(
+ final String username, final String password, final String sqlDialect) {
+ final Properties info = BaseEnv.constructProperties(username, password, sqlDialect);
+ if (isThriftClientSSLEnabled()) {
+ info.put(Config.USE_SSL, Boolean.TRUE.toString());
+ putIfPresent(
+ info, Config.TRUST_STORE, getDataNodeCommonConfigProperty("trust_store_path", ""));
+ putIfPresent(
+ info, Config.TRUST_STORE_PWD, getDataNodeCommonConfigProperty("trust_store_pwd", ""));
+ putIfPresent(info, Config.SSL_PROTOCOL, getClientSSLProtocol());
+ }
+ return info;
+ }
+
+ private void putIfPresent(final Properties properties, final String key, final String value) {
+ if (value != null && !value.isEmpty()) {
+ properties.put(key, value);
+ }
+ }
+
+ private Session.Builder configureClientSSL(final Session.Builder builder) {
+ if (isThriftClientSSLEnabled()) {
+ builder
+ .useSSL(true)
+ .trustStore(getDataNodeCommonConfigProperty("trust_store_path", ""))
+ .trustStorePwd(getDataNodeCommonConfigProperty("trust_store_pwd", ""))
+ .sslProtocol(getClientSSLProtocol());
+ }
+ return builder;
+ }
+
+ private TableSessionBuilder configureClientSSL(final TableSessionBuilder builder) {
+ if (isThriftClientSSLEnabled()) {
+ builder
+ .useSSL(true)
+ .trustStore(getDataNodeCommonConfigProperty("trust_store_path", ""))
+ .trustStorePwd(getDataNodeCommonConfigProperty("trust_store_pwd", ""))
+ .sslProtocol(getClientSSLProtocol());
+ }
+ return builder;
+ }
+
+ private SessionPool.Builder configureClientSSL(final SessionPool.Builder builder) {
+ if (isThriftClientSSLEnabled()) {
+ builder
+ .useSSL(true)
+ .trustStore(getDataNodeCommonConfigProperty("trust_store_path", ""))
+ .trustStorePwd(getDataNodeCommonConfigProperty("trust_store_pwd", ""))
+ .sslProtocol(getClientSSLProtocol());
+ }
+ return builder;
+ }
+
+ private TableSessionPoolBuilder configureClientSSL(final TableSessionPoolBuilder builder) {
+ if (isThriftClientSSLEnabled()) {
+ builder
+ .useSSL(true)
+ .trustStore(getDataNodeCommonConfigProperty("trust_store_path", ""))
+ .trustStorePwd(getDataNodeCommonConfigProperty("trust_store_pwd", ""))
+ .sslProtocol(getClientSSLProtocol());
+ }
+ return builder;
+ }
+
@Override
public Connection getConnection(
final String username, final String password, final String sqlDialect) throws SQLException {
@@ -695,7 +772,8 @@ public ISession getSessionConnection() throws IoTDBConnectionException {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
final Session session =
- new Session.Builder().host(dataNode.getIp()).port(dataNode.getPort()).build();
+ configureClientSSL(new Session.Builder().host(dataNode.getIp()).port(dataNode.getPort()))
+ .build();
session.open();
return session;
}
@@ -705,10 +783,11 @@ public ISession getSessionConnection(ZoneId zoneId) throws IoTDBConnectionExcept
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
final Session session =
- new Session.Builder()
- .host(dataNode.getIp())
- .port(dataNode.getPort())
- .zoneId(zoneId)
+ configureClientSSL(
+ new Session.Builder()
+ .host(dataNode.getIp())
+ .port(dataNode.getPort())
+ .zoneId(zoneId))
.build();
session.open();
return session;
@@ -720,11 +799,12 @@ public ISession getSessionConnection(final String userName, final String passwor
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
final Session session =
- new Session.Builder()
- .host(dataNode.getIp())
- .port(dataNode.getPort())
- .username(userName)
- .password(password)
+ configureClientSSL(
+ new Session.Builder()
+ .host(dataNode.getIp())
+ .port(dataNode.getPort())
+ .username(userName)
+ .password(password))
.build();
session.open();
return session;
@@ -734,16 +814,17 @@ public ISession getSessionConnection(final String userName, final String passwor
public ISession getSessionConnection(final List nodeUrls)
throws IoTDBConnectionException {
final Session session =
- new Session.Builder()
- .nodeUrls(nodeUrls)
- .username(SessionConfig.DEFAULT_USER)
- .password(SessionConfig.DEFAULT_PASSWORD)
- .fetchSize(SessionConfig.DEFAULT_FETCH_SIZE)
- .zoneId(null)
- .thriftDefaultBufferSize(SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY)
- .thriftMaxFrameSize(SessionConfig.DEFAULT_MAX_FRAME_SIZE)
- .enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE)
- .version(SessionConfig.DEFAULT_VERSION)
+ configureClientSSL(
+ new Session.Builder()
+ .nodeUrls(nodeUrls)
+ .username(SessionConfig.DEFAULT_USER)
+ .password(SessionConfig.DEFAULT_PASSWORD)
+ .fetchSize(SessionConfig.DEFAULT_FETCH_SIZE)
+ .zoneId(null)
+ .thriftDefaultBufferSize(SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY)
+ .thriftMaxFrameSize(SessionConfig.DEFAULT_MAX_FRAME_SIZE)
+ .enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE)
+ .version(SessionConfig.DEFAULT_VERSION))
.build();
session.open();
return session;
@@ -753,8 +834,9 @@ public ISession getSessionConnection(final List nodeUrls)
public ITableSession getTableSessionConnection() throws IoTDBConnectionException {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new TableSessionBuilder()
- .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ return configureClientSSL(
+ new TableSessionBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString())))
.build();
}
@@ -763,10 +845,11 @@ public ITableSession getTableSessionConnection(String userName, String password)
throws IoTDBConnectionException {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new TableSessionBuilder()
- .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
- .username(userName)
- .password(password)
+ return configureClientSSL(
+ new TableSessionBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ .username(userName)
+ .password(password))
.build();
}
@@ -775,23 +858,25 @@ public ITableSession getTableSessionConnectionWithDB(final String database)
throws IoTDBConnectionException {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new TableSessionBuilder()
- .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
- .database(database)
+ return configureClientSSL(
+ new TableSessionBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ .database(database))
.build();
}
public ITableSession getTableSessionConnection(List nodeUrls)
throws IoTDBConnectionException {
- return new TableSessionBuilder()
- .nodeUrls(nodeUrls)
- .username(SessionConfig.DEFAULT_USER)
- .password(SessionConfig.DEFAULT_PASSWORD)
- .fetchSize(SessionConfig.DEFAULT_FETCH_SIZE)
- .zoneId(null)
- .thriftDefaultBufferSize(SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY)
- .thriftMaxFrameSize(SessionConfig.DEFAULT_MAX_FRAME_SIZE)
- .enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE)
+ return configureClientSSL(
+ new TableSessionBuilder()
+ .nodeUrls(nodeUrls)
+ .username(SessionConfig.DEFAULT_USER)
+ .password(SessionConfig.DEFAULT_PASSWORD)
+ .fetchSize(SessionConfig.DEFAULT_FETCH_SIZE)
+ .zoneId(null)
+ .thriftDefaultBufferSize(SessionConfig.DEFAULT_INITIAL_BUFFER_CAPACITY)
+ .thriftMaxFrameSize(SessionConfig.DEFAULT_MAX_FRAME_SIZE)
+ .enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE))
.build();
}
@@ -799,12 +884,13 @@ public ITableSession getTableSessionConnection(List nodeUrls)
public ISessionPool getSessionPool(final int maxSize) {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new SessionPool.Builder()
- .host(dataNode.getIp())
- .port(dataNode.getPort())
- .user(SessionConfig.DEFAULT_USER)
- .password(SessionConfig.DEFAULT_PASSWORD)
- .maxSize(maxSize)
+ return configureClientSSL(
+ new SessionPool.Builder()
+ .host(dataNode.getIp())
+ .port(dataNode.getPort())
+ .user(SessionConfig.DEFAULT_USER)
+ .password(SessionConfig.DEFAULT_PASSWORD)
+ .maxSize(maxSize))
.build();
}
@@ -812,11 +898,12 @@ public ISessionPool getSessionPool(final int maxSize) {
public ITableSessionPool getTableSessionPool(final int maxSize) {
final DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new TableSessionPoolBuilder()
- .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
- .user(SessionConfig.DEFAULT_USER)
- .password(SessionConfig.DEFAULT_PASSWORD)
- .maxSize(maxSize)
+ return configureClientSSL(
+ new TableSessionPoolBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ .user(SessionConfig.DEFAULT_USER)
+ .password(SessionConfig.DEFAULT_PASSWORD)
+ .maxSize(maxSize))
.build();
}
@@ -824,12 +911,13 @@ public ITableSessionPool getTableSessionPool(final int maxSize) {
public ITableSessionPool getTableSessionPool(final int maxSize, final String database) {
DataNodeWrapper dataNode =
this.dataNodeWrapperList.get(rand.nextInt(this.dataNodeWrapperList.size()));
- return new TableSessionPoolBuilder()
- .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
- .user(SessionConfig.DEFAULT_USER)
- .password(SessionConfig.DEFAULT_PASSWORD)
- .database(database)
- .maxSize(maxSize)
+ return configureClientSSL(
+ new TableSessionPoolBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ .user(SessionConfig.DEFAULT_USER)
+ .password(SessionConfig.DEFAULT_PASSWORD)
+ .database(database)
+ .maxSize(maxSize))
.build();
}
@@ -853,7 +941,7 @@ protected NodeConnection getWriteConnectionWithSpecifiedDataNode(
Config.IOTDB_URL_PREFIX
+ endpoint
+ getParam(version, NODE_NETWORK_TIMEOUT_MS, ZERO_TIME_ZONE),
- BaseEnv.constructProperties(username, password, sqlDialect));
+ constructConnectionProperties(username, password, sqlDialect));
return new NodeConnection(
endpoint,
NodeConnection.NodeRole.DATA_NODE,
@@ -910,7 +998,7 @@ protected List getReadConnections(
Config.IOTDB_URL_PREFIX
+ endpoint
+ getParam(version, NODE_NETWORK_TIMEOUT_MS, ZERO_TIME_ZONE),
- BaseEnv.constructProperties(username, password, sqlDialect))));
+ constructConnectionProperties(username, password, sqlDialect))));
});
return readConnRequestDelegate.requestAll();
}
@@ -957,7 +1045,7 @@ protected List getReadConnections(
Config.IOTDB_URL_PREFIX
+ dataNode.getIpAndPortString()
+ getParam(version, NODE_NETWORK_TIMEOUT_MS, ZERO_TIME_ZONE),
- BaseEnv.constructProperties(username, password, sqlDialect))));
+ constructConnectionProperties(username, password, sqlDialect))));
return readConnRequestDelegate.requestAll();
}
@@ -988,8 +1076,10 @@ protected void testJDBCConnection() {
Config.IOTDB_URL_PREFIX
+ dataNodeEndpoint
+ getParam(null, NODE_NETWORK_TIMEOUT_MS, ZERO_TIME_ZONE),
- System.getProperty("User", "root"),
- System.getProperty("Password", "root"))) {
+ constructConnectionProperties(
+ System.getProperty("User", "root"),
+ System.getProperty("Password", "root"),
+ TREE_SQL_DIALECT))) {
logger.info("Successfully connecting to DataNode: {}.", dataNodeEndpoint);
return null;
} catch (final Exception e) {
diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java
index 03948e2371f79..01ef8f468fa6e 100644
--- a/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java
@@ -447,6 +447,11 @@ public CommonConfig setEnforceStrongPassword(boolean enforceStrongPassword) {
return this;
}
+ @Override
+ public CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL) {
+ return this;
+ }
+
@Override
public CommonConfig setSubscriptionPrefetchTsFileBatchMaxDelayInMs(
int subscriptionPrefetchTsFileBatchMaxDelayInMs) {
@@ -484,6 +489,11 @@ public CommonConfig setTrustStorePwd(String trustStorePwd) {
return this;
}
+ @Override
+ public CommonConfig setSslProtocol(String sslProtocol) {
+ return this;
+ }
+
@Override
public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion) {
return this;
diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java
index ad9168faebfb2..767a047239f98 100644
--- a/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java
@@ -204,6 +204,8 @@ default CommonConfig setDefaultDatabaseLevel(int defaultDatabaseLevel) {
CommonConfig setEnforceStrongPassword(boolean enforceStrongPassword);
+ CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL);
+
CommonConfig setEnableInternalSSL(boolean enableInternalSSL);
CommonConfig setKeyStorePath(String keyStorePath);
@@ -214,6 +216,8 @@ default CommonConfig setDefaultDatabaseLevel(int defaultDatabaseLevel) {
CommonConfig setTrustStorePwd(String trustStorePwd);
+ CommonConfig setSslProtocol(String sslProtocol);
+
CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion);
CommonConfig setEnableAuditLog(boolean enableAuditLog);
diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBClientSSLIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBClientSSLIT.java
new file mode 100644
index 0000000000000..23906fdb4c87d
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBClientSSLIT.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.iotdb.session.it;
+
+import org.apache.iotdb.isession.ISession;
+import org.apache.iotdb.isession.ITableSession;
+import org.apache.iotdb.isession.SessionConfig;
+import org.apache.iotdb.isession.SessionDataSet;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.category.TableClusterIT;
+import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
+import org.apache.iotdb.jdbc.Config;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.session.Session;
+import org.apache.iotdb.session.TableSessionBuilder;
+
+import org.apache.tsfile.read.common.RowRecord;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Collections;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({
+ LocalStandaloneIT.class,
+ ClusterIT.class,
+ TableLocalStandaloneIT.class,
+ TableClusterIT.class
+})
+public class IoTDBClientSSLIT {
+
+ private static final String STORE_PASSWORD = "thrift";
+ private static String keyDir;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ keyDir =
+ System.getProperty("user.dir")
+ + File.separator
+ + "target"
+ + File.separator
+ + "test-classes"
+ + File.separator;
+
+ EnvFactory.getEnv()
+ .getConfig()
+ .getCommonConfig()
+ .setEnableThriftClientSSL(true)
+ .setKeyStorePath(keyStorePath())
+ .setKeyStorePwd(STORE_PASSWORD)
+ .setTrustStorePath(trustStorePath())
+ .setTrustStorePwd(STORE_PASSWORD)
+ .setSslProtocol(SessionConfig.DEFAULT_SSL_PROTOCOL);
+ EnvFactory.getEnv().initClusterEnvironment();
+ }
+
+ @After
+ public void tearDown() {
+ try (ISession session = newSSLSession()) {
+ deleteTreeDatabase(session, "root.client_ssl_tree");
+ deleteTreeDatabase(session, "root.client_ssl_jdbc");
+ } catch (Exception ignored) {
+ // ignored
+ }
+ try (ITableSession session = newSSLTableSession()) {
+ session.executeNonQueryStatement("DROP DATABASE IF EXISTS client_ssl_table");
+ } catch (Exception ignored) {
+ // ignored
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ EnvFactory.getEnv().cleanClusterEnvironment();
+ }
+
+ @Test
+ public void nonSSLClientCanNotConnectToSSLPort() {
+ final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
+ final Session session =
+ new Session.Builder().host(dataNode.getIp()).port(dataNode.getPort()).build();
+
+ assertThrows(IoTDBConnectionException.class, session::open);
+ }
+
+ @Test
+ public void treeSessionCanConnectWithSSL() throws Exception {
+ try (ISession session = newSSLSession()) {
+ session.executeNonQueryStatement("CREATE DATABASE root.client_ssl_tree");
+ session.executeNonQueryStatement(
+ "CREATE TIMESERIES root.client_ssl_tree.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN");
+ session.executeNonQueryStatement(
+ "INSERT INTO root.client_ssl_tree.d1(time, s1) VALUES (1, 11)");
+
+ try (SessionDataSet dataSet =
+ session.executeQueryStatement("SELECT s1 FROM root.client_ssl_tree.d1")) {
+ assertTrue(dataSet.hasNext());
+ final RowRecord record = dataSet.next();
+ assertEquals(1L, record.getTimestamp());
+ assertEquals(11, record.getFields().get(0).getIntV());
+ assertFalse(dataSet.hasNext());
+ }
+ }
+ }
+
+ @Test
+ public void tableSessionCanConnectWithSSL() throws Exception {
+ try (ITableSession session = newSSLTableSession()) {
+ session.executeNonQueryStatement("CREATE DATABASE IF NOT EXISTS client_ssl_table");
+ session.executeNonQueryStatement("USE client_ssl_table");
+ session.executeNonQueryStatement(
+ "CREATE TABLE IF NOT EXISTS ssl_table (tag1 STRING TAG, value INT32 FIELD)");
+ session.executeNonQueryStatement(
+ "INSERT INTO ssl_table(time, tag1, value) VALUES (1, 'tag1', 22)");
+
+ try (SessionDataSet dataSet =
+ session.executeQueryStatement("SELECT time, value FROM ssl_table WHERE tag1 = 'tag1'")) {
+ assertTrue(dataSet.hasNext());
+ final RowRecord record = dataSet.next();
+ assertEquals(1L, record.getFields().get(0).getLongV());
+ assertEquals(22, record.getFields().get(1).getIntV());
+ assertFalse(dataSet.hasNext());
+ }
+ }
+ }
+
+ @Test
+ public void jdbcCanConnectWithSSL() throws Exception {
+ final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
+
+ try (Connection connection =
+ DriverManager.getConnection(
+ Config.IOTDB_URL_PREFIX + dataNode.getIpAndPortString(), sslProperties());
+ Statement statement = connection.createStatement()) {
+ statement.execute("CREATE DATABASE root.client_ssl_jdbc");
+ statement.execute(
+ "CREATE TIMESERIES root.client_ssl_jdbc.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN");
+ statement.execute("INSERT INTO root.client_ssl_jdbc.d1(time, s1) VALUES (1, 33)");
+
+ try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM root.client_ssl_jdbc.d1")) {
+ assertTrue(resultSet.next());
+ assertEquals(1L, resultSet.getLong(1));
+ assertEquals(33, resultSet.getInt(2));
+ assertFalse(resultSet.next());
+ }
+ }
+ }
+
+ private static ISession newSSLSession() throws IoTDBConnectionException {
+ final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
+ final Session session =
+ new Session.Builder()
+ .host(dataNode.getIp())
+ .port(dataNode.getPort())
+ .useSSL(true)
+ .trustStore(trustStorePath())
+ .trustStorePwd(STORE_PASSWORD)
+ .build();
+ session.open();
+ return session;
+ }
+
+ private static ITableSession newSSLTableSession() throws IoTDBConnectionException {
+ final DataNodeWrapper dataNode = EnvFactory.getEnv().getDataNodeWrapper(0);
+ return new TableSessionBuilder()
+ .nodeUrls(Collections.singletonList(dataNode.getIpAndPortString()))
+ .useSSL(true)
+ .trustStore(trustStorePath())
+ .trustStorePwd(STORE_PASSWORD)
+ .build();
+ }
+
+ private static Properties sslProperties() {
+ final Properties properties = new Properties();
+ properties.put("user", SessionConfig.DEFAULT_USER);
+ properties.put("password", SessionConfig.DEFAULT_PASSWORD);
+ properties.put(Config.USE_SSL, Boolean.TRUE.toString());
+ properties.put(Config.TRUST_STORE, trustStorePath());
+ properties.put(Config.TRUST_STORE_PWD, STORE_PASSWORD);
+ return properties;
+ }
+
+ private void deleteTreeDatabase(final ISession session, final String database) {
+ try {
+ session.executeNonQueryStatement("DELETE DATABASE " + database);
+ } catch (Exception ignored) {
+ // ignored
+ }
+ }
+
+ private static String keyStorePath() {
+ return keyDir + "test-keystore";
+ }
+
+ private static String trustStorePath() {
+ return keyDir + "test-truststore";
+ }
+}
diff --git a/integration-test/src/test/resources/test-keystore b/integration-test/src/test/resources/test-keystore
index 2346c547259fd..766057947174c 100644
Binary files a/integration-test/src/test/resources/test-keystore and b/integration-test/src/test/resources/test-keystore differ
diff --git a/integration-test/src/test/resources/test-truststore b/integration-test/src/test/resources/test-truststore
index 92c5b819f21f1..c6b93a476c560 100644
Binary files a/integration-test/src/test/resources/test-truststore and b/integration-test/src/test/resources/test-truststore differ
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/AbstractCli.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/AbstractCli.java
index 3d8535aac3c3e..017f0a1a6ca2b 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/AbstractCli.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/AbstractCli.java
@@ -77,12 +77,15 @@ public abstract class AbstractCli {
static final String TRUST_STORE_PWD_ARGS = "tpw";
+ static final String SSL_PROTOCOL_ARGS = "ssl_protocol";
+
private static final String EXECUTE_NAME = "execute";
private static final String USE_SSL = "use_ssl";
private static final String TRUST_STORE = "trust_store";
private static final String TRUST_STORE_PWD = "trust_store_pwd";
+ private static final String SSL_PROTOCOL = "ssl_protocol";
private static final String NULL = "null";
static final int CODE_OK = 0;
@@ -132,6 +135,7 @@ public abstract class AbstractCli {
static String trustStore;
// TODO: Make non-static
static String trustStorePwd;
+ static String sslProtocol;
static String execute;
static boolean hasExecuteSQL = false;
@@ -156,6 +160,7 @@ static void init() {
keywordSet.add("-" + USE_SSL_ARGS);
keywordSet.add("-" + TRUST_STORE_ARGS);
keywordSet.add("-" + TRUST_STORE_PWD_ARGS);
+ keywordSet.add("-" + SSL_PROTOCOL_ARGS);
keywordSet.add("-" + EXECUTE_ARGS);
keywordSet.add("-" + ISO8601_ARGS);
keywordSet.add("-" + RPC_COMPRESS_ARGS);
@@ -214,6 +219,15 @@ static Options createOptions() {
.build();
options.addOption(useSSL);
+ Option sslProtocol =
+ Option.builder(SSL_PROTOCOL_ARGS)
+ .longOpt(SSL_PROTOCOL)
+ .argName(SSL_PROTOCOL)
+ .hasArg()
+ .desc("SSL protocol. (optional)")
+ .build();
+ options.addOption(sslProtocol);
+
Option execute =
Option.builder(EXECUTE_ARGS)
.argName(EXECUTE_NAME)
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java
index d1bbd6165f694..a9e911be6edc3 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java
@@ -111,6 +111,9 @@ private static void constructProperties() {
info.setProperty("use_ssl", useSsl);
info.setProperty("trust_store", trustStore);
info.setProperty("trust_store_pwd", trustStorePwd);
+ if (sslProtocol != null) {
+ info.setProperty(Config.SSL_PROTOCOL, sslProtocol);
+ }
}
info.setProperty("user", username);
info.setProperty("password", password);
@@ -159,6 +162,7 @@ private static boolean parseCommandLine(
private static void serve(CliContext ctx) {
try {
useSsl = commandLine.getOptionValue(USE_SSL_ARGS);
+ sslProtocol = commandLine.getOptionValue(SSL_PROTOCOL_ARGS);
if (Boolean.parseBoolean(useSsl)) {
trustStore = ctx.getLineReader().readLine("please input your trust_store:", '\0');
trustStorePwd = ctx.getLineReader().readLine("please input your trust_store_pwd:", '\0');
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java
index 0d4c5f218b73b..a106326095756 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java
@@ -68,6 +68,10 @@ public class Constants {
public static final String TRUST_STORE_PWD_NAME = "trust_store_password";
public static final String TRUST_STORE_PWD_DESC = "Trust store password. (optional)";
+ public static final String SSL_PROTOCOL_ARGS = "ssl_protocol";
+ public static final String SSL_PROTOCOL_NAME = "ssl_protocol";
+ public static final String SSL_PROTOCOL_DESC = "SSL protocol. (optional)";
+
public static final String FILE_TYPE_ARGS = "ft";
public static final String FILE_TYPE_NAME = "file_type";
public static final String FILE_TYPE_ARGS_NAME = "format";
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java
index b60809eba636a..1f79b303f6e4e 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java
@@ -133,6 +133,16 @@ public static Options createCommonOptions(Options options) {
.build();
options.addOption(opTrustStorePwd);
+ Option opSslProtocol =
+ Option.builder(SSL_PROTOCOL_ARGS)
+ .longOpt(SSL_PROTOCOL_NAME)
+ .optionalArg(true)
+ .argName(SSL_PROTOCOL_NAME)
+ .hasArg()
+ .desc(SSL_PROTOCOL_DESC)
+ .build();
+ options.addOption(opSslProtocol);
+
return options;
}
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java
index 4ef95c78eda14..6ea79a5b58216 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java
@@ -34,6 +34,9 @@
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
+import org.apache.iotdb.session.TableSessionBuilder;
+import org.apache.iotdb.session.pool.SessionPool;
+import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
import org.apache.iotdb.tool.common.Constants;
import org.apache.iotdb.tool.common.ImportTsFileOperation;
@@ -94,6 +97,7 @@ public abstract class AbstractDataTool {
protected static Boolean useSsl;
protected static String trustStore;
protected static String trustStorePwd;
+ protected static String sslProtocol;
protected static Boolean aligned;
protected static String database;
protected static String startTime;
@@ -134,6 +138,38 @@ public abstract class AbstractDataTool {
protected AbstractDataTool() {}
+ protected static Session.Builder configureSsl(Session.Builder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
+ protected static SessionPool.Builder configureSsl(SessionPool.Builder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
+ protected static TableSessionBuilder configureSsl(TableSessionBuilder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
+ protected static TableSessionPoolBuilder configureSsl(TableSessionPoolBuilder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
protected static String checkRequiredArg(
String arg, String name, CommandLine commandLine, String defaultValue)
throws ArgsErrorException {
@@ -170,6 +206,7 @@ protected static void parseBasicParams(CommandLine commandLine)
String useSslStr = commandLine.getOptionValue(Constants.USE_SSL_ARGS);
useSsl = Boolean.parseBoolean(useSslStr);
if (useSsl) {
+ sslProtocol = commandLine.getOptionValue(Constants.SSL_PROTOCOL_ARGS);
String givenTS = commandLine.getOptionValue(Constants.TRUST_STORE_ARGS);
if (givenTS != null) {
trustStore = givenTS;
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java
index dcf05baa14e66..458c447ba4f5b 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java
@@ -71,8 +71,7 @@ public void init() throws IoTDBConnectionException, StatementExecutionException
.database(database)
.thriftMaxFrameSize(rpcMaxFrameSize);
if (useSsl) {
- tableSessionBuilder =
- tableSessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ tableSessionBuilder = configureSsl(tableSessionBuilder);
}
tableSession = tableSessionBuilder.build();
SessionDataSet sessionDataSet = tableSession.executeQueryStatement("show databases", timeout);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java
index 9d7d0ca521d09..fd8aeb0cbe352 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java
@@ -80,8 +80,7 @@ public void init() throws IoTDBConnectionException, StatementExecutionException,
.enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE)
.version(SessionConfig.DEFAULT_VERSION);
if (useSsl) {
- sessionBuilder =
- sessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ sessionBuilder = configureSsl(sessionBuilder);
}
session = sessionBuilder.build();
session.open(false);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java
index 506da8b8e17ce..d103c63555b67 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java
@@ -88,8 +88,7 @@ public void init() throws InterruptedException {
.enableAutoFetch(false)
.database(database);
if (useSsl) {
- tableSessionPoolBuilder =
- tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder);
}
sessionPool = tableSessionPoolBuilder.build();
final File file = new File(targetPath);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java
index 95aa92631422a..c976e847740d2 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java
@@ -72,8 +72,7 @@ public void init()
.enableRedirection(false)
.enableAutoFetch(false);
if (useSsl) {
- sessionPoolBuilder =
- sessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ sessionPoolBuilder = configureSsl(sessionPoolBuilder);
}
sessionPool = sessionPoolBuilder.build();
sessionPool.setEnableQueryRedirection(false);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java
index 09442bdab878f..2bee5f5d33151 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java
@@ -25,6 +25,8 @@
import org.apache.iotdb.cli.utils.JlineUtils;
import org.apache.iotdb.exception.ArgsErrorException;
import org.apache.iotdb.session.Session;
+import org.apache.iotdb.session.pool.SessionPool;
+import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
import org.apache.iotdb.tool.common.Constants;
import org.apache.commons.cli.CommandLine;
@@ -53,6 +55,7 @@ public abstract class AbstractSchemaTool {
protected static Boolean useSsl;
protected static String trustStore;
protected static String trustStorePwd;
+ protected static String sslProtocol;
protected static Session session;
protected static String queryPath;
protected static int threadNum = 8;
@@ -73,6 +76,30 @@ public abstract class AbstractSchemaTool {
protected AbstractSchemaTool() {}
+ protected static Session.Builder configureSsl(Session.Builder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
+ protected static SessionPool.Builder configureSsl(SessionPool.Builder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
+ protected static TableSessionPoolBuilder configureSsl(TableSessionPoolBuilder builder) {
+ builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ if (sslProtocol != null) {
+ builder.sslProtocol(sslProtocol);
+ }
+ return builder;
+ }
+
protected static String checkRequiredArg(
String arg, String name, CommandLine commandLine, String defaultValue)
throws ArgsErrorException {
@@ -107,6 +134,7 @@ protected static void parseBasicParams(CommandLine commandLine)
String useSslStr = commandLine.getOptionValue(Constants.USE_SSL_ARGS);
useSsl = Boolean.parseBoolean(useSslStr);
if (useSsl) {
+ sslProtocol = commandLine.getOptionValue(Constants.SSL_PROTOCOL_ARGS);
String givenTS = commandLine.getOptionValue(Constants.TRUST_STORE_ARGS);
if (givenTS != null) {
trustStore = givenTS;
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java
index 1ed3e2c6b862a..c9b15870d2175 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java
@@ -64,8 +64,7 @@ public void init() throws InterruptedException {
.enableAutoFetch(false)
.database(database);
if (useSsl) {
- tableSessionPoolBuilder =
- tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder);
}
sessionPool = tableSessionPoolBuilder.build();
checkDatabase();
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java
index 334d8a8d8dc42..da304f87c4986 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java
@@ -51,8 +51,7 @@ public void init()
.username(username)
.password(password);
if (useSsl) {
- sessionBuilder =
- sessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ sessionBuilder = configureSsl(sessionBuilder);
}
session = sessionBuilder.build();
session.open(false);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java
index 011042c34d29c..004ec8b4152bb 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java
@@ -60,8 +60,7 @@ public void init() throws InterruptedException {
.enableAutoFetch(false)
.database(database);
if (useSsl) {
- tableSessionPoolBuilder =
- tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder);
}
sessionPool = tableSessionPoolBuilder.build();
final File file = new File(targetPath);
diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java
index 9526447fd9654..5d7dfc35d8a0d 100644
--- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java
+++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java
@@ -73,8 +73,7 @@ public void init()
.enableRedirection(false)
.enableAutoFetch(false);
if (useSsl) {
- sessionPoolBuilder =
- sessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd);
+ sessionPoolBuilder = configureSsl(sessionPoolBuilder);
}
sessionPool = sessionPoolBuilder.build();
sessionPool.setEnableQueryRedirection(false);
diff --git a/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java b/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java
index 611014c615c3b..7885d50cf5da1 100644
--- a/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java
+++ b/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java
@@ -56,5 +56,7 @@ public class SessionConfig {
public static final String SQL_DIALECT = "tree";
+ public static final String DEFAULT_SSL_PROTOCOL = "TLS";
+
private SessionConfig() {}
}
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java
index 0b1049330eae7..d79656cc8d295 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java
@@ -82,6 +82,10 @@ private Config() {
public static final String TRUST_STORE_PWD = "trust_store_pwd";
+ public static final String SSL_PROTOCOL = "ssl_protocol";
+
+ static final String DEFAULT_SSL_PROTOCOL = "TLS";
+
public static final String SQL_DIALECT = "sql_dialect";
public static final String DATABASE = "db";
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
index 7f37e2206fb87..0dc81115dd01b 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java
@@ -544,12 +544,13 @@ private void openTransport() throws TTransportException {
if (params.isUseSSL()) {
transport =
- DeepCopyRpcTransportFactory.INSTANCE.getTransport(
+ DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig(
params.getHost(),
params.getPort(),
getNetworkTimeout(),
params.getTrustStore(),
- params.getTrustStorePwd());
+ params.getTrustStorePwd(),
+ params.getSslProtocol());
} else {
transport =
DeepCopyRpcTransportFactory.INSTANCE.getTransport(
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
index 1112caabd4e20..8bf51379c5c2a 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java
@@ -51,6 +51,7 @@ public class IoTDBConnectionParams {
private boolean useSSL = false;
private String trustStore;
private String trustStorePwd;
+ private String sslProtocol = Config.DEFAULT_SSL_PROTOCOL;
private String sqlDialect = TREE;
@@ -184,6 +185,14 @@ public void setTrustStorePwd(String trustStorePwd) {
this.trustStorePwd = trustStorePwd;
}
+ public String getSslProtocol() {
+ return sslProtocol;
+ }
+
+ public void setSslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ }
+
public String getSqlDialect() {
return sqlDialect;
}
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
index 00e46cc340d15..ea205ef726757 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java
@@ -19,6 +19,8 @@
package org.apache.iotdb.jdbc;
+import org.apache.iotdb.rpc.RpcSslUtils;
+
import java.nio.charset.Charset;
import java.time.DateTimeException;
import java.time.ZoneId;
@@ -136,6 +138,9 @@ static IoTDBConnectionParams parseUrl(String url, Properties info) throws IoTDBU
if (info.containsKey(Config.TRUST_STORE_PWD)) {
params.setTrustStorePwd(info.getProperty(Config.TRUST_STORE_PWD));
}
+ if (info.containsKey(Config.SSL_PROTOCOL)) {
+ params.setSslProtocol(RpcSslUtils.normalizeProtocol(info.getProperty(Config.SSL_PROTOCOL)));
+ }
if (info.containsKey(Config.SQL_DIALECT)) {
params.setSqlDialect(info.getProperty(Config.SQL_DIALECT));
}
@@ -175,6 +180,7 @@ private static boolean parseUrlParam(String subURL, Properties info) {
case Config.USE_SSL:
case Config.TRUST_STORE:
case Config.TRUST_STORE_PWD:
+ case Config.SSL_PROTOCOL:
case Config.VERSION:
case Config.NETWORK_TIMEOUT:
case Config.SQL_DIALECT:
diff --git a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
index 4c401b88017af..d201a9b2d4569 100644
--- a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
+++ b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java
@@ -159,4 +159,15 @@ public void testRpcCompress() throws IoTDBURLException {
Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?rpc_compress=true", properties);
assertTrue(Config.rpcThriftCompressionEnable);
}
+
+ @Test
+ public void testParseSslConfig() throws IoTDBURLException {
+ Properties properties = new Properties();
+ IoTDBConnectionParams params =
+ Utils.parseUrl(
+ "jdbc:iotdb://127.0.0.1:6667?use_ssl=true&ssl_protocol=ProviderProtocol", properties);
+
+ assertTrue(params.isUseSSL());
+ assertEquals("ProviderProtocol", params.getSslProtocol());
+ }
}
diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
index 22e104b6a58ac..03bf2070bca98 100644
--- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
+++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java
@@ -83,9 +83,15 @@ public TTransport getTransportWithNoTimeout(String ip, int port) throws TTranspo
public TTransport getTransport(
String ip, int port, int timeout, String trustStore, String trustStorePwd)
throws TTransportException {
+ return getTransportWithSSLConfig(ip, port, timeout, trustStore, trustStorePwd, null);
+ }
+
+ public TTransport getTransportWithSSLConfig(
+ String ip, int port, int timeout, String trustStore, String trustStorePwd, String sslProtocol)
+ throws TTransportException {
TSSLTransportFactory.TSSLTransportParameters params =
- new TSSLTransportFactory.TSSLTransportParameters();
- params.setTrustStore(trustStore, trustStorePwd);
+ RpcSslUtils.createTSSLTransportParameters(sslProtocol);
+ RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd);
TTransport transport = TSSLTransportFactory.getClientSocket(ip, port, timeout, params);
return inner.getTransport(transport);
}
@@ -99,11 +105,24 @@ public TTransport getTransport(
String keyStore,
String keyStorePwd)
throws TTransportException {
+ return getTransport(ip, port, timeout, trustStore, trustStorePwd, keyStore, keyStorePwd, null);
+ }
+
+ public TTransport getTransport(
+ String ip,
+ int port,
+ int timeout,
+ String trustStore,
+ String trustStorePwd,
+ String keyStore,
+ String keyStorePwd,
+ String sslProtocol)
+ throws TTransportException {
TSSLTransportFactory.TSSLTransportParameters params =
- new TSSLTransportFactory.TSSLTransportParameters();
+ RpcSslUtils.createTSSLTransportParameters(sslProtocol);
if (Files.exists(Paths.get(trustStore)) && Files.exists(Paths.get(keyStore))) {
- params.setTrustStore(trustStore, trustStorePwd);
- params.setKeyStore(keyStore, keyStorePwd);
+ RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd);
+ RpcSslUtils.setKeyStore(params, keyStore, keyStorePwd);
} else {
throw new TTransportException(new IOException(RpcMessages.COULD_NOT_LOAD_KEYSTORE));
}
diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java
new file mode 100644
index 0000000000000..c6ceb5b4c5d64
--- /dev/null
+++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.iotdb.rpc;
+
+import org.apache.thrift.transport.TSSLTransportFactory;
+import org.apache.thrift.transport.TTransportException;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.stream.Stream;
+
+public final class RpcSslUtils {
+
+ private static final String DEFAULT_PROTOCOL = "TLS";
+ private static final String PKCS12_STORE_TYPE = "PKCS12";
+ private static final String JKS_STORE_TYPE = "JKS";
+
+ private static volatile String protocol = DEFAULT_PROTOCOL;
+
+ private RpcSslUtils() {}
+
+ public static void configure(String sslProtocol) {
+ protocol = normalizeProtocol(sslProtocol);
+ }
+
+ public static TSSLTransportFactory.TSSLTransportParameters createTSSLTransportParameters() {
+ return createTSSLTransportParameters(protocol);
+ }
+
+ public static TSSLTransportFactory.TSSLTransportParameters createTSSLTransportParameters(
+ String sslProtocol) {
+ return new TSSLTransportFactory.TSSLTransportParameters(normalizeProtocol(sslProtocol), null);
+ }
+
+ public static void setKeyStore(
+ TSSLTransportFactory.TSSLTransportParameters params, String keyStorePath, String keyStorePwd)
+ throws TTransportException {
+ try {
+ params.setKeyStore(
+ keyStorePath,
+ keyStorePwd,
+ KeyManagerFactory.getDefaultAlgorithm(),
+ detectStoreType(keyStorePath, keyStorePwd));
+ } catch (GeneralSecurityException | IOException e) {
+ throw new TTransportException(e);
+ }
+ }
+
+ public static void setTrustStore(
+ TSSLTransportFactory.TSSLTransportParameters params,
+ String trustStorePath,
+ String trustStorePwd)
+ throws TTransportException {
+ try {
+ params.setTrustStore(
+ trustStorePath,
+ trustStorePwd,
+ TrustManagerFactory.getDefaultAlgorithm(),
+ detectStoreType(trustStorePath, trustStorePwd));
+ } catch (GeneralSecurityException | IOException e) {
+ throw new TTransportException(e);
+ }
+ }
+
+ public static SSLContext createSSLContext(
+ String keyStorePath,
+ String keyStorePassword,
+ String trustStorePath,
+ String trustStorePassword)
+ throws GeneralSecurityException, IOException {
+ return createSSLContext(
+ keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, protocol);
+ }
+
+ public static SSLContext createSSLContext(
+ String keyStorePath,
+ String keyStorePassword,
+ String trustStorePath,
+ String trustStorePassword,
+ String sslProtocol)
+ throws GeneralSecurityException, IOException {
+ SSLContext context = SSLContext.getInstance(normalizeProtocol(sslProtocol));
+ KeyManager[] keyManagers =
+ hasText(keyStorePath) ? loadKeyManagers(keyStorePath, keyStorePassword) : null;
+ TrustManager[] trustManagers =
+ hasText(trustStorePath) ? loadTrustManagers(trustStorePath, trustStorePassword) : null;
+ context.init(keyManagers, trustManagers, null);
+ return context;
+ }
+
+ public static KeyManager[] createKeyManagers(String keyStorePath, String keyStorePassword)
+ throws GeneralSecurityException, IOException {
+ return loadKeyManagers(keyStorePath, keyStorePassword);
+ }
+
+ public static TrustManager[] createTrustManagers(String trustStorePath, String trustStorePassword)
+ throws GeneralSecurityException, IOException {
+ return loadTrustManagers(trustStorePath, trustStorePassword);
+ }
+
+ public static String getProtocol() {
+ return protocol;
+ }
+
+ public static void validateKeyStore(String keyStorePath, String keyStorePassword)
+ throws TTransportException {
+ validateStore(keyStorePath, keyStorePassword);
+ }
+
+ public static void validateTrustStore(String trustStorePath, String trustStorePassword)
+ throws TTransportException {
+ validateStore(trustStorePath, trustStorePassword);
+ }
+
+ private static KeyManager[] loadKeyManagers(String keyStorePath, String keyStorePassword)
+ throws GeneralSecurityException, IOException {
+ KeyStore keyStore = loadStore(keyStorePath, keyStorePassword);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(keyStore, toPassword(keyStorePassword));
+ return kmf.getKeyManagers();
+ }
+
+ private static TrustManager[] loadTrustManagers(String trustStorePath, String trustStorePassword)
+ throws GeneralSecurityException, IOException {
+ KeyStore trustStore = loadStore(trustStorePath, trustStorePassword);
+ TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(trustStore);
+ return tmf.getTrustManagers();
+ }
+
+ private static String detectStoreType(String storePath, String storePassword)
+ throws GeneralSecurityException, IOException {
+ return loadStore(storePath, storePassword).getType();
+ }
+
+ private static KeyStore loadStore(String storePath, String storePassword)
+ throws GeneralSecurityException, IOException {
+ Exception lastException = null;
+ for (String storeType : storeTypeCandidates()) {
+ try {
+ return loadStore(storePath, storePassword, storeType);
+ } catch (AccessDeniedException | FileNotFoundException e) {
+ throw e;
+ } catch (GeneralSecurityException | IOException e) {
+ lastException = e;
+ }
+ }
+ if (lastException instanceof GeneralSecurityException) {
+ throw (GeneralSecurityException) lastException;
+ }
+ if (lastException instanceof IOException) {
+ throw (IOException) lastException;
+ }
+ throw new IOException("No supported keystore or truststore type is available");
+ }
+
+ private static KeyStore loadStore(String storePath, String storePassword, String storeType)
+ throws GeneralSecurityException, IOException {
+ KeyStore store = KeyStore.getInstance(storeType);
+ try (InputStream inputStream = Files.newInputStream(Path.of(storePath))) {
+ store.load(inputStream, toPassword(storePassword));
+ } catch (AccessDeniedException e) {
+ throw new AccessDeniedException("Failed to load keystore or truststore file");
+ } catch (FileNotFoundException | NoSuchFileException e) {
+ throw new FileNotFoundException("keystore or truststore file not found: " + storePath);
+ }
+ return store;
+ }
+
+ private static void validateStore(String storePath, String storePassword)
+ throws TTransportException {
+ try {
+ KeyStore store = loadStore(storePath, storePassword);
+ Enumeration aliases = store.aliases();
+ while (aliases.hasMoreElements()) {
+ X509Certificate cert = (X509Certificate) store.getCertificate(aliases.nextElement());
+ if (cert != null) {
+ cert.checkValidity();
+ }
+ }
+ } catch (Exception e) {
+ throw new TTransportException(e);
+ }
+ }
+
+ private static char[] toPassword(String password) {
+ return password == null ? null : password.toCharArray();
+ }
+
+ public static String normalizeProtocol(String value) {
+ String trimmed = trimToEmpty(value);
+ return trimmed.isEmpty() ? DEFAULT_PROTOCOL : trimmed;
+ }
+
+ private static String trimToEmpty(String value) {
+ return value == null ? "" : value.trim();
+ }
+
+ private static boolean hasText(String value) {
+ return value != null && !value.trim().isEmpty();
+ }
+
+ private static String[] storeTypeCandidates() {
+ return Stream.of(KeyStore.getDefaultType(), PKCS12_STORE_TYPE, JKS_STORE_TYPE)
+ .map(String::trim)
+ .map(s -> s.toUpperCase(Locale.ROOT))
+ .filter(s -> !s.isEmpty())
+ .distinct()
+ .toArray(String[]::new);
+ }
+}
diff --git a/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/RpcUtilsTest.java b/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/RpcUtilsTest.java
index 940c50453a26b..143de1d9ab76a 100644
--- a/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/RpcUtilsTest.java
+++ b/iotdb-client/service-rpc/src/test/java/org/apache/iotdb/rpc/RpcUtilsTest.java
@@ -99,4 +99,11 @@ public void testVerifySuccessListThrowsOnFailure() {
Assert.assertTrue(e.getMessage().contains("failed"));
}
}
+
+ @Test
+ public void testSslProtocolNormalization() {
+ Assert.assertEquals("TLS", RpcSslUtils.normalizeProtocol(null));
+ Assert.assertEquals("TLSv1.3", RpcSslUtils.normalizeProtocol(" TLSv1.3 "));
+ Assert.assertEquals("ProviderProtocol", RpcSslUtils.normalizeProtocol(" ProviderProtocol "));
+ }
}
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/AbstractSessionBuilder.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/AbstractSessionBuilder.java
index f410b167463af..873e6dd248d8a 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/AbstractSessionBuilder.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/AbstractSessionBuilder.java
@@ -63,6 +63,7 @@ public abstract class AbstractSessionBuilder {
public boolean useSSL = false;
public String trustStore;
public String trustStorePwd;
+ public String sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL;
// max retry count, if set to 0, means that we won't do any retry
// we can use any available DataNodes(fetched in background thread if enableAutoFetch is true,
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
index d57844b499705..a41db581e9cc7 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java
@@ -61,6 +61,7 @@ public class NodesSupplier implements INodeSupplier, Runnable {
private final boolean useSSL;
private final String trustStore;
private final String trustStorePwd;
+ private final String sslProtocol;
private final boolean enableRPCCompression;
private final String userName;
@@ -95,6 +96,7 @@ public static NodesSupplier createNodeSupplier(
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
boolean enableRPCCompression,
String version) {
@@ -110,6 +112,7 @@ public static NodesSupplier createNodeSupplier(
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableRPCCompression,
version);
@@ -132,6 +135,7 @@ private NodesSupplier(
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
boolean enableRPCCompression,
String version) {
this.availableNodes.addAll(new HashSet<>(endPointList));
@@ -140,6 +144,7 @@ private NodesSupplier(
this.useSSL = useSSL;
this.trustStore = trustStore;
this.trustStorePwd = trustStorePwd;
+ this.sslProtocol = sslProtocol;
this.enableRPCCompression = enableRPCCompression;
this.zoneId = zoneId == null ? ZoneId.systemDefault() : zoneId;
this.thriftDefaultBufferSize = thriftDefaultBufferSize;
@@ -188,6 +193,7 @@ private boolean createConnection(TEndPoint endPoint) {
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
userName,
password,
enableRPCCompression,
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/Session.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/Session.java
index f352a0612e6a7..648a63845b4bf 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/Session.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/Session.java
@@ -134,6 +134,7 @@ public class Session implements ISession {
protected boolean useSSL;
protected String trustStore;
protected String trustStorePwd;
+ protected String sslProtocol;
/**
* Timeout of query can be set by users. A negative number means using the default configuration
@@ -474,6 +475,7 @@ public Session(AbstractSessionBuilder builder) {
this.useSSL = builder.useSSL;
this.trustStore = builder.trustStore;
this.trustStorePwd = builder.trustStorePwd;
+ this.sslProtocol = builder.sslProtocol;
this.enableAutoFetch = builder.enableAutoFetch;
this.maxRetryCount = builder.maxRetryCount;
this.retryIntervalInMs = builder.retryIntervalInMs;
@@ -543,6 +545,7 @@ public synchronized void open(boolean enableRPCCompaction, int connectionTimeout
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableRPCCompaction,
version.toString());
} else {
@@ -4435,6 +4438,11 @@ public Builder trustStorePwd(String trustStorePwd) {
return this;
}
+ public Builder sslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ return this;
+ }
+
public Session build() {
if (nodeUrls != null
&& (!SessionConfig.DEFAULT_HOST.equals(host) || rpcPort != SessionConfig.DEFAULT_PORT)) {
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/SessionConnection.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
index c3e62cdd3e92e..468b59abb0c23 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
@@ -152,7 +152,8 @@ public SessionConnection(
this.sqlDialect = sqlDialect;
this.database = database;
try {
- init(endPoint, session.useSSL, session.trustStore, session.trustStorePwd);
+ init(
+ endPoint, session.useSSL, session.trustStore, session.trustStorePwd, session.sslProtocol);
} catch (StatementExecutionException e) {
throw new IoTDBConnectionException(e.getMessage());
} catch (IoTDBConnectionException e) {
@@ -180,7 +181,12 @@ public SessionConnection(
initClusterConn();
}
- private void init(TEndPoint endPoint, boolean useSSL, String trustStore, String trustStorePwd)
+ private void init(
+ TEndPoint endPoint,
+ boolean useSSL,
+ String trustStore,
+ String trustStorePwd,
+ String sslProtocol)
throws IoTDBConnectionException, StatementExecutionException {
DeepCopyRpcTransportFactory.setDefaultBufferCapacity(session.thriftDefaultBufferSize);
DeepCopyRpcTransportFactory.setThriftMaxFrameSize(session.thriftMaxFrameSize);
@@ -190,12 +196,13 @@ private void init(TEndPoint endPoint, boolean useSSL, String trustStore, String
}
if (useSSL) {
transport =
- DeepCopyRpcTransportFactory.INSTANCE.getTransport(
+ DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig(
endPoint.getIp(),
endPoint.getPort(),
session.connectionTimeoutInMs,
trustStore,
- trustStorePwd);
+ trustStorePwd,
+ sslProtocol);
} else {
transport =
DeepCopyRpcTransportFactory.INSTANCE.getTransport(
@@ -266,7 +273,12 @@ private void initClusterConn() throws IoTDBConnectionException {
for (TEndPoint tEndPoint : endPointList) {
try {
session.defaultEndPoint = tEndPoint;
- init(tEndPoint, session.useSSL, session.trustStore, session.trustStorePwd);
+ init(
+ tEndPoint,
+ session.useSSL,
+ session.trustStore,
+ session.trustStorePwd,
+ session.sslProtocol);
} catch (IoTDBConnectionException e) {
if (!reconnect()) {
logger.error(SessionMessages.CLUSTER_NO_NODES);
@@ -1083,7 +1095,12 @@ private boolean reconnect() {
}
tryHostNum++;
try {
- init(endPoint, session.useSSL, session.trustStore, session.trustStorePwd);
+ init(
+ endPoint,
+ session.useSSL,
+ session.trustStore,
+ session.trustStorePwd,
+ session.sslProtocol);
connectedSuccess = true;
} catch (IoTDBConnectionException e) {
logger.warn(SessionMessages.NODE_DOWN_TRY_NEXT, endPoint);
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java
index be53797165a6a..e724c0fd53220 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java
@@ -239,6 +239,18 @@ public TableSessionBuilder trustStorePwd(String trustStorePwd) {
return this;
}
+ /**
+ * Sets the SSL protocol for secure connections.
+ *
+ * @param sslProtocol the SSL protocol.
+ * @return the current {@link TableSessionBuilder} instance.
+ * @defaultValue TLS
+ */
+ public TableSessionBuilder sslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ return this;
+ }
+
/**
* Enables or disables rpc compression for the connection.
*
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java
index e3b9e8fc98987..3ab3abd581d9a 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java
@@ -78,6 +78,7 @@ public void init(
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
String username,
String password,
boolean enableRPCCompression,
@@ -89,12 +90,13 @@ public void init(
try {
if (useSSL) {
transport =
- DeepCopyRpcTransportFactory.INSTANCE.getTransport(
+ DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig(
endPoint.getIp(),
endPoint.getPort(),
connectionTimeoutInMs,
trustStore,
- trustStorePwd);
+ trustStorePwd,
+ sslProtocol);
} else {
transport =
DeepCopyRpcTransportFactory.INSTANCE.getTransport(
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
index 3eaabe7f1fa78..8136b2be68fd1 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
@@ -116,6 +116,9 @@ public class SessionPool implements ISessionPool {
private String trustStore;
private String trustStorePwd;
+
+ private String sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL;
+
private ZoneId zoneId;
// this field only take effect in write request, nothing to do with any other type requests,
// like query, load and so on.
@@ -466,6 +469,7 @@ public SessionPool(
this.useSSL = useSSL;
this.trustStore = trustStore;
this.trustStorePwd = trustStorePwd;
+ this.sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL;
initThreadPool();
initAvailableNodes(Collections.singletonList(new TEndPoint(host, port)));
}
@@ -536,6 +540,7 @@ public SessionPool(AbstractSessionPoolBuilder builder) {
this.useSSL = builder.useSSL;
this.trustStore = builder.trustStore;
this.trustStorePwd = builder.trustStorePwd;
+ this.sslProtocol = builder.sslProtocol;
this.maxRetryCount = builder.maxRetryCount;
this.retryIntervalInMs = builder.retryIntervalInMs;
this.sqlDialect = builder.sqlDialect;
@@ -593,6 +598,7 @@ private Session constructNewSession() {
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
+ .sslProtocol(sslProtocol)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.sqlDialect(sqlDialect)
@@ -618,6 +624,7 @@ private Session constructNewSession() {
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
+ .sslProtocol(sslProtocol)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.sqlDialect(sqlDialect)
@@ -662,6 +669,7 @@ private void initAvailableNodes(List endPointList) {
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableThriftCompression,
version.toString());
}
@@ -3637,6 +3645,11 @@ public Builder trustStorePwd(String trustStorePwd) {
return this;
}
+ public Builder sslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ return this;
+ }
+
public Builder host(String host) {
this.host = host;
return this;
diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java
index d5f52f3a8dc73..2c7aba1a45213 100644
--- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java
+++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java
@@ -281,6 +281,18 @@ public TableSessionPoolBuilder trustStorePwd(String trustStorePwd) {
return this;
}
+ /**
+ * Sets the SSL protocol for secure connections.
+ *
+ * @param sslProtocol the SSL protocol.
+ * @return the current {@link TableSessionPoolBuilder} instance.
+ * @defaultValue TLS
+ */
+ public TableSessionPoolBuilder sslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ return this;
+ }
+
/**
* Builds and returns a configured {@link ITableSessionPool} instance.
*
diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/iot/client/SyncIoTConsensusServiceClient.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/iot/client/SyncIoTConsensusServiceClient.java
index 43b2f60d89f47..3f3eb2d358e60 100644
--- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/iot/client/SyncIoTConsensusServiceClient.java
+++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/iot/client/SyncIoTConsensusServiceClient.java
@@ -61,7 +61,8 @@ public SyncIoTConsensusServiceClient(
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/NoHostnameVerificationTrustManager.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/NoHostnameVerificationTrustManager.java
deleted file mode 100644
index fb5c908548861..0000000000000
--- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/NoHostnameVerificationTrustManager.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.iotdb.consensus.ratis.utils;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.X509ExtendedTrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import java.net.Socket;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-public class NoHostnameVerificationTrustManager extends X509ExtendedTrustManager {
-
- private final X509TrustManager delegate;
-
- public NoHostnameVerificationTrustManager(X509TrustManager delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return delegate.getAcceptedIssuers();
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- delegate.checkClientTrusted(chain, authType);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- delegate.checkServerTrusted(chain, authType);
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
- throws CertificateException {
- if (delegate instanceof X509ExtendedTrustManager) {
- ((X509ExtendedTrustManager) delegate).checkClientTrusted(chain, authType, socket);
- } else {
- delegate.checkClientTrusted(chain, authType);
- }
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
- throws CertificateException {
- // Skip hostname check by calling base method
- delegate.checkServerTrusted(chain, authType);
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
- throws CertificateException {
- if (delegate instanceof X509ExtendedTrustManager) {
- ((X509ExtendedTrustManager) delegate).checkClientTrusted(chain, authType, engine);
- } else {
- delegate.checkClientTrusted(chain, authType);
- }
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
- throws CertificateException {
- // Skip hostname check by calling base method
- delegate.checkServerTrusted(chain, authType);
- }
-}
diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java
index 2c24ff12b6d36..442ac4840649e 100644
--- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java
+++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java
@@ -29,6 +29,7 @@
import org.apache.iotdb.consensus.config.RatisConfig;
import org.apache.iotdb.consensus.i18n.ConsensusMessages;
import org.apache.iotdb.rpc.AutoScalingBufferWriteTransport;
+import org.apache.iotdb.rpc.RpcSslUtils;
import org.apache.ratis.client.RaftClientConfigKeys;
import org.apache.ratis.conf.Parameters;
@@ -53,19 +54,12 @@
import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.AccessDeniedException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.KeyStore;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -371,31 +365,10 @@ public static Parameters initRatisConfig(RaftProperties properties, RatisConfig
String keyStorePassword = config.getGrpc().getSslKeyStorePassword();
String trustStorePath = config.getGrpc().getSslTrustStorePath();
String trustStorePassword = config.getGrpc().getSslTrustStorePassword();
- try (InputStream keyStoreStream = Files.newInputStream(Paths.get(keyStorePath));
- InputStream trustStoreStream = Files.newInputStream(Paths.get(trustStorePath))) {
- // === 1) create KeyManager ===
- KeyStore keyStore = KeyStore.getInstance("JKS");
- keyStore.load(keyStoreStream, keyStorePassword.toCharArray());
-
- KeyManagerFactory kmf =
- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(keyStore, keyStorePassword.toCharArray());
- KeyManager keyManager = kmf.getKeyManagers()[0];
-
- // === 2) create TrustManager ===
- KeyStore trustStore = KeyStore.getInstance("JKS");
- trustStore.load(trustStoreStream, trustStorePassword.toCharArray());
-
- TrustManagerFactory tmf =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(trustStore);
- TrustManager originalTrustManager = tmf.getTrustManagers()[0];
-
- // The self-signed certification may not set Subject Alternative Name (SAN)
- // Thrift with ssl didn't check it, but Grpc did.
- // Wrap to disable the verification
+ try {
+ KeyManager keyManager = RpcSslUtils.createKeyManagers(keyStorePath, keyStorePassword)[0];
TrustManager trustManager =
- new NoHostnameVerificationTrustManager((X509TrustManager) originalTrustManager);
+ RpcSslUtils.createTrustManagers(trustStorePath, trustStorePassword)[0];
GrpcConfigKeys.TLS.setConf(parameters, new GrpcTlsConfig(keyManager, trustManager, true));
} catch (AccessDeniedException e) {
LOGGER.error(ConsensusMessages.FAILED_TO_LOAD_KEYSTORE);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
index f6b7848d8ac9d..b7af9dcb201a4 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
@@ -45,6 +45,9 @@ public class IoTDBRestServiceConfig {
/** ssl trust Store password. */
private String trustStorePwd = "";
+ /** SSL protocol. */
+ private String sslProtocol = "";
+
/** ssl timeout. */
private int idleTimeoutInSeconds = 50000;
@@ -78,6 +81,14 @@ public void setTrustStorePwd(String trustStorePwd) {
this.trustStorePwd = trustStorePwd;
}
+ public String getSslProtocol() {
+ return sslProtocol;
+ }
+
+ public void setSslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ }
+
public int getIdleTimeoutInSeconds() {
return idleTimeoutInSeconds;
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
index 2e4ed0c28a6d0..807ef3054e712 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
@@ -23,6 +23,7 @@
import org.apache.iotdb.commons.conf.TrimProperties;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
+import org.apache.iotdb.rpc.RpcSslUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -108,6 +109,9 @@ private void loadProps(TrimProperties trimProperties) {
conf.setTrustStorePath(
trimProperties.getProperty("trust_store_path", conf.getTrustStorePath()));
conf.setTrustStorePwd(trimProperties.getProperty("trust_store_pwd", conf.getTrustStorePwd()));
+ conf.setSslProtocol(
+ RpcSslUtils.normalizeProtocol(
+ trimProperties.getProperty("ssl_protocol", conf.getSslProtocol())));
conf.setIdleTimeoutInSeconds(
Integer.parseInt(
trimProperties.getProperty(
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
index 12153a19eedb5..ec55111a200b4 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java
@@ -283,7 +283,8 @@ public void connect(TEndPoint endpoint, int timeoutMs) throws TException {
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
// As there is a try-catch already, we do not need to use TSocket.wrap
endpoint.getIp(), endpoint.getPort(), timeoutMs);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/an/AINodeClient.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/an/AINodeClient.java
index 46af33b3172d2..6efb5a8c02167 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/an/AINodeClient.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/an/AINodeClient.java
@@ -222,7 +222,8 @@ public void connect(TEndPoint endpoint, int timeoutMs) throws TException {
COMMON_CONFIG.getTrustStorePath(),
COMMON_CONFIG.getTrustStorePwd(),
COMMON_CONFIG.getKeyStorePath(),
- COMMON_CONFIG.getKeyStorePwd())
+ COMMON_CONFIG.getKeyStorePwd(),
+ COMMON_CONFIG.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
// As there is a try-catch already, we do not need to use TSocket.wrap
endpoint.getIp(), endpoint.getPort(), timeoutMs);
diff --git a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
index 1e855a9704c88..55a716f52813a 100644
--- a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
+++ b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
@@ -474,6 +474,14 @@ trust_store_path=
# Datatype: String
trust_store_pwd=
+# SSL protocol used by server-side SSL services.
+# The protocol is passed to the current JSSE provider, such as TLS, TLSv1.2,
+# TLSv1.3, or another provider-specific SSL protocol name.
+# effectiveMode: restart
+# Datatype: String
+# Privilege: SECURITY
+ssl_protocol=TLS
+
####################
### Connection Configuration
####################
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncAINodeClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncAINodeClient.java
index 054b644609958..636007107048e 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncAINodeClient.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncAINodeClient.java
@@ -63,7 +63,8 @@ public SyncAINodeClient(
COMMON_CONFIG.getTrustStorePath(),
COMMON_CONFIG.getTrustStorePwd(),
COMMON_CONFIG.getKeyStorePath(),
- COMMON_CONFIG.getKeyStorePwd())
+ COMMON_CONFIG.getKeyStorePwd(),
+ COMMON_CONFIG.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncConfigNodeIServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncConfigNodeIServiceClient.java
index ced2c92b4a0ef..323e00bace104 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncConfigNodeIServiceClient.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncConfigNodeIServiceClient.java
@@ -63,7 +63,8 @@ public SyncConfigNodeIServiceClient(
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeInternalServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeInternalServiceClient.java
index 854b4a4aa18b6..3f51cfa5d3e9c 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeInternalServiceClient.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeInternalServiceClient.java
@@ -64,7 +64,8 @@ public SyncDataNodeInternalServiceClient(
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeMPPDataExchangeServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeMPPDataExchangeServiceClient.java
index 4dcde11bfac6b..b4393bfd4eedd 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeMPPDataExchangeServiceClient.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncDataNodeMPPDataExchangeServiceClient.java
@@ -63,7 +63,8 @@ public SyncDataNodeMPPDataExchangeServiceClient(
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncIoTConsensusV2ServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncIoTConsensusV2ServiceClient.java
index 3073434c92186..0b74424277593 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncIoTConsensusV2ServiceClient.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/sync/SyncIoTConsensusV2ServiceClient.java
@@ -63,7 +63,8 @@ public SyncIoTConsensusV2ServiceClient(
commonConfig.getTrustStorePath(),
commonConfig.getTrustStorePwd(),
commonConfig.getKeyStorePath(),
- commonConfig.getKeyStorePwd())
+ commonConfig.getKeyStorePwd(),
+ commonConfig.getSslProtocol())
: DeepCopyRpcTransportFactory.INSTANCE.getTransport(
new TSocket(
TConfigurationConst.defaultTConfiguration,
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
index 6ec3478109eba..25315ba4c2f89 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java
@@ -499,6 +499,9 @@ public class CommonConfig {
/** ssl trust Store password. */
private String trustStorePwd = "";
+ /** SSL protocol. */
+ private String sslProtocol = "TLS";
+
private String userEncryptTokenHint = "not set yet";
private boolean enforceStrongPassword = false;
@@ -3009,6 +3012,14 @@ public void setTrustStorePwd(String trustStorePwd) {
this.trustStorePwd = trustStorePwd;
}
+ public String getSslProtocol() {
+ return sslProtocol;
+ }
+
+ public void setSslProtocol(String sslProtocol) {
+ this.sslProtocol = sslProtocol;
+ }
+
public boolean isEnforceStrongPassword() {
return enforceStrongPassword;
}
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
index 3242639c7e1a9..9c039cf25c207 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
@@ -24,6 +24,7 @@
import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
import org.apache.iotdb.confignode.rpc.thrift.TAuditConfig;
import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
+import org.apache.iotdb.rpc.RpcSslUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -658,5 +659,13 @@ public void initThriftSSL(TrimProperties properties) {
config.setTrustStorePath(
properties.getProperty("trust_store_path", config.getTrustStorePath()));
config.setTrustStorePwd(properties.getProperty("trust_store_pwd", config.getTrustStorePwd()));
+ config.setSslProtocol(
+ RpcSslUtils.normalizeProtocol(
+ properties.getProperty("ssl_protocol", config.getSslProtocol())));
+ configureRpcSsl();
+ }
+
+ public void configureRpcSsl() {
+ RpcSslUtils.configure(config.getSslProtocol());
}
}
diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
index 84361727a32e0..cd2716108cebd 100644
--- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
+++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java
@@ -24,6 +24,7 @@
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.exception.runtime.RPCServiceException;
import org.apache.iotdb.commons.i18n.ServiceMessages;
+import org.apache.iotdb.rpc.RpcSslUtils;
import org.apache.thrift.TBaseAsyncProcessor;
import org.apache.thrift.TProcessor;
@@ -45,13 +46,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.net.InetSocketAddress;
-import java.nio.file.AccessDeniedException;
-import java.security.KeyStore;
-import java.security.cert.X509Certificate;
-import java.util.Enumeration;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
@@ -184,13 +179,13 @@ protected AbstractThriftServiceThread(
this.serviceName = serviceName;
try {
- validateCertificate(keyStorePath, keyStorePwd);
+ RpcSslUtils.validateKeyStore(keyStorePath, keyStorePwd);
TSSLTransportFactory.TSSLTransportParameters params =
- new TSSLTransportFactory.TSSLTransportParameters();
- params.setKeyStore(keyStorePath, keyStorePwd);
+ RpcSslUtils.createTSSLTransportParameters();
+ RpcSslUtils.setKeyStore(params, keyStorePath, keyStorePwd);
if (trustStorePath != null && !trustStorePath.isEmpty()) {
- validateCertificate(trustStorePath, trustStorePwd);
- params.setTrustStore(trustStorePath, trustStorePwd);
+ RpcSslUtils.validateTrustStore(trustStorePath, trustStorePwd);
+ RpcSslUtils.setTrustStore(params, trustStorePath, trustStorePwd);
params.requireClientAuth(true);
}
InetSocketAddress socketAddress = new InetSocketAddress(bindAddress, port);
@@ -206,41 +201,6 @@ protected AbstractThriftServiceThread(
}
}
- private static void validateCertificate(String keyStorePath, String keystorePassword)
- throws TTransportException {
- try {
- KeyStore keystore = KeyStore.getInstance("JKS");
- try (FileInputStream fis = new FileInputStream(keyStorePath)) {
- keystore.load(fis, keystorePassword.toCharArray());
- }
-
- Enumeration aliases = keystore.aliases();
- while (aliases.hasMoreElements()) {
- String currentAlias = aliases.nextElement();
- checkCertificate(keystore, currentAlias);
- }
- } catch (AccessDeniedException e) {
- throw new TTransportException(ServiceMessages.FAILED_TO_LOAD_KEYSTORE_OR_TRUSTSTORE);
- } catch (FileNotFoundException e) {
- throw new TTransportException(ServiceMessages.KEYSTORE_OR_TRUSTSTORE_NOT_FOUND);
- } catch (Exception e) {
- throw new TTransportException(e);
- }
- }
-
- private static void checkCertificate(KeyStore keystore, String alias) throws Exception {
- if (!keystore.containsAlias(alias)) {
- return;
- }
-
- X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
- if (cert == null) {
- return;
- }
-
- cert.checkValidity();
- }
-
@SuppressWarnings("squid:S107")
protected AbstractThriftServiceThread(
TProcessor processor,
diff --git a/pom.xml b/pom.xml
index c577243cb0ac2..3f3b235f19a1e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,7 +119,7 @@
1.5.6
2.0.9
1.0.11
- 3.2.2
+ 3.3.0-adac7ef-SNAPSHOT
1.0.4
1.2.9
3.7.9
@@ -331,6 +331,16 @@
org.apache.ratis
ratis-common
${ratis.version}
+
+
+ io.opentelemetry
+ opentelemetry-api
+
+
+ io.opentelemetry
+ opentelemetry-context
+
+
org.apache.ratis