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 2e072d87961c0..85d0ee4476aca 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/RestService.java @@ -21,6 +21,7 @@ import org.apache.iotdb.externalservice.api.IExternalService; import org.apache.iotdb.rest.i18n.RestMessages; import org.apache.iotdb.rest.protocol.filter.ApiOriginFilter; +import org.apache.iotdb.rpc.RpcSslUtils; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.HttpConfiguration; @@ -52,6 +53,8 @@ private void startSSL( String trustStorePath, String keyStorePwd, String trustStorePwd, + String sslProtocol, + String sslProviderClass, int idleTime, boolean clientAuth) { server = new Server(); @@ -61,6 +64,7 @@ private void startSSL( httpsConfig.addCustomizer(new SecureRequestCustomizer()); SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + configureSSL(sslContextFactory, sslProtocol, sslProviderClass); sslContextFactory.setKeyStorePath(keyStorePath); sslContextFactory.setKeyStorePassword(keyStorePwd); if (clientAuth) { @@ -125,6 +129,8 @@ public void start() { config.getTrustStorePath(), config.getKeyStorePwd(), config.getTrustStorePwd(), + config.getSslProtocol(), + config.getSslProviderClass(), config.getIdleTimeoutInSeconds(), config.isClientAuth()); } else { @@ -142,4 +148,22 @@ public void stop() { server.destroy(); } } + + private void configureSSL( + SslContextFactory.Server sslContextFactory, String sslProtocol, String sslProviderClass) { + String protocol = trimToEmpty(sslProtocol); + try { + RpcSslUtils.ensureProvider(protocol, sslProviderClass); + } catch (Exception e) { + throw new IllegalArgumentException("Failed to initialize SSL provider for REST service", e); + } + if (!protocol.isEmpty()) { + sslContextFactory.setProtocol(protocol); + sslContextFactory.setIncludeProtocols(protocol); + } + } + + private String trimToEmpty(String value) { + return value == null ? "" : value.trim(); + } } 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 22ecdc3a40ed1..1f079450f5a54 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,18 @@ public abstract class AbstractCli { static final String TRUST_STORE_PWD_ARGS = "tpw"; + static final String SSL_PROTOCOL_ARGS = "ssl_protocol"; + + static final String SSL_PROVIDER_CLASS_ARGS = "ssl_provider_class"; + 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 SSL_PROVIDER_CLASS = "ssl_provider_class"; private static final String NULL = "null"; static final int CODE_OK = 0; @@ -132,6 +138,10 @@ public abstract class AbstractCli { static String trustStore; // TODO: Make non-static static String trustStorePwd; + // TODO: Make non-static + static String sslProtocol; + // TODO: Make non-static + static String sslProviderClass; static String execute; static boolean hasExecuteSQL = false; @@ -156,6 +166,10 @@ static void init() { keywordSet.add("-" + USE_SSL_ARGS); keywordSet.add("-" + TRUST_STORE_ARGS); keywordSet.add("-" + TRUST_STORE_PWD_ARGS); + keywordSet.add("-" + SSL_PROTOCOL_ARGS); + keywordSet.add("--" + SSL_PROTOCOL_ARGS); + keywordSet.add("-" + SSL_PROVIDER_CLASS_ARGS); + keywordSet.add("--" + SSL_PROVIDER_CLASS_ARGS); keywordSet.add("-" + EXECUTE_ARGS); keywordSet.add("-" + ISO8601_ARGS); keywordSet.add("-" + RPC_COMPRESS_ARGS); @@ -214,6 +228,24 @@ static Options createOptions() { .build(); options.addOption(useSSL); + Option sslProtocol = + Option.builder(SSL_PROTOCOL_ARGS) + .longOpt(SSL_PROTOCOL) + .argName(SSL_PROTOCOL) + .hasArg() + .desc("SSL protocol. (optional)") + .build(); + options.addOption(sslProtocol); + + Option sslProviderClass = + Option.builder(SSL_PROVIDER_CLASS_ARGS) + .longOpt(SSL_PROVIDER_CLASS) + .argName(SSL_PROVIDER_CLASS) + .hasArg() + .desc("JSSE provider class for SSL. (optional)") + .build(); + options.addOption(sslProviderClass); + Option execute = Option.builder(EXECUTE_ARGS) .argName(EXECUTE_NAME) diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/Cli.java index d1bbd6165f694..f4e3e6bdfddf5 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,12 @@ private static void constructProperties() { info.setProperty("use_ssl", useSsl); info.setProperty("trust_store", trustStore); info.setProperty("trust_store_pwd", trustStorePwd); + if (sslProtocol != null) { + info.setProperty(Config.SSL_PROTOCOL, sslProtocol); + } + if (sslProviderClass != null) { + info.setProperty(Config.SSL_PROVIDER_CLASS, sslProviderClass); + } } info.setProperty("user", username); info.setProperty("password", password); @@ -159,6 +165,8 @@ private static boolean parseCommandLine( private static void serve(CliContext ctx) { try { useSsl = commandLine.getOptionValue(USE_SSL_ARGS); + sslProtocol = commandLine.getOptionValue(SSL_PROTOCOL_ARGS); + sslProviderClass = commandLine.getOptionValue(SSL_PROVIDER_CLASS_ARGS); if (Boolean.parseBoolean(useSsl)) { trustStore = ctx.getLineReader().readLine("please input your trust_store:", '\0'); trustStorePwd = ctx.getLineReader().readLine("please input your trust_store_pwd:", '\0'); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/Constants.java index 0d4c5f218b73b..56c34dbdf0387 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,14 @@ 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 SSL_PROVIDER_CLASS_ARGS = "ssl_provider_class"; + public static final String SSL_PROVIDER_CLASS_NAME = "ssl_provider_class"; + public static final String SSL_PROVIDER_CLASS_DESC = "JSSE provider class for SSL. (optional)"; + public static final String FILE_TYPE_ARGS = "ft"; public static final String FILE_TYPE_NAME = "file_type"; public static final String FILE_TYPE_ARGS_NAME = "format"; diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/common/OptionsUtil.java index b60809eba636a..acbac88afbed6 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,26 @@ public static Options createCommonOptions(Options options) { .build(); options.addOption(opTrustStorePwd); + Option opSslProtocol = + Option.builder(SSL_PROTOCOL_ARGS) + .longOpt(SSL_PROTOCOL_NAME) + .optionalArg(true) + .argName(SSL_PROTOCOL_NAME) + .hasArg() + .desc(SSL_PROTOCOL_DESC) + .build(); + options.addOption(opSslProtocol); + + Option opSslProviderClass = + Option.builder(SSL_PROVIDER_CLASS_ARGS) + .longOpt(SSL_PROVIDER_CLASS_NAME) + .optionalArg(true) + .argName(SSL_PROVIDER_CLASS_NAME) + .hasArg() + .desc(SSL_PROVIDER_CLASS_DESC) + .build(); + options.addOption(opSslProviderClass); + return options; } diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java index 4ef95c78eda14..5a9b14f333715 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/AbstractDataTool.java @@ -34,6 +34,9 @@ import org.apache.iotdb.rpc.IoTDBConnectionException; import org.apache.iotdb.rpc.StatementExecutionException; import org.apache.iotdb.session.Session; +import org.apache.iotdb.session.TableSessionBuilder; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.iotdb.session.pool.TableSessionPoolBuilder; import org.apache.iotdb.tool.common.Constants; import org.apache.iotdb.tool.common.ImportTsFileOperation; @@ -94,6 +97,8 @@ public abstract class AbstractDataTool { protected static Boolean useSsl; protected static String trustStore; protected static String trustStorePwd; + protected static String sslProtocol; + protected static String sslProviderClass; protected static Boolean aligned; protected static String database; protected static String startTime; @@ -134,6 +139,50 @@ 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); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + + protected static SessionPool.Builder configureSsl(SessionPool.Builder builder) { + builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + if (sslProtocol != null) { + builder.sslProtocol(sslProtocol); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + + protected static TableSessionBuilder configureSsl(TableSessionBuilder builder) { + builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + if (sslProtocol != null) { + builder.sslProtocol(sslProtocol); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + + protected static TableSessionPoolBuilder configureSsl(TableSessionPoolBuilder builder) { + builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + if (sslProtocol != null) { + builder.sslProtocol(sslProtocol); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + protected static String checkRequiredArg( String arg, String name, CommandLine commandLine, String defaultValue) throws ArgsErrorException { @@ -170,6 +219,8 @@ protected static void parseBasicParams(CommandLine commandLine) String useSslStr = commandLine.getOptionValue(Constants.USE_SSL_ARGS); useSsl = Boolean.parseBoolean(useSslStr); if (useSsl) { + sslProtocol = commandLine.getOptionValue(Constants.SSL_PROTOCOL_ARGS); + sslProviderClass = commandLine.getOptionValue(Constants.SSL_PROVIDER_CLASS_ARGS); String givenTS = commandLine.getOptionValue(Constants.TRUST_STORE_ARGS); if (givenTS != null) { trustStore = givenTS; diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java index dcf05baa14e66..458c447ba4f5b 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTable.java @@ -71,8 +71,7 @@ public void init() throws IoTDBConnectionException, StatementExecutionException .database(database) .thriftMaxFrameSize(rpcMaxFrameSize); if (useSsl) { - tableSessionBuilder = - tableSessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + tableSessionBuilder = configureSsl(tableSessionBuilder); } tableSession = tableSessionBuilder.build(); SessionDataSet sessionDataSet = tableSession.executeQueryStatement("show databases", timeout); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java index 9d7d0ca521d09..fd8aeb0cbe352 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ExportDataTree.java @@ -80,8 +80,7 @@ public void init() throws IoTDBConnectionException, StatementExecutionException, .enableRedirection(SessionConfig.DEFAULT_REDIRECTION_MODE) .version(SessionConfig.DEFAULT_VERSION); if (useSsl) { - sessionBuilder = - sessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + sessionBuilder = configureSsl(sessionBuilder); } session = sessionBuilder.build(); session.open(false); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java index 506da8b8e17ce..d103c63555b67 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTable.java @@ -88,8 +88,7 @@ public void init() throws InterruptedException { .enableAutoFetch(false) .database(database); if (useSsl) { - tableSessionPoolBuilder = - tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder); } sessionPool = tableSessionPoolBuilder.build(); final File file = new File(targetPath); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java index 95aa92631422a..c976e847740d2 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/data/ImportDataTree.java @@ -72,8 +72,7 @@ public void init() .enableRedirection(false) .enableAutoFetch(false); if (useSsl) { - sessionPoolBuilder = - sessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + sessionPoolBuilder = configureSsl(sessionPoolBuilder); } sessionPool = sessionPoolBuilder.build(); sessionPool.setEnableQueryRedirection(false); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java index 09442bdab878f..7a18b84f559e7 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/AbstractSchemaTool.java @@ -25,6 +25,8 @@ import org.apache.iotdb.cli.utils.JlineUtils; import org.apache.iotdb.exception.ArgsErrorException; import org.apache.iotdb.session.Session; +import org.apache.iotdb.session.pool.SessionPool; +import org.apache.iotdb.session.pool.TableSessionPoolBuilder; import org.apache.iotdb.tool.common.Constants; import org.apache.commons.cli.CommandLine; @@ -53,6 +55,8 @@ public abstract class AbstractSchemaTool { protected static Boolean useSsl; protected static String trustStore; protected static String trustStorePwd; + protected static String sslProtocol; + protected static String sslProviderClass; protected static Session session; protected static String queryPath; protected static int threadNum = 8; @@ -73,6 +77,39 @@ 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); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + + protected static SessionPool.Builder configureSsl(SessionPool.Builder builder) { + builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + if (sslProtocol != null) { + builder.sslProtocol(sslProtocol); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + + protected static TableSessionPoolBuilder configureSsl(TableSessionPoolBuilder builder) { + builder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + if (sslProtocol != null) { + builder.sslProtocol(sslProtocol); + } + if (sslProviderClass != null) { + builder.sslProviderClass(sslProviderClass); + } + return builder; + } + protected static String checkRequiredArg( String arg, String name, CommandLine commandLine, String defaultValue) throws ArgsErrorException { @@ -107,6 +144,8 @@ protected static void parseBasicParams(CommandLine commandLine) String useSslStr = commandLine.getOptionValue(Constants.USE_SSL_ARGS); useSsl = Boolean.parseBoolean(useSslStr); if (useSsl) { + sslProtocol = commandLine.getOptionValue(Constants.SSL_PROTOCOL_ARGS); + sslProviderClass = commandLine.getOptionValue(Constants.SSL_PROVIDER_CLASS_ARGS); String givenTS = commandLine.getOptionValue(Constants.TRUST_STORE_ARGS); if (givenTS != null) { trustStore = givenTS; diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java index 1ed3e2c6b862a..c9b15870d2175 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTable.java @@ -64,8 +64,7 @@ public void init() throws InterruptedException { .enableAutoFetch(false) .database(database); if (useSsl) { - tableSessionPoolBuilder = - tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder); } sessionPool = tableSessionPoolBuilder.build(); checkDatabase(); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java index 334d8a8d8dc42..da304f87c4986 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ExportSchemaTree.java @@ -51,8 +51,7 @@ public void init() .username(username) .password(password); if (useSsl) { - sessionBuilder = - sessionBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + sessionBuilder = configureSsl(sessionBuilder); } session = sessionBuilder.build(); session.open(false); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java index 011042c34d29c..004ec8b4152bb 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTable.java @@ -60,8 +60,7 @@ public void init() throws InterruptedException { .enableAutoFetch(false) .database(database); if (useSsl) { - tableSessionPoolBuilder = - tableSessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + tableSessionPoolBuilder = configureSsl(tableSessionPoolBuilder); } sessionPool = tableSessionPoolBuilder.build(); final File file = new File(targetPath); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java index 9526447fd9654..5d7dfc35d8a0d 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/schema/ImportSchemaTree.java @@ -73,8 +73,7 @@ public void init() .enableRedirection(false) .enableAutoFetch(false); if (useSsl) { - sessionPoolBuilder = - sessionPoolBuilder.useSSL(true).trustStore(trustStore).trustStorePwd(trustStorePwd); + sessionPoolBuilder = configureSsl(sessionPoolBuilder); } sessionPool = sessionPoolBuilder.build(); sessionPool.setEnableQueryRedirection(false); diff --git a/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java b/iotdb-client/isession/src/main/java/org/apache/iotdb/isession/SessionConfig.java index 611014c615c3b..0a577c45f2d74 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,9 @@ public class SessionConfig { public static final String SQL_DIALECT = "tree"; + public static final String DEFAULT_SSL_PROTOCOL = "TLS"; + + public static final String DEFAULT_SSL_PROVIDER_CLASS = ""; + private SessionConfig() {} } diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Config.java index 0b1049330eae7..5aaf0f6836641 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,14 @@ private Config() { public static final String TRUST_STORE_PWD = "trust_store_pwd"; + public static final String SSL_PROTOCOL = "ssl_protocol"; + + public static final String SSL_PROVIDER_CLASS = "ssl_provider_class"; + + static final String DEFAULT_SSL_PROTOCOL = "TLS"; + + static final String DEFAULT_SSL_PROVIDER_CLASS = ""; + public static final String SQL_DIALECT = "sql_dialect"; public static final String DATABASE = "db"; diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnection.java index 7f37e2206fb87..9b95939864d4a 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,14 @@ private void openTransport() throws TTransportException { if (params.isUseSSL()) { transport = - DeepCopyRpcTransportFactory.INSTANCE.getTransport( + DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig( params.getHost(), params.getPort(), getNetworkTimeout(), params.getTrustStore(), - params.getTrustStorePwd()); + params.getTrustStorePwd(), + params.getSslProtocol(), + params.getSslProviderClass()); } else { transport = DeepCopyRpcTransportFactory.INSTANCE.getTransport( diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBConnectionParams.java index 1112caabd4e20..4ae629e74b17c 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,8 @@ public class IoTDBConnectionParams { private boolean useSSL = false; private String trustStore; private String trustStorePwd; + private String sslProtocol = Config.DEFAULT_SSL_PROTOCOL; + private String sslProviderClass = Config.DEFAULT_SSL_PROVIDER_CLASS; private String sqlDialect = TREE; @@ -184,6 +186,22 @@ public void setTrustStorePwd(String trustStorePwd) { this.trustStorePwd = trustStorePwd; } + public String getSslProtocol() { + return sslProtocol; + } + + public void setSslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + } + + public String getSslProviderClass() { + return sslProviderClass; + } + + public void setSslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + } + public String getSqlDialect() { return sqlDialect; } diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/Utils.java index 00e46cc340d15..8bd394cf11547 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 @@ -136,6 +136,12 @@ static IoTDBConnectionParams parseUrl(String url, Properties info) throws IoTDBU if (info.containsKey(Config.TRUST_STORE_PWD)) { params.setTrustStorePwd(info.getProperty(Config.TRUST_STORE_PWD)); } + if (info.containsKey(Config.SSL_PROTOCOL)) { + params.setSslProtocol(info.getProperty(Config.SSL_PROTOCOL)); + } + if (info.containsKey(Config.SSL_PROVIDER_CLASS)) { + params.setSslProviderClass(info.getProperty(Config.SSL_PROVIDER_CLASS)); + } if (info.containsKey(Config.SQL_DIALECT)) { params.setSqlDialect(info.getProperty(Config.SQL_DIALECT)); } @@ -175,6 +181,8 @@ private static boolean parseUrlParam(String subURL, Properties info) { case Config.USE_SSL: case Config.TRUST_STORE: case Config.TRUST_STORE_PWD: + case Config.SSL_PROTOCOL: + case Config.SSL_PROVIDER_CLASS: case Config.VERSION: case Config.NETWORK_TIMEOUT: case Config.SQL_DIALECT: diff --git a/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java b/iotdb-client/jdbc/src/test/java/org/apache/iotdb/jdbc/UtilsTest.java index 4c401b88017af..32dd7a78a6dd7 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,18 @@ public void testRpcCompress() throws IoTDBURLException { Utils.parseUrl("jdbc:iotdb://127.0.0.1:6667?rpc_compress=true", properties); assertTrue(Config.rpcThriftCompressionEnable); } + + @Test + public void testParseSslConfig() throws IoTDBURLException { + Properties properties = new Properties(); + IoTDBConnectionParams params = + Utils.parseUrl( + "jdbc:iotdb://127.0.0.1:6667?use_ssl=true&ssl_protocol=TLSv1.3" + + "&ssl_provider_class=com.example.ssl.Provider", + properties); + + assertTrue(params.isUseSSL()); + assertEquals("TLSv1.3", params.getSslProtocol()); + assertEquals("com.example.ssl.Provider", params.getSslProviderClass()); + } } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/BaseRpcTransportFactory.java index 22e104b6a58ac..58d8abbc60e1a 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 @@ -84,8 +84,24 @@ public TTransport getTransport( String ip, int port, int timeout, String trustStore, String trustStorePwd) throws TTransportException { TSSLTransportFactory.TSSLTransportParameters params = - new TSSLTransportFactory.TSSLTransportParameters(); - params.setTrustStore(trustStore, trustStorePwd); + RpcSslUtils.createTSSLTransportParameters(); + RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd); + TTransport transport = TSSLTransportFactory.getClientSocket(ip, port, timeout, params); + return inner.getTransport(transport); + } + + public TTransport getTransportWithSSLConfig( + String ip, + int port, + int timeout, + String trustStore, + String trustStorePwd, + String sslProtocol, + String sslProviderClass) + throws TTransportException { + TSSLTransportFactory.TSSLTransportParameters params = + RpcSslUtils.createTSSLTransportParameters(sslProtocol, sslProviderClass, null); + RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd, sslProtocol, sslProviderClass); TTransport transport = TSSLTransportFactory.getClientSocket(ip, port, timeout, params); return inner.getTransport(transport); } @@ -100,10 +116,33 @@ public TTransport getTransport( String keyStorePwd) throws TTransportException { TSSLTransportFactory.TSSLTransportParameters params = - new TSSLTransportFactory.TSSLTransportParameters(); + RpcSslUtils.createTSSLTransportParameters(); + if (Files.exists(Paths.get(trustStore)) && Files.exists(Paths.get(keyStore))) { + RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd); + RpcSslUtils.setKeyStore(params, keyStore, keyStorePwd); + } else { + throw new TTransportException(new IOException(RpcMessages.COULD_NOT_LOAD_KEYSTORE)); + } + TTransport transport = TSSLTransportFactory.getClientSocket(ip, port, timeout, params); + return inner.getTransport(transport); + } + + public TTransport getTransport( + String ip, + int port, + int timeout, + String trustStore, + String trustStorePwd, + String keyStore, + String keyStorePwd, + String sslProtocol, + String sslProviderClass) + throws TTransportException { + TSSLTransportFactory.TSSLTransportParameters params = + RpcSslUtils.createTSSLTransportParameters(sslProtocol, sslProviderClass, null); if (Files.exists(Paths.get(trustStore)) && Files.exists(Paths.get(keyStore))) { - params.setTrustStore(trustStore, trustStorePwd); - params.setKeyStore(keyStore, keyStorePwd); + RpcSslUtils.setTrustStore(params, trustStore, trustStorePwd, sslProtocol, sslProviderClass); + RpcSslUtils.setKeyStore(params, keyStore, keyStorePwd, sslProtocol, sslProviderClass); } else { throw new TTransportException(new IOException(RpcMessages.COULD_NOT_LOAD_KEYSTORE)); } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java new file mode 100644 index 0000000000000..cfd0dca615e01 --- /dev/null +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcSslUtils.java @@ -0,0 +1,422 @@ +/* + * 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.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.nio.file.AccessDeniedException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.Provider; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Arrays; +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 SslConfig config = new SslConfig(DEFAULT_PROTOCOL, "", null); + + private RpcSslUtils() {} + + public static void configure(String protocol, String providerClass, String cipherSuites) { + config = newSslConfig(protocol, providerClass, cipherSuites); + } + + public static void ensureProvider(String protocol, String providerClass) + throws TTransportException { + ensureProvider(newSslConfig(protocol, providerClass, null)); + } + + public static TSSLTransportFactory.TSSLTransportParameters createTSSLTransportParameters() + throws TTransportException { + SslConfig current = config; + ensureProvider(current); + return createTSSLTransportParameters(current); + } + + public static TSSLTransportFactory.TSSLTransportParameters createTSSLTransportParameters( + String protocol, String providerClass, String cipherSuites) throws TTransportException { + SslConfig current = newSslConfig(protocol, providerClass, cipherSuites); + ensureProvider(current); + return createTSSLTransportParameters(current); + } + + private static TSSLTransportFactory.TSSLTransportParameters createTSSLTransportParameters( + SslConfig current) { + return new TSSLTransportFactory.TSSLTransportParameters(current.protocol, current.cipherSuites); + } + + public static void setKeyStore( + TSSLTransportFactory.TSSLTransportParameters params, String keyStorePath, String keyStorePwd) + throws TTransportException { + setKeyStore(params, keyStorePath, keyStorePwd, config); + } + + public static void setKeyStore( + TSSLTransportFactory.TSSLTransportParameters params, + String keyStorePath, + String keyStorePwd, + String protocol, + String providerClass) + throws TTransportException { + setKeyStore(params, keyStorePath, keyStorePwd, newSslConfig(protocol, providerClass, null)); + } + + private static void setKeyStore( + TSSLTransportFactory.TSSLTransportParameters params, + String keyStorePath, + String keyStorePwd, + SslConfig current) + throws TTransportException { + try { + ensureProvider(current); + 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 { + setTrustStore(params, trustStorePath, trustStorePwd, config); + } + + public static void setTrustStore( + TSSLTransportFactory.TSSLTransportParameters params, + String trustStorePath, + String trustStorePwd, + String protocol, + String providerClass) + throws TTransportException { + setTrustStore( + params, trustStorePath, trustStorePwd, newSslConfig(protocol, providerClass, null)); + } + + private static void setTrustStore( + TSSLTransportFactory.TSSLTransportParameters params, + String trustStorePath, + String trustStorePwd, + SslConfig current) + throws TTransportException { + try { + ensureProvider(current); + 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, TTransportException { + return createSSLContext( + keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, config); + } + + public static SSLContext createSSLContext( + String keyStorePath, + String keyStorePassword, + String trustStorePath, + String trustStorePassword, + String protocol, + String providerClass, + String cipherSuites) + throws GeneralSecurityException, IOException, TTransportException { + return createSSLContext( + keyStorePath, + keyStorePassword, + trustStorePath, + trustStorePassword, + newSslConfig(protocol, providerClass, cipherSuites)); + } + + private static SSLContext createSSLContext( + String keyStorePath, + String keyStorePassword, + String trustStorePath, + String trustStorePassword, + SslConfig current) + throws GeneralSecurityException, IOException, TTransportException { + ensureProvider(current); + SSLContext context = newSSLContext(current); + 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, TTransportException { + ensureProvider(config); + return loadKeyManagers(keyStorePath, keyStorePassword); + } + + public static TrustManager[] createTrustManagers(String trustStorePath, String trustStorePassword) + throws GeneralSecurityException, IOException, TTransportException { + ensureProvider(config); + return loadTrustManagers(trustStorePath, trustStorePassword); + } + + public static String getProtocol() { + return config.protocol; + } + + public static String[] getCipherSuites() { + SslConfig current = config; + return current.cipherSuites == null + ? null + : Arrays.copyOf(current.cipherSuites, current.cipherSuites.length); + } + + public static boolean hasConfiguredProvider() { + return hasText(config.providerClass); + } + + public static String getSSLContextProviderName() throws TTransportException { + ensureProvider(config); + try { + return newSSLContext(config).getProvider().getName(); + } catch (GeneralSecurityException e) { + throw new TTransportException("Failed to initialize SSL context", e); + } + } + + public static String[] getEnabledCipherSuites() throws TTransportException { + ensureProvider(config); + try { + SSLContext context = newSSLContext(config); + context.init(null, null, null); + SSLEngine engine = context.createSSLEngine(); + return engine.getEnabledCipherSuites(); + } catch (GeneralSecurityException e) { + throw new TTransportException("Failed to initialize SSL context", e); + } + } + + 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 SSLContext newSSLContext(SslConfig current) throws GeneralSecurityException { + return SSLContext.getInstance(current.protocol); + } + + 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 (FileInputStream fis = new FileInputStream(storePath)) { + store.load(fis, toPassword(storePassword)); + } catch (AccessDeniedException e) { + throw new AccessDeniedException("Failed to load keystore or truststore file"); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("keystore or truststore file not found: " + storePath); + } + return store; + } + + private static void validateStore(String storePath, String storePassword) + throws TTransportException { + try { + ensureProvider(config); + KeyStore store = loadStore(storePath, storePassword); + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) { + X509Certificate cert = (X509Certificate) store.getCertificate(aliases.nextElement()); + if (cert != null) { + cert.checkValidity(); + } + } + } catch (Exception e) { + throw new TTransportException(e); + } + } + + private static synchronized void ensureProvider(SslConfig current) throws TTransportException { + if (!hasText(current.providerClass)) { + return; + } + try { + String[] providerClassNames = splitProviderClasses(current.providerClass); + for (int i = providerClassNames.length - 1; i >= 0; i--) { + String providerClassName = providerClassNames[i]; + Class providerClass = Class.forName(providerClassName); + Constructor constructor = providerClass.getDeclaredConstructor(); + constructor.setAccessible(true); + Provider provider = (Provider) constructor.newInstance(); + Provider firstProvider = Security.getProviders()[0]; + if (!provider.getName().equals(firstProvider.getName())) { + Security.removeProvider(provider.getName()); + Security.insertProviderAt(provider, 1); + } + } + } catch (Exception e) { + throw new TTransportException("Failed to initialize SSL provider", e); + } + } + + private static char[] toPassword(String password) { + return password == null ? null : password.toCharArray(); + } + + private static String trimToDefault(String value, String defaultValue) { + String trimmed = trimToEmpty(value); + return trimmed.isEmpty() ? defaultValue : 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[] splitCipherSuites(String cipherSuites) { + if (!hasText(cipherSuites)) { + return null; + } + return splitCommaSeparated(cipherSuites); + } + + private static String[] splitProviderClasses(String providerClasses) { + return splitCommaSeparated(providerClasses); + } + + private static String[] splitCommaSeparated(String value) { + return Stream.of(value.split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .toArray(String[]::new); + } + + 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); + } + + private static SslConfig newSslConfig( + String protocol, String providerClass, String cipherSuites) { + return new SslConfig( + trimToDefault(protocol, DEFAULT_PROTOCOL), + trimToEmpty(providerClass), + splitCipherSuites(cipherSuites)); + } + + private static final class SslConfig { + private final String protocol; + private final String providerClass; + private final String[] cipherSuites; + + private SslConfig(String protocol, String providerClass, String[] cipherSuites) { + this.protocol = protocol; + this.providerClass = providerClass; + this.cipherSuites = + cipherSuites == null ? null : Arrays.copyOf(cipherSuites, cipherSuites.length); + } + } +} 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 f6132d8041f1b..2fe601f994dbb 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 @@ -62,6 +62,8 @@ public abstract class AbstractSessionBuilder { public boolean useSSL = false; public String trustStore; public String trustStorePwd; + public String sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL; + public String sslProviderClass = SessionConfig.DEFAULT_SSL_PROVIDER_CLASS; // max retry count, if set to 0, means that we won't do any retry // we can use any available DataNodes(fetched in background thread if enableAutoFetch is true, diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/NodesSupplier.java index d57844b499705..c6c2288b8b2d2 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,8 @@ public class NodesSupplier implements INodeSupplier, Runnable { private final boolean useSSL; private final String trustStore; private final String trustStorePwd; + private final String sslProtocol; + private final String sslProviderClass; private final boolean enableRPCCompression; private final String userName; @@ -95,6 +97,8 @@ public static NodesSupplier createNodeSupplier( boolean useSSL, String trustStore, String trustStorePwd, + String sslProtocol, + String sslProviderClass, boolean enableRPCCompression, String version) { @@ -110,6 +114,8 @@ public static NodesSupplier createNodeSupplier( useSSL, trustStore, trustStorePwd, + sslProtocol, + sslProviderClass, enableRPCCompression, version); @@ -132,6 +138,8 @@ private NodesSupplier( boolean useSSL, String trustStore, String trustStorePwd, + String sslProtocol, + String sslProviderClass, boolean enableRPCCompression, String version) { this.availableNodes.addAll(new HashSet<>(endPointList)); @@ -140,6 +148,8 @@ private NodesSupplier( this.useSSL = useSSL; this.trustStore = trustStore; this.trustStorePwd = trustStorePwd; + this.sslProtocol = sslProtocol; + this.sslProviderClass = sslProviderClass; this.enableRPCCompression = enableRPCCompression; this.zoneId = zoneId == null ? ZoneId.systemDefault() : zoneId; this.thriftDefaultBufferSize = thriftDefaultBufferSize; @@ -188,6 +198,8 @@ private boolean createConnection(TEndPoint endPoint) { useSSL, trustStore, trustStorePwd, + sslProtocol, + sslProviderClass, 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 b92df62f5ad5b..81798b046ba9e 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 @@ -133,6 +133,8 @@ public class Session implements ISession { protected boolean useSSL; protected String trustStore; protected String trustStorePwd; + protected String sslProtocol; + protected String sslProviderClass; /** * Timeout of query can be set by users. A negative number means using the default configuration @@ -472,6 +474,8 @@ public Session(AbstractSessionBuilder builder) { this.useSSL = builder.useSSL; this.trustStore = builder.trustStore; this.trustStorePwd = builder.trustStorePwd; + this.sslProtocol = builder.sslProtocol; + this.sslProviderClass = builder.sslProviderClass; this.enableAutoFetch = builder.enableAutoFetch; this.maxRetryCount = builder.maxRetryCount; this.retryIntervalInMs = builder.retryIntervalInMs; @@ -541,6 +545,8 @@ public synchronized void open(boolean enableRPCCompaction, int connectionTimeout useSSL, trustStore, trustStorePwd, + sslProtocol, + sslProviderClass, enableRPCCompaction, version.toString()); } else { @@ -4433,6 +4439,16 @@ public Builder trustStorePwd(String trustStorePwd) { return this; } + public Builder sslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + return this; + } + + public Builder sslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + 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 f6608d8fe4bfe..e12ccdcc0c5e2 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 @@ -151,7 +151,13 @@ public SessionConnection( this.sqlDialect = sqlDialect; this.database = database; try { - init(endPoint, session.useSSL, session.trustStore, session.trustStorePwd); + init( + endPoint, + session.useSSL, + session.trustStore, + session.trustStorePwd, + session.sslProtocol, + session.sslProviderClass); } catch (StatementExecutionException e) { throw new IoTDBConnectionException(e.getMessage()); } catch (IoTDBConnectionException e) { @@ -179,7 +185,13 @@ public SessionConnection( initClusterConn(); } - private void init(TEndPoint endPoint, boolean useSSL, String trustStore, String trustStorePwd) + private void init( + TEndPoint endPoint, + boolean useSSL, + String trustStore, + String trustStorePwd, + String sslProtocol, + String sslProviderClass) throws IoTDBConnectionException, StatementExecutionException { DeepCopyRpcTransportFactory.setDefaultBufferCapacity(session.thriftDefaultBufferSize); DeepCopyRpcTransportFactory.setThriftMaxFrameSize(session.thriftMaxFrameSize); @@ -189,12 +201,14 @@ private void init(TEndPoint endPoint, boolean useSSL, String trustStore, String } if (useSSL) { transport = - DeepCopyRpcTransportFactory.INSTANCE.getTransport( + DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig( endPoint.getIp(), endPoint.getPort(), session.connectionTimeoutInMs, trustStore, - trustStorePwd); + trustStorePwd, + sslProtocol, + sslProviderClass); } else { transport = DeepCopyRpcTransportFactory.INSTANCE.getTransport( @@ -262,7 +276,13 @@ private void initClusterConn() throws IoTDBConnectionException { for (TEndPoint tEndPoint : endPointList) { try { session.defaultEndPoint = tEndPoint; - init(tEndPoint, session.useSSL, session.trustStore, session.trustStorePwd); + init( + tEndPoint, + session.useSSL, + session.trustStore, + session.trustStorePwd, + session.sslProtocol, + session.sslProviderClass); } catch (IoTDBConnectionException e) { if (!reconnect()) { logger.error(SessionMessages.CLUSTER_NO_NODES); @@ -1079,7 +1099,13 @@ private boolean reconnect() { } tryHostNum++; try { - init(endPoint, session.useSSL, session.trustStore, session.trustStorePwd); + init( + endPoint, + session.useSSL, + session.trustStore, + session.trustStorePwd, + session.sslProtocol, + session.sslProviderClass); connectedSuccess = true; } catch (IoTDBConnectionException e) { logger.warn(SessionMessages.NODE_DOWN_TRY_NEXT, endPoint); diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java index be53797165a6a..bc8ec1a1643a2 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,30 @@ public TableSessionBuilder trustStorePwd(String trustStorePwd) { return this; } + /** + * Sets the SSL protocol for secure connections. + * + * @param sslProtocol the SSL protocol. + * @return the current {@link TableSessionBuilder} instance. + * @defaultValue TLS + */ + public TableSessionBuilder sslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + return this; + } + + /** + * Sets the JSSE provider class for SSL connections. + * + * @param sslProviderClass the JSSE provider class. + * @return the current {@link TableSessionBuilder} instance. + * @defaultValue empty + */ + public TableSessionBuilder sslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + return this; + } + /** * Enables or disables rpc compression for the connection. * diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/ThriftConnection.java index e3b9e8fc98987..251ed3566cbe1 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,8 @@ public void init( boolean useSSL, String trustStore, String trustStorePwd, + String sslProtocol, + String sslProviderClass, String username, String password, boolean enableRPCCompression, @@ -89,12 +91,14 @@ public void init( try { if (useSSL) { transport = - DeepCopyRpcTransportFactory.INSTANCE.getTransport( + DeepCopyRpcTransportFactory.INSTANCE.getTransportWithSSLConfig( endPoint.getIp(), endPoint.getPort(), connectionTimeoutInMs, trustStore, - trustStorePwd); + trustStorePwd, + sslProtocol, + sslProviderClass); } else { transport = DeepCopyRpcTransportFactory.INSTANCE.getTransport( diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java index 3eaabe7f1fa78..d7975f9b29121 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,11 @@ public class SessionPool implements ISessionPool { private String trustStore; private String trustStorePwd; + + private String sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL; + + private String sslProviderClass = SessionConfig.DEFAULT_SSL_PROVIDER_CLASS; + 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 +471,8 @@ public SessionPool( this.useSSL = useSSL; this.trustStore = trustStore; this.trustStorePwd = trustStorePwd; + this.sslProtocol = SessionConfig.DEFAULT_SSL_PROTOCOL; + this.sslProviderClass = SessionConfig.DEFAULT_SSL_PROVIDER_CLASS; initThreadPool(); initAvailableNodes(Collections.singletonList(new TEndPoint(host, port))); } @@ -536,6 +543,8 @@ public SessionPool(AbstractSessionPoolBuilder builder) { this.useSSL = builder.useSSL; this.trustStore = builder.trustStore; this.trustStorePwd = builder.trustStorePwd; + this.sslProtocol = builder.sslProtocol; + this.sslProviderClass = builder.sslProviderClass; this.maxRetryCount = builder.maxRetryCount; this.retryIntervalInMs = builder.retryIntervalInMs; this.sqlDialect = builder.sqlDialect; @@ -593,6 +602,8 @@ private Session constructNewSession() { .useSSL(useSSL) .trustStore(trustStore) .trustStorePwd(trustStorePwd) + .sslProtocol(sslProtocol) + .sslProviderClass(sslProviderClass) .maxRetryCount(maxRetryCount) .retryIntervalInMs(retryIntervalInMs) .sqlDialect(sqlDialect) @@ -618,6 +629,8 @@ private Session constructNewSession() { .useSSL(useSSL) .trustStore(trustStore) .trustStorePwd(trustStorePwd) + .sslProtocol(sslProtocol) + .sslProviderClass(sslProviderClass) .maxRetryCount(maxRetryCount) .retryIntervalInMs(retryIntervalInMs) .sqlDialect(sqlDialect) @@ -662,6 +675,8 @@ private void initAvailableNodes(List endPointList) { useSSL, trustStore, trustStorePwd, + sslProtocol, + sslProviderClass, enableThriftCompression, version.toString()); } @@ -3637,6 +3652,16 @@ public Builder trustStorePwd(String trustStorePwd) { return this; } + public Builder sslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + return this; + } + + public Builder sslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + return this; + } + public Builder host(String host) { this.host = host; return this; diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/pool/TableSessionPoolBuilder.java index d5f52f3a8dc73..ea02d8cf28cdf 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,30 @@ public TableSessionPoolBuilder trustStorePwd(String trustStorePwd) { return this; } + /** + * Sets the SSL protocol for secure connections. + * + * @param sslProtocol the SSL protocol. + * @return the current {@link TableSessionPoolBuilder} instance. + * @defaultValue TLS + */ + public TableSessionPoolBuilder sslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + return this; + } + + /** + * Sets the JSSE provider class for SSL connections. + * + * @param sslProviderClass the JSSE provider class. + * @return the current {@link TableSessionPoolBuilder} instance. + * @defaultValue empty + */ + public TableSessionPoolBuilder sslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + return this; + } + /** * Builds and returns a configured {@link ITableSessionPool} instance. * diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java index 2c24ff12b6d36..9e6cee1411558 100644 --- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Utils.java @@ -29,6 +29,7 @@ import org.apache.iotdb.consensus.config.RatisConfig; import org.apache.iotdb.consensus.i18n.ConsensusMessages; import org.apache.iotdb.rpc.AutoScalingBufferWriteTransport; +import org.apache.iotdb.rpc.RpcSslUtils; import org.apache.ratis.client.RaftClientConfigKeys; import org.apache.ratis.conf.Parameters; @@ -53,19 +54,13 @@ 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,25 +366,10 @@ public static Parameters initRatisConfig(RaftProperties properties, RatisConfig String keyStorePassword = config.getGrpc().getSslKeyStorePassword(); String trustStorePath = config.getGrpc().getSslTrustStorePath(); String trustStorePassword = config.getGrpc().getSslTrustStorePassword(); - try (InputStream keyStoreStream = Files.newInputStream(Paths.get(keyStorePath)); - InputStream trustStoreStream = Files.newInputStream(Paths.get(trustStorePath))) { - // === 1) create KeyManager === - KeyStore keyStore = KeyStore.getInstance("JKS"); - keyStore.load(keyStoreStream, keyStorePassword.toCharArray()); - - KeyManagerFactory kmf = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(keyStore, keyStorePassword.toCharArray()); - KeyManager keyManager = kmf.getKeyManagers()[0]; - - // === 2) create TrustManager === - KeyStore trustStore = KeyStore.getInstance("JKS"); - trustStore.load(trustStoreStream, trustStorePassword.toCharArray()); - - TrustManagerFactory tmf = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(trustStore); - TrustManager originalTrustManager = tmf.getTrustManagers()[0]; + try { + KeyManager keyManager = RpcSslUtils.createKeyManagers(keyStorePath, keyStorePassword)[0]; + TrustManager originalTrustManager = + RpcSslUtils.createTrustManagers(trustStorePath, trustStorePassword)[0]; // The self-signed certification may not set Subject Alternative Name (SAN) // Thrift with ssl didn't check it, but Grpc did. 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 64c0f65fe3034..4e142a426b7b8 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,12 @@ public class IoTDBRestServiceConfig { /** ssl trust Store password. */ private String trustStorePwd = ""; + /** SSL protocol. */ + private String sslProtocol = ""; + + /** SSL provider class. */ + private String sslProviderClass = ""; + /** ssl timeout. */ private int idleTimeoutInSeconds = 50000; @@ -78,6 +84,22 @@ public void setTrustStorePwd(String trustStorePwd) { this.trustStorePwd = trustStorePwd; } + public String getSslProtocol() { + return sslProtocol; + } + + public void setSslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + } + + public String getSslProviderClass() { + return sslProviderClass; + } + + public void setSslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + } + public int getIdleTimeoutInSeconds() { return idleTimeoutInSeconds; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java index 2e4ed0c28a6d0..c832d6cea62e0 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 @@ -108,6 +108,9 @@ private void loadProps(TrimProperties trimProperties) { conf.setTrustStorePath( trimProperties.getProperty("trust_store_path", conf.getTrustStorePath())); conf.setTrustStorePwd(trimProperties.getProperty("trust_store_pwd", conf.getTrustStorePwd())); + conf.setSslProtocol(trimProperties.getProperty("ssl_protocol", conf.getSslProtocol())); + conf.setSslProviderClass( + trimProperties.getProperty("ssl_provider_class", conf.getSslProviderClass())); conf.setIdleTimeoutInSeconds( Integer.parseInt( trimProperties.getProperty( 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 3b2d5ff54731c..4b9156f02dd90 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,26 @@ trust_store_path= # Datatype: String trust_store_pwd= +# SSL protocol used by SSL services. +# effectiveMode: restart +# Datatype: String +# Privilege: SECURITY +ssl_protocol=TLS + +# Optional JSSE provider class used by SSL. If set, the provider is registered with highest priority. +# Multiple provider classes can be separated by commas. +# effectiveMode: restart +# Datatype: String +# Privilege: SECURITY +ssl_provider_class= + +# Comma-separated SSL cipher suites. +# Leave empty to use the provider default. +# effectiveMode: restart +# Datatype: String +# Privilege: SECURITY +ssl_cipher_suites= + #################### ### Connection Configuration #################### 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 6a8956e423b48..73b286a30ab6e 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 @@ -467,6 +467,15 @@ public class CommonConfig { /** ssl trust Store password. */ private String trustStorePwd = ""; + /** SSL protocol. */ + private String sslProtocol = "TLS"; + + /** SSL provider class. */ + private String sslProviderClass = ""; + + /** SSL cipher suites. */ + private String sslCipherSuites = ""; + private String userEncryptTokenHint = "not set yet"; private boolean enforceStrongPassword = false; @@ -2813,6 +2822,30 @@ public void setTrustStorePwd(String trustStorePwd) { this.trustStorePwd = trustStorePwd; } + public String getSslProtocol() { + return sslProtocol; + } + + public void setSslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + } + + public String getSslProviderClass() { + return sslProviderClass; + } + + public void setSslProviderClass(String sslProviderClass) { + this.sslProviderClass = sslProviderClass; + } + + public String getSslCipherSuites() { + return sslCipherSuites; + } + + public void setSslCipherSuites(String sslCipherSuites) { + this.sslCipherSuites = sslCipherSuites; + } + 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 5cd954a09f7b8..aad31835a28e0 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java @@ -24,6 +24,7 @@ import org.apache.iotdb.commons.utils.CommonDateTimeUtils; import org.apache.iotdb.confignode.rpc.thrift.TAuditConfig; import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig; +import org.apache.iotdb.rpc.RpcSslUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -521,5 +522,16 @@ public void initThriftSSL(TrimProperties properties) { config.setTrustStorePath( properties.getProperty("trust_store_path", config.getTrustStorePath())); config.setTrustStorePwd(properties.getProperty("trust_store_pwd", config.getTrustStorePwd())); + config.setSslProtocol(properties.getProperty("ssl_protocol", config.getSslProtocol())); + config.setSslProviderClass( + properties.getProperty("ssl_provider_class", config.getSslProviderClass())); + config.setSslCipherSuites( + properties.getProperty("ssl_cipher_suites", config.getSslCipherSuites())); + configureRpcSsl(); + } + + public void configureRpcSsl() { + RpcSslUtils.configure( + config.getSslProtocol(), config.getSslProviderClass(), config.getSslCipherSuites()); } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java index 84361727a32e0..cd2716108cebd 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/AbstractThriftServiceThread.java @@ -24,6 +24,7 @@ import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.runtime.RPCServiceException; import org.apache.iotdb.commons.i18n.ServiceMessages; +import org.apache.iotdb.rpc.RpcSslUtils; import org.apache.thrift.TBaseAsyncProcessor; import org.apache.thrift.TProcessor; @@ -45,13 +46,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.net.InetSocketAddress; -import java.nio.file.AccessDeniedException; -import java.security.KeyStore; -import java.security.cert.X509Certificate; -import java.util.Enumeration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; @@ -184,13 +179,13 @@ protected AbstractThriftServiceThread( this.serviceName = serviceName; try { - validateCertificate(keyStorePath, keyStorePwd); + RpcSslUtils.validateKeyStore(keyStorePath, keyStorePwd); TSSLTransportFactory.TSSLTransportParameters params = - new TSSLTransportFactory.TSSLTransportParameters(); - params.setKeyStore(keyStorePath, keyStorePwd); + RpcSslUtils.createTSSLTransportParameters(); + RpcSslUtils.setKeyStore(params, keyStorePath, keyStorePwd); if (trustStorePath != null && !trustStorePath.isEmpty()) { - validateCertificate(trustStorePath, trustStorePwd); - params.setTrustStore(trustStorePath, trustStorePwd); + RpcSslUtils.validateTrustStore(trustStorePath, trustStorePwd); + RpcSslUtils.setTrustStore(params, trustStorePath, trustStorePwd); params.requireClientAuth(true); } InetSocketAddress socketAddress = new InetSocketAddress(bindAddress, port); @@ -206,41 +201,6 @@ protected AbstractThriftServiceThread( } } - private static void validateCertificate(String keyStorePath, String keystorePassword) - throws TTransportException { - try { - KeyStore keystore = KeyStore.getInstance("JKS"); - try (FileInputStream fis = new FileInputStream(keyStorePath)) { - keystore.load(fis, keystorePassword.toCharArray()); - } - - Enumeration aliases = keystore.aliases(); - while (aliases.hasMoreElements()) { - String currentAlias = aliases.nextElement(); - checkCertificate(keystore, currentAlias); - } - } catch (AccessDeniedException e) { - throw new TTransportException(ServiceMessages.FAILED_TO_LOAD_KEYSTORE_OR_TRUSTSTORE); - } catch (FileNotFoundException e) { - throw new TTransportException(ServiceMessages.KEYSTORE_OR_TRUSTSTORE_NOT_FOUND); - } catch (Exception e) { - throw new TTransportException(e); - } - } - - private static void checkCertificate(KeyStore keystore, String alias) throws Exception { - if (!keystore.containsAlias(alias)) { - return; - } - - X509Certificate cert = (X509Certificate) keystore.getCertificate(alias); - if (cert == null) { - return; - } - - cert.checkValidity(); - } - @SuppressWarnings("squid:S107") protected AbstractThriftServiceThread( TProcessor processor,