This is an automated email from the ASF dual-hosted git repository.
JackieTien97 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 4c2fd638a15 Add generic SSL/TLS configuration support (#17854)
4c2fd638a15 is described below
commit 4c2fd638a154ced095c503f6030e547e581cf4a9
Author: Haonan <[email protected]>
AuthorDate: Mon Jun 22 09:28:41 2026 +0800
Add generic SSL/TLS configuration support (#17854)
---
external-service-impl/rest/pom.xml | 12 -
.../java/org/apache/iotdb/rest/RestService.java | 9 +
.../iotdb/it/env/cluster/config/MppBaseConfig.java | 4 +
.../it/env/cluster/config/MppCommonConfig.java | 12 +
.../env/cluster/config/MppSharedCommonConfig.java | 14 ++
.../iotdb/it/env/cluster/env/AbstractEnv.java | 210 +++++++++++++-----
.../it/env/remote/config/RemoteCommonConfig.java | 10 +
.../org/apache/iotdb/itbase/env/CommonConfig.java | 4 +
.../apache/iotdb/session/it/IoTDBClientSSLIT.java | 233 ++++++++++++++++++++
integration-test/src/test/resources/test-keystore | Bin 2710 -> 2742 bytes
.../src/test/resources/test-truststore | Bin 1238 -> 1270 bytes
.../java/org/apache/iotdb/cli/AbstractCli.java | 14 ++
.../src/main/java/org/apache/iotdb/cli/Cli.java | 4 +
.../org/apache/iotdb/tool/common/Constants.java | 4 +
.../org/apache/iotdb/tool/common/OptionsUtil.java | 10 +
.../apache/iotdb/tool/data/AbstractDataTool.java | 37 ++++
.../apache/iotdb/tool/data/ExportDataTable.java | 3 +-
.../org/apache/iotdb/tool/data/ExportDataTree.java | 3 +-
.../apache/iotdb/tool/data/ImportDataTable.java | 3 +-
.../org/apache/iotdb/tool/data/ImportDataTree.java | 3 +-
.../iotdb/tool/schema/AbstractSchemaTool.java | 28 +++
.../iotdb/tool/schema/ExportSchemaTable.java | 3 +-
.../apache/iotdb/tool/schema/ExportSchemaTree.java | 3 +-
.../iotdb/tool/schema/ImportSchemaTable.java | 3 +-
.../apache/iotdb/tool/schema/ImportSchemaTree.java | 3 +-
.../org/apache/iotdb/isession/SessionConfig.java | 2 +
.../main/java/org/apache/iotdb/jdbc/Config.java | 4 +
.../org/apache/iotdb/jdbc/IoTDBConnection.java | 5 +-
.../apache/iotdb/jdbc/IoTDBConnectionParams.java | 9 +
.../src/main/java/org/apache/iotdb/jdbc/Utils.java | 6 +
.../test/java/org/apache/iotdb/jdbc/UtilsTest.java | 11 +
.../apache/iotdb/rpc/BaseRpcTransportFactory.java | 29 ++-
.../java/org/apache/iotdb/rpc/RpcSslUtils.java | 245 +++++++++++++++++++++
.../java/org/apache/iotdb/rpc/RpcUtilsTest.java | 7 +
.../iotdb/session/AbstractSessionBuilder.java | 1 +
.../org/apache/iotdb/session/NodesSupplier.java | 6 +
.../java/org/apache/iotdb/session/Session.java | 8 +
.../apache/iotdb/session/SessionConnection.java | 29 ++-
.../apache/iotdb/session/TableSessionBuilder.java | 12 +
.../org/apache/iotdb/session/ThriftConnection.java | 6 +-
.../org/apache/iotdb/session/pool/SessionPool.java | 13 ++
.../session/pool/TableSessionPoolBuilder.java | 12 +
.../iot/client/SyncIoTConsensusServiceClient.java | 3 +-
.../utils/NoHostnameVerificationTrustManager.java | 88 --------
.../apache/iotdb/consensus/ratis/utils/Utils.java | 35 +--
.../iotdb/db/conf/rest/IoTDBRestServiceConfig.java | 11 +
.../db/conf/rest/IoTDBRestServiceDescriptor.java | 4 +
.../iotdb/db/protocol/client/ConfigNodeClient.java | 3 +-
.../iotdb/db/protocol/client/an/AINodeClient.java | 3 +-
.../conf/iotdb-system.properties.template | 8 +
.../commons/client/sync/SyncAINodeClient.java | 3 +-
.../client/sync/SyncConfigNodeIServiceClient.java | 3 +-
.../sync/SyncDataNodeInternalServiceClient.java | 3 +-
.../SyncDataNodeMPPDataExchangeServiceClient.java | 3 +-
.../sync/SyncIoTConsensusV2ServiceClient.java | 3 +-
.../apache/iotdb/commons/conf/CommonConfig.java | 11 +
.../iotdb/commons/conf/CommonDescriptor.java | 9 +
.../service/AbstractThriftServiceThread.java | 52 +----
pom.xml | 12 +-
59 files changed, 1011 insertions(+), 277 deletions(-)
diff --git a/external-service-impl/rest/pom.xml
b/external-service-impl/rest/pom.xml
index fbc02b6dfb8..5287a25440c 100644
--- a/external-service-impl/rest/pom.xml
+++ b/external-service-impl/rest/pom.xml
@@ -38,13 +38,6 @@
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<scope>runtime</scope>
- <exclusions>
- <!-- repeated in node commons -->
- <exclusion>
- <groupId>jakarta.annotation</groupId>
- <artifactId>jakarta.annotation-api</artifactId>
- </exclusion>
- </exclusions>
</dependency>
<dependency>
<groupId>org.apache.iotdb</groupId>
@@ -87,11 +80,6 @@
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</exclusion>
- <!-- repeated in node commons -->
- <exclusion>
- <groupId>jakarta.annotation</groupId>
- <artifactId>jakarta.annotation-api</artifactId>
- </exclusion>
</exclusions>
</dependency>
<dependency>
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 acba4e30390..506facdb4ce 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.db.conf.rest.IoTDBRestServiceDescriptor;
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 @@ public class RestService implements IExternalService {
String trustStorePath,
String keyStorePwd,
String trustStorePwd,
+ String sslProtocol,
int idleTime,
boolean clientAuth) {
server = new Server();
@@ -61,6 +63,7 @@ public class RestService implements IExternalService {
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 class RestService implements IExternalService {
config.getTrustStorePath(),
config.getKeyStorePwd(),
config.getTrustStorePwd(),
+ config.getSslProtocol(),
config.getIdleTimeoutInSeconds(),
config.isClientAuth());
} else {
@@ -142,4 +146,9 @@ public class RestService implements IExternalService {
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 e0758de70c9..69b2e540e96 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 @@ public abstract class MppBaseConfig {
}
}
+ 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 d2743e89a8a..4dd7f857162 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
@@ -626,6 +626,12 @@ public class MppCommonConfig extends MppBaseConfig
implements CommonConfig {
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));
@@ -656,6 +662,12 @@ public class MppCommonConfig extends MppBaseConfig
implements CommonConfig {
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 708e7466ab1..8e0398de309 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
@@ -651,6 +651,13 @@ public class MppSharedCommonConfig implements CommonConfig
{
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);
@@ -686,6 +693,13 @@ public class MppSharedCommonConfig implements CommonConfig
{
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 df0b31090f5..342b4aba26d 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
@@ -688,6 +688,83 @@ public abstract class AbstractEnv implements BaseEnv {
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 {
@@ -769,7 +846,8 @@ public abstract class AbstractEnv implements BaseEnv {
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;
}
@@ -779,10 +857,11 @@ public abstract class AbstractEnv implements BaseEnv {
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;
@@ -794,11 +873,12 @@ public abstract class AbstractEnv implements BaseEnv {
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;
@@ -808,16 +888,17 @@ public abstract class AbstractEnv implements BaseEnv {
public ISession getSessionConnection(final List<String> 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;
@@ -827,8 +908,9 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -837,10 +919,11 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -849,23 +932,25 @@ public abstract class AbstractEnv implements BaseEnv {
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<String> 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();
}
@@ -873,12 +958,13 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -886,11 +972,12 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -898,12 +985,13 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -927,7 +1015,7 @@ public abstract class AbstractEnv implements BaseEnv {
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,
@@ -984,7 +1072,7 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -1031,7 +1119,7 @@ public abstract class AbstractEnv implements BaseEnv {
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();
}
@@ -1063,8 +1151,10 @@ public abstract class AbstractEnv implements BaseEnv {
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 7d9499773f0..a2d10c01009 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
@@ -442,6 +442,11 @@ public class RemoteCommonConfig implements CommonConfig {
return this;
}
+ @Override
+ public CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL) {
+ return this;
+ }
+
@Override
public CommonConfig setSubscriptionPrefetchTsFileBatchMaxDelayInMs(
int subscriptionPrefetchTsFileBatchMaxDelayInMs) {
@@ -479,6 +484,11 @@ public class RemoteCommonConfig implements CommonConfig {
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 9e446e97d34..5b51a6a8cf9 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
@@ -201,6 +201,8 @@ public interface CommonConfig {
CommonConfig setEnforceStrongPassword(boolean enforceStrongPassword);
+ CommonConfig setEnableThriftClientSSL(boolean enableThriftClientSSL);
+
CommonConfig setEnableInternalSSL(boolean enableInternalSSL);
CommonConfig setKeyStorePath(String keyStorePath);
@@ -211,6 +213,8 @@ public interface CommonConfig {
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 00000000000..23906fdb4c8
--- /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 2346c547259..76605794717 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 92c5b819f21..c6b93a476c5 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 3d8535aac3c..017f0a1a6ca 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 @@ public abstract class AbstractCli {
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 @@ public abstract class AbstractCli {
.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 d1bbd6165f6..a9e911be6ed 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 @@ public class Cli extends AbstractCli {
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 @@ public class Cli extends AbstractCli {
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 0d4c5f218b7..a1063260957 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 b60809eba63..1f79b303f6e 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 class OptionsUtil extends Constants {
.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 4ef95c78eda..6ea79a5b582 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.isession.SessionDataSet;
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 @@ public abstract class AbstractDataTool {
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 dcf05baa14e..458c447ba4f 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 class ExportDataTable extends AbstractExportData {
.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 9d7d0ca521d..fd8aeb0cbe3 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 class ExportDataTree extends AbstractExportData {
.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 506da8b8e17..d103c63555b 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 class ImportDataTable extends AbstractImportData {
.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 95aa9263142..c976e847740 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 class ImportDataTree extends AbstractImportData {
.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 09442bdab87..2bee5f5d331 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.IoTPrinter;
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 @@ public abstract class AbstractSchemaTool {
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 1ed3e2c6b86..c9b15870d21 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 class ExportSchemaTable extends AbstractExportSchema {
.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 334d8a8d8dc..da304f87c49 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 class ExportSchemaTree extends AbstractExportSchema {
.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 011042c34d2..004ec8b4152 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 class ImportSchemaTable extends AbstractImportSchema {
.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 9526447fd96..5d7dfc35d8a 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 class ImportSchemaTree extends AbstractImportSchema {
.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 611014c615c..7885d50cf5d 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 0b1049330ea..d79656cc8d2 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 @@ public class 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 7f37e2206fb..0dc81115dd0 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 @@ public class IoTDBConnection implements Connection {
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 1112caabd4e..8bf51379c5c 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 class IoTDBConnectionParams {
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 00e46cc340d..ea205ef7267 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 @@ public class Utils {
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 @@ public class Utils {
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 4c401b88017..d201a9b2d45 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 class UtilsTest {
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 22e104b6a58..03bf2070bca 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 class BaseRpcTransportFactory extends
TTransportFactory {
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 class BaseRpcTransportFactory extends
TTransportFactory {
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 00000000000..c6ceb5b4c5d
--- /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<String> 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 940c50453a2..143de1d9ab7 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 class RpcUtilsTest {
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 f410b167463..873e6dd248d 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 d57844b4997..a41db581e9c 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 class NodesSupplier implements INodeSupplier, Runnable
{
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
boolean enableRPCCompression,
String version) {
@@ -110,6 +112,7 @@ public class NodesSupplier implements INodeSupplier,
Runnable {
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableRPCCompression,
version);
@@ -132,6 +135,7 @@ public class NodesSupplier implements INodeSupplier,
Runnable {
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
boolean enableRPCCompression,
String version) {
this.availableNodes.addAll(new HashSet<>(endPointList));
@@ -140,6 +144,7 @@ public class NodesSupplier implements INodeSupplier,
Runnable {
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 @@ public class NodesSupplier implements INodeSupplier,
Runnable {
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 f352a0612e6..648a63845b4 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 class Session implements ISession {
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 class Session implements ISession {
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableRPCCompaction,
version.toString());
} else {
@@ -4435,6 +4438,11 @@ public class Session implements ISession {
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 c3e62cdd3e9..468b59abb0c 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 class 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 class 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 @@ public class SessionConnection {
}
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 @@ public class SessionConnection {
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 @@ public class SessionConnection {
}
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 be53797165a..e724c0fd532 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 class TableSessionBuilder extends
AbstractSessionBuilder {
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 e3b9e8fc989..3ab3abd581d 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 class ThriftConnection {
boolean useSSL,
String trustStore,
String trustStorePwd,
+ String sslProtocol,
String username,
String password,
boolean enableRPCCompression,
@@ -89,12 +90,13 @@ public class ThriftConnection {
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 3eaabe7f1fa..8136b2be68f 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 class SessionPool implements ISessionPool {
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 class SessionPool implements ISessionPool {
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 @@ public class SessionPool implements ISessionPool {
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
+ .sslProtocol(sslProtocol)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.sqlDialect(sqlDialect)
@@ -618,6 +624,7 @@ public class SessionPool implements ISessionPool {
.useSSL(useSSL)
.trustStore(trustStore)
.trustStorePwd(trustStorePwd)
+ .sslProtocol(sslProtocol)
.maxRetryCount(maxRetryCount)
.retryIntervalInMs(retryIntervalInMs)
.sqlDialect(sqlDialect)
@@ -662,6 +669,7 @@ public class SessionPool implements ISessionPool {
useSSL,
trustStore,
trustStorePwd,
+ sslProtocol,
enableThriftCompression,
version.toString());
}
@@ -3637,6 +3645,11 @@ public class SessionPool implements ISessionPool {
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 d5f52f3a8dc..2c7aba1a452 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 class TableSessionPoolBuilder extends
AbstractSessionPoolBuilder {
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 43b2f60d89f..3f3eb2d358e 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 class SyncIoTConsensusServiceClient extends
IoTConsensusIService.Client
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 fb5c9085488..00000000000
---
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 2c24ff12b6d..442ac484064 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.common.Peer;
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.Logger;
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 class Utils {
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 f6b7848d8ac..b7af9dcb201 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 class IoTDBRestServiceConfig {
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 2e4ed0c28a6..807ef3054e7 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.IoTDBConstant;
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 @@ public class IoTDBRestServiceDescriptor {
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 12153a19eed..ec55111a200 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 class ConfigNodeClient implements
IConfigNodeRPCService.Iface, ThriftClie
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 46af33b3172..6efb5a8c021 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 class AINodeClient implements
IAINodeRPCService.Iface, AutoCloseable, Thr
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 2bd65bb3f98..56f64fb8f12 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 054b6446099..63600710704 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 class SyncAINodeClient extends IAINodeRPCService.Client
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 ced2c92b4a0..323e00bace1 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 class SyncConfigNodeIServiceClient extends
IConfigNodeRPCService.Client
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 854b4a4aa18..3f51cfa5d3e 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 class SyncDataNodeInternalServiceClient extends
IDataNodeRPCService.Clien
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 4dcde11bfac..b4393bfd4ee 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 class SyncDataNodeMPPDataExchangeServiceClient extends
MPPDataExchangeSer
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 3073434c921..0b744242775 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 class SyncIoTConsensusV2ServiceClient extends
IoTConsensusV2IService.Clie
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 6ec3478109e..25315ba4c2f 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 class CommonConfig {
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 3242639c7e1..9c039cf25c2 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.pipe.config.PipeDescriptor;
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 class CommonDescriptor {
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 84361727a32..cd2716108ce 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.concurrent.threadpool.WrappedThreadPoolExecutor;
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.apache.thrift.transport.TTransportFactory;
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 @@ public abstract class AbstractThriftServiceThread extends
Thread {
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 @@ public abstract class AbstractThriftServiceThread extends
Thread {
}
}
- 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<String> 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 c577243cb0a..3f3b235f19a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,7 +119,7 @@
<pax-jdbc-common.version>1.5.6</pax-jdbc-common.version>
<powermock.version>2.0.9</powermock.version>
<ratis-thirdparty-misc.version>1.0.11</ratis-thirdparty-misc.version>
- <ratis.version>3.2.2</ratis.version>
+ <ratis.version>3.3.0-adac7ef-SNAPSHOT</ratis.version>
<reactive-streams.version>1.0.4</reactive-streams.version>
<reactor-netty.version>1.2.9</reactor-netty.version>
<reactor.version>3.7.9</reactor.version>
@@ -331,6 +331,16 @@
<groupId>org.apache.ratis</groupId>
<artifactId>ratis-common</artifactId>
<version>${ratis.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>io.opentelemetry</groupId>
+ <artifactId>opentelemetry-context</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.apache.ratis</groupId>