Repository: ignite Updated Branches: refs/heads/ignite-10189 [created] 45263e2bb
IGNITE-10189 WIP. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/45263e2b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/45263e2b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/45263e2b Branch: refs/heads/ignite-10189 Commit: 45263e2bb9f4bdfd77b09ccb88c510d2118bae2f Parents: 1502494 Author: Alexey Kuznetsov <[email protected]> Authored: Mon Dec 3 17:27:42 2018 +0700 Committer: Alexey Kuznetsov <[email protected]> Committed: Mon Dec 3 17:27:42 2018 +0700 ---------------------------------------------------------------------- .../client/ClientSslParametersTest.java | 338 +++++++++++++++++++ .../client/suite/IgniteClientTestSuite.java | 4 + .../client/ssl/GridSslBasicContextFactory.java | 88 ++++- .../ignite/internal/commandline/Arguments.java | 34 +- .../internal/commandline/CommandHandler.java | 123 +++++-- .../apache/ignite/ssl/SSLContextWrapper.java | 13 +- .../apache/ignite/ssl/SslContextFactory.java | 16 +- .../apache/ignite/client/SslParametersTest.java | 15 +- 8 files changed, 576 insertions(+), 55 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientSslParametersTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientSslParametersTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientSslParametersTest.java new file mode 100644 index 0000000..228ce82 --- /dev/null +++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientSslParametersTest.java @@ -0,0 +1,338 @@ +/* + * 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.ignite.internal.client; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; + +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.ConnectorConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import org.jetbrains.annotations.NotNull; + +/** + * Tests cases when node connects to cluster with different set of cipher suites. + */ +public class ClientSslParametersTest extends GridCommonAbstractTest { + /** */ + public static final String TEST_CACHE_NAME = "TEST"; + + /** */ + private volatile String[] cipherSuites; + + /** */ + private volatile String[] protocols; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + ConnectorConfiguration conCfg = new ConnectorConfiguration(); + conCfg.setSslEnabled(true); + conCfg.setSslClientAuth(true); + conCfg.setSslContextFactory(createSslFactory()); + + cfg.setConnectorConfiguration(conCfg); + + CacheConfiguration ccfg = new CacheConfiguration(TEST_CACHE_NAME); + + cfg.setCacheConfiguration(ccfg); + + return cfg; + } + + /** + * @return Client configuration. + */ + protected GridClientConfiguration getClientConfiguration() { + GridClientConfiguration cfg = new GridClientConfiguration(); + + cfg.setServers(Collections.singleton("127.0.0.1:11211")); + + cfg.setSslContextFactory(createSslFactory()); + + return cfg; + } + + /** + * @return SSL Factory. + */ + @NotNull private GridSslBasicContextFactory createSslFactory() { + GridSslBasicContextFactory factory = (GridSslBasicContextFactory)GridTestUtils.sslContextFactory(); + + factory.setCipherSuites(cipherSuites); + factory.setProtocols(protocols); + + return factory; + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + protocols = null; + cipherSuites = null; + } + + /** + * @throws Exception If failed. + */ + public void testSameCipherSuite() throws Exception { + cipherSuites = new String[] { + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + }; + + startGrid(); + + checkSuccessfulClientStart( + new String[][] { + new String[] { + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + } + }, + null + ); + } + + /** + * @throws Exception If failed. + */ + public void testOneCommonCipherSuite() throws Exception { + cipherSuites = new String[] { + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + }; + + startGrid(); + + checkSuccessfulClientStart( + new String[][] { + new String[] { + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + } + }, + null + ); + } + + /** + * @throws Exception If failed. + */ + public void testNoCommonCipherSuite() throws Exception { + cipherSuites = new String[] { + "TLS_RSA_WITH_AES_128_GCM_SHA256" + }; + + startGrid(); + + checkClientStartFailure( + new String[][] { + new String[] { + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + } + }, + null + ); + } + + /** + * @throws Exception If failed. + */ + public void testNonExistentCipherSuite() throws Exception { + fail("IGNITE-10245"); + + cipherSuites = new String[] { + "TLS_RSA_WITH_AES_128_GCM_SHA256" + }; + + startGrid(); + + checkClientStartFailure( + new String[][] { + new String[] { + "TLC_FAKE_CIPHER", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + } + }, + null, + GridClientException.class, + "Unsupported ciphersuite" + ); + } + + /** + * @throws Exception If failed. + */ + public void testNoCommonProtocols() throws Exception { + protocols = new String[] { + "TLSv1.1", + "SSLv3" + }; + + startGrid(); + + checkClientStartFailure( + null, + new String[][] { + new String[] { + "TLSv1", + "TLSv1.2", + } + } + ); + } + + /** + * @throws Exception If failed. + */ + public void testNonExistentProtocol() throws Exception { + fail("IGNITE-10245"); + + protocols = new String[] { + "SSLv3" + }; + + startGrid(); + + checkClientStartFailure( + null, + new String[][] { + new String[] { + "SSLv3", + "SSLvDoesNotExist" + } + }, + GridClientException.class, + "SSLvDoesNotExist" + ); + } + + /** + * @throws Exception If failed. + */ + public void testSameProtocols() throws Exception { + protocols = new String[] { + "TLSv1.1", + "TLSv1.2", + }; + + startGrid(); + + checkSuccessfulClientStart(null, + new String[][] { + new String[] { + "TLSv1.1", + "TLSv1.2", + } + } + ); + } + + /** + * @throws Exception If failed. + */ + public void testOneCommonProtocol() throws Exception { + protocols = new String[] { + "TLSv1", + "TLSv1.1", + "TLSv1.2" + }; + + startGrid(); + + checkSuccessfulClientStart(null, + new String[][] { + new String[] { + "TLSv1.1", + "SSLv3" + } + } + ); + } + + /** + * @param cipherSuites list of cipher suites + * @param protocols list of protocols + * @throws Exception If failed. + */ + private void checkSuccessfulClientStart(String[][] cipherSuites, String[][] protocols) throws Exception { + int n = Math.max( + cipherSuites != null ? cipherSuites.length : 0, + protocols != null ? protocols.length : 0); + + for (int i = 0; i < n; i++) { + this.cipherSuites = cipherSuites != null && i < cipherSuites.length ? cipherSuites[i] : null; + this.protocols = protocols != null && i < protocols.length ? protocols[i] : null; + + GridClient client = GridClientFactory.start(getClientConfiguration()); + + List<GridClientNode> top = client.compute().refreshTopology(false, false); + + assertEquals(1, top.size()); + + client.close(); + } + } + + /** + * @param cipherSuites list of cipher suites + * @param protocols list of protocols + */ + private void checkClientStartFailure(String[][] cipherSuites, String[][] protocols) { + checkClientStartFailure(cipherSuites, protocols, GridClientException.class, "Latest topology update failed."); + } + + /** + * @param cipherSuites list of cipher suites + * @param protocols list of protocols + * @param ex expected exception class + * @param msg exception message + */ + private void checkClientStartFailure(String[][] cipherSuites, String[][] protocols, Class<? extends Throwable> ex, String msg) { + int n = Math.max( + cipherSuites != null ? cipherSuites.length : 0, + protocols != null ? protocols.length : 0); + + for (int i = 0; i < n; i++) { + this.cipherSuites = cipherSuites != null && i < cipherSuites.length ? cipherSuites[i] : null; + this.protocols = protocols != null && i < protocols.length ? protocols[i] : null; + + GridTestUtils.assertThrows(null, new Callable<Object>() { + @Override public Object call() throws Exception { + GridClient client = GridClientFactory.start(getClientConfiguration()); + + client.compute().refreshTopology(false, false); + + return null; + } + }, ex, msg); + } + } + +} http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java index d08c9a1..1ea2a1f 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java @@ -21,6 +21,7 @@ import junit.framework.TestSuite; import org.apache.ignite.internal.TaskEventSubjectIdSelfTest; import org.apache.ignite.internal.client.ClientDefaultCacheSelfTest; import org.apache.ignite.internal.client.ClientReconnectionSelfTest; +import org.apache.ignite.internal.client.ClientSslParametersTest; import org.apache.ignite.internal.client.ClientTcpMultiThreadedSelfTest; import org.apache.ignite.internal.client.ClientTcpSslAuthenticationSelfTest; import org.apache.ignite.internal.client.ClientTcpSslMultiThreadedSelfTest; @@ -167,6 +168,9 @@ public class IgniteClientTestSuite extends TestSuite { suite.addTestSuite(ClientTcpTaskExecutionAfterTopologyRestartSelfTest.class); + // SSL params. + suite.addTestSuite(ClientSslParametersTest.class); + return suite; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/main/java/org/apache/ignite/internal/client/ssl/GridSslBasicContextFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/ssl/GridSslBasicContextFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/client/ssl/GridSslBasicContextFactory.java index 8bf1e8d..27a32df 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/ssl/GridSslBasicContextFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/ssl/GridSslBasicContextFactory.java @@ -23,17 +23,20 @@ import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; import java.security.KeyStore; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.Collection; import javax.cache.configuration.Factory; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.A; +import org.apache.ignite.ssl.SSLContextWrapper; /** * Basic ssl context factory that provides ssl context configuration with specified key @@ -87,6 +90,12 @@ public class GridSslBasicContextFactory implements GridSslContextFactory { /** Trust managers. */ private TrustManager[] trustMgrs; + /** Enabled cipher suites. */ + private String[] cipherSuites; + + /** Enabled protocols. */ + private String[] protocols; + /** * Gets key store type used for context creation. * @@ -270,6 +279,63 @@ public class GridSslBasicContextFactory implements GridSslContextFactory { } /** + * Gets enabled cipher suites. + * + * @return Enabled cipher suites. + */ + public String[] getCipherSuites() { + return cipherSuites; + } + + /** + * Sets enabled cipher suites. + * + * @param cipherSuites Enabled cipher suites. + */ + public void setCipherSuites(String... cipherSuites) { + this.cipherSuites = cipherSuites; + } + + + /** + * Sets enabled cipher suites. + * + * @param cipherSuites Enabled cipher suites. + */ + public void setCipherSuites(Collection<String> cipherSuites) { + if (!F.isEmpty(cipherSuites)) + setCipherSuites(cipherSuites.toArray(new String[0])); + } + + /** + * Gets enabled protocols. + * + * @return Enabled protocols. + */ + public String[] getProtocols() { + return protocols; + } + + /** + * Sets enabled protocols. + * + * @param protocols Enabled protocols. + */ + public void setProtocols(String... protocols) { + this.protocols = protocols; + } + + /** + * Sets enabled protocols. + * + * @param protocols Enabled protocols. + */ + public void setProtocols(Collection<String> protocols) { + if (!F.isEmpty(protocols)) + setProtocols(protocols.toArray(new String[0])); + } + + /** * Returns an instance of trust manager that will always succeed regardless of certificate provided. * * @return Trust manager instance. @@ -303,6 +369,18 @@ public class GridSslBasicContextFactory implements GridSslContextFactory { SSLContext ctx = SSLContext.getInstance(proto); + if (cipherSuites != null || protocols != null) { + SSLParameters sslParameters = new SSLParameters(); + + if (cipherSuites != null) + sslParameters.setCipherSuites(cipherSuites); + + if (protocols != null) + sslParameters.setProtocols(protocols); + + ctx = new SSLContextWrapper(ctx, sslParameters); + } + ctx.init(keyMgrFactory.getKeyManagers(), mgrs, null); return ctx; @@ -431,14 +509,12 @@ public class GridSslBasicContextFactory implements GridSslContextFactory { private static final X509Certificate[] CERTS = new X509Certificate[0]; /** {@inheritDoc} */ - @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) - throws CertificateException { + @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { // No-op, all clients are trusted. } /** {@inheritDoc} */ - @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) - throws CertificateException { + @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { // No-op, all servers are trusted. } @@ -447,4 +523,4 @@ public class GridSslBasicContextFactory implements GridSslContextFactory { return CERTS; } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java index 07e7b10..ff04fc3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java @@ -80,6 +80,9 @@ public class Arguments { /** SSL Protocol. */ private String sslProtocol; + /** SSL Cipher suites. */ + private String sslCipherSuites; + /** SSL Key Algorithm. */ private String sslKeyAlgorithm; @@ -117,6 +120,7 @@ public class Arguments { * @param pingInterval Ping interval. See {@link GridClientConfiguration#pingInterval}. * @param autoConfirmation Auto confirmation flag. * @param sslProtocol SSL Protocol. + * @param sslCipherSuites SSL cipher suites. * @param sslKeyAlgorithm SSL Key Algorithm. * @param sslKeyStorePath Keystore. * @param sslKeyStorePassword Keystore Password. @@ -127,28 +131,40 @@ public class Arguments { */ public Arguments(Command cmd, String host, String port, String user, String pwd, String baselineAct, String baselineArgs, VisorTxTaskArg txArg, CacheArguments cacheArgs, String walAct, String walArgs, - Long pingTimeout, Long pingInterval, boolean autoConfirmation, String sslProtocol, String sslKeyAlgorithm, + Long pingTimeout, Long pingInterval, boolean autoConfirmation, + String sslProtocol, String sslCipherSuites, String sslKeyAlgorithm, String sslKeyStorePath, char[] sslKeyStorePassword, String sslKeyStoreType, - String sslTrustStorePath, char[] sslTrustStorePassword, String sslTrustStoreType) { + String sslTrustStorePath, char[] sslTrustStorePassword, String sslTrustStoreType + ) { this.cmd = cmd; this.host = host; this.port = port; this.user = user; this.pwd = pwd; + this.baselineAct = baselineAct; this.baselineArgs = baselineArgs; + this.txArg = txArg; this.cacheArgs = cacheArgs; + this.walAct = walAct; this.walArgs = walArgs; + this.pingTimeout = pingTimeout; this.pingInterval = pingInterval; + this.autoConfirmation = autoConfirmation; + + this.sslEnable = sslEnable; this.sslProtocol = sslProtocol; + this.sslCipherSuites = sslCipherSuites; + this.sslKeyAlgorithm = sslKeyAlgorithm; this.sslKeyStorePath = sslKeyStorePath; this.sslKeyStoreType = sslKeyStoreType; this.sslKeyStorePassword = sslKeyStorePassword; + this.sslTrustStorePath = sslTrustStorePath; this.sslTrustStoreType = sslTrustStoreType; this.sslTrustStorePassword = sslTrustStorePassword; @@ -271,6 +287,13 @@ public class Arguments { } /** + * @return {@code true} if SSL should be used. + */ + public boolean isSslEnable() { + return sslEnable; + } + + /** * @return SSL protocol */ public String sslProtocol() { @@ -278,6 +301,13 @@ public class Arguments { } /** + * @return SSL cipher suites. + */ + public String getSslCipherSuites() { + return sslCipherSuites; + } + + /** * @return SSL Key Algorithm */ public String sslKeyAlgorithm() { http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java index 56f278b..076d322 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java @@ -201,9 +201,15 @@ public class CommandHandler { // SSL configuration section /** */ + private static final String CMD_SSL_ENABLED = "--ssl_enabled"; + + /** */ private static final String CMD_SSL_PROTOCOL = "--ssl-protocol"; /** */ + private static final String CMD_SSL_CIPHER_SUITES = "--ssl-cipher-suites"; + + /** */ private static final String CMD_SSL_KEY_ALGORITHM = "--ssl-key-algorithm"; /** */ @@ -229,21 +235,30 @@ public class CommandHandler { static { AUX_COMMANDS.add(CMD_HELP); + AUX_COMMANDS.add(CMD_HOST); AUX_COMMANDS.add(CMD_PORT); + AUX_COMMANDS.add(CMD_PASSWORD); AUX_COMMANDS.add(CMD_USER); + AUX_COMMANDS.add(CMD_AUTO_CONFIRMATION); + AUX_COMMANDS.add(CMD_PING_INTERVAL); AUX_COMMANDS.add(CMD_PING_TIMEOUT); + + AUX_COMMANDS.add(CMD_SSL_ENABLED); AUX_COMMANDS.add(CMD_SSL_PROTOCOL); + AUX_COMMANDS.add(CMD_SSL_CIPHER_SUITES); + AUX_COMMANDS.add(CMD_SSL_KEY_ALGORITHM); + AUX_COMMANDS.add(CMD_KEYSTORE_TYPE); AUX_COMMANDS.add(CMD_KEYSTORE); AUX_COMMANDS.add(CMD_KEYSTORE_PASSWORD); - AUX_COMMANDS.add(CMD_KEYSTORE_TYPE); + + AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE); AUX_COMMANDS.add(CMD_TRUSTSTORE); AUX_COMMANDS.add(CMD_TRUSTSTORE_PASSWORD); - AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE); } /** Broadcast uuid. */ @@ -352,13 +367,15 @@ public class CommandHandler { private static final String UTILITY_NAME = "control.sh"; /** Common options. */ - private static final String COMMON_OPTIONS = String.join(" ", op(CMD_HOST, "HOST_OR_IP"), - op(CMD_PORT, "PORT"), op(CMD_USER, "USER"), op(CMD_PASSWORD, "PASSWORD"), + private static final String COMMON_OPTIONS = String.join(" ", op(CMD_HOST, "HOST_OR_IP"), op(CMD_PORT, "PORT"), + op(CMD_USER, "USER"), op(CMD_PASSWORD, "PASSWORD"), op(CMD_PING_INTERVAL, "PING_INTERVAL"), op(CMD_PING_TIMEOUT, "PING_TIMEOUT"), - op(CMD_SSL_PROTOCOL, "SSL_PROTOCOL"), op(CMD_SSL_KEY_ALGORITHM, "SSL_KEY_ALGORITHM"), - op(CMD_KEYSTORE, "KEYSTORE"), op(CMD_KEYSTORE_TYPE, "KEYSTORE_TYPE"), - op(CMD_KEYSTORE_PASSWORD, "KEYSTORE_PASSWORD"), op(CMD_TRUSTSTORE, "TRUSTSTORE"), - op(CMD_TRUSTSTORE_TYPE, "TRUSTSTORE_TYPE"), op(CMD_TRUSTSTORE_PASSWORD, "TRUSTSTORE_PASSWORD")); + op(CMD_SSL_ENABLED), + op(CMD_SSL_PROTOCOL, "SSL_PROTOCOL[, SSL_PROTOCOL_2, ...]"), + op(CMD_SSL_CIPHER_SUITES, "SSL_CIPHER_1[, SSL_CIPHER_2, ...]"), + op(CMD_SSL_KEY_ALGORITHM, "SSL_KEY_ALGORITHM"), + op(CMD_KEYSTORE_TYPE, "KEYSTORE_TYPE"), op(CMD_KEYSTORE, "KEYSTORE"), op(CMD_KEYSTORE_PASSWORD, "KEYSTORE_PASSWORD"), + op(CMD_TRUSTSTORE_TYPE, "TRUSTSTORE_TYPE"), op(CMD_TRUSTSTORE, "TRUSTSTORE"), op(CMD_TRUSTSTORE_PASSWORD, "TRUSTSTORE_PASSWORD")); /** Utility name with common options. */ private static final String UTILITY_NAME_WITH_COMMON_OPTIONS = String.join(" ", UTILITY_NAME, COMMON_OPTIONS); @@ -1032,10 +1049,9 @@ public class CommandHandler { executeTaskByNameOnNode(client, VisorCacheConfigurationCollectorTask.class.getName(), taskArg, nodeId); Map<String, Integer> cacheToMapped = - viewRes.cacheInfos().stream().collect(Collectors.toMap(x -> x.getCacheName(), x -> x.getMapped())); + viewRes.cacheInfos().stream().collect(Collectors.toMap(CacheInfo::getCacheName, CacheInfo::getMapped)); printCachesConfig(res, cacheArgs.outputFormat(), cacheToMapped); - } /** @@ -1818,20 +1834,24 @@ public class CommandHandler { VisorTxTaskArg txArgs = null; + boolean sslEnable = false; + String sslProtocol = SslContextFactory.DFLT_SSL_PROTOCOL; - String sslKeyAlgorithm = SslContextFactory.DFLT_KEY_ALGORITHM; + String sslCipherSuites = ""; - String sslKeyStorePath = null; + String sslKeyAlgorithm = SslContextFactory.DFLT_KEY_ALGORITHM; String sslKeyStoreType = SslContextFactory.DFLT_STORE_TYPE; - char sslKeyStorePassword[] = null; + String sslKeyStorePath = null; - String sslTrustStorePath = null; + char sslKeyStorePassword[] = null; String sslTrustStoreType = SslContextFactory.DFLT_STORE_TYPE; + String sslTrustStorePath = null; + char sslTrustStorePassword[] = null; while (hasNextArg()) { @@ -1946,43 +1966,52 @@ public class CommandHandler { break; + case CMD_SSL_ENABLED: + sslEnable = true; + + break; case CMD_SSL_PROTOCOL: sslProtocol = nextArg("Expected SSL protocol"); break; + case CMD_SSL_CIPHER_SUITES: + sslCipherSuites = nextArg("Expected SSL cipher suites"); + + break; + case CMD_SSL_KEY_ALGORITHM: sslKeyAlgorithm = nextArg("Expected SSL key algorithm"); break; case CMD_KEYSTORE: - sslKeyStorePath = nextArg("Expected keystore path"); + sslKeyStorePath = nextArg("Expected SSL key store path"); break; case CMD_KEYSTORE_PASSWORD: - sslKeyStorePassword = nextArg("Expected keystore password").toCharArray(); + sslKeyStorePassword = nextArg("Expected SSL key store password").toCharArray(); break; case CMD_KEYSTORE_TYPE: - sslKeyStoreType = nextArg("Expected keystore type"); + sslKeyStoreType = nextArg("Expected SSL key store type"); break; case CMD_TRUSTSTORE: - sslTrustStorePath = nextArg("Expected truststore path"); + sslTrustStorePath = nextArg("Expected SSL trust store path"); break; case CMD_TRUSTSTORE_PASSWORD: - sslTrustStorePassword = nextArg("Expected truststore password").toCharArray(); + sslTrustStorePassword = nextArg("Expected SSL trust store password").toCharArray(); break; case CMD_TRUSTSTORE_TYPE: - sslTrustStoreType = nextArg("Expected truststore type"); + sslTrustStoreType = nextArg("Expected SSL trust store type"); break; @@ -2007,9 +2036,13 @@ public class CommandHandler { Command cmd = commands.get(0); - return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, txArgs, cacheArgs, walAct, walArgs, + return new Arguments(cmd, host, port, user, pwd, + baselineAct, baselineArgs, + txArgs, cacheArgs, + walAct, walArgs, pingTimeout, pingInterval, autoConfirmation, - sslProtocol, sslKeyAlgorithm, sslKeyStorePath, sslKeyStorePassword, sslKeyStoreType, + sslEnable, sslProtocol, sslCipherSuites, + sslKeyAlgorithm, sslKeyStorePath, sslKeyStorePassword, sslKeyStoreType, sslTrustStorePath, sslTrustStorePassword, sslTrustStoreType); } @@ -2492,6 +2525,23 @@ public class CommandHandler { } /** + * Split string into items. + * + * @param s String to process. + * @param delim Delimiter. + * @return List with items. + */ + private List<String> split(String s, String delim) { + if (F.isEmpty(s)) + return Collections.emptyList(); + + return Arrays.stream(s.split(delim)) + .map(String::trim) + .filter(item -> !item.isEmpty()) + .collect(Collectors.toList()); + } + + /** * Parse and execute command. * * @param rawArgs Arguments to parse and execute. @@ -2537,8 +2587,8 @@ public class CommandHandler { log(i("PING_TIMEOUT=" + DFLT_PING_TIMEOUT, 2)); log(i("SSL_PROTOCOL=" + SslContextFactory.DFLT_SSL_PROTOCOL, 2)); log(i("SSL_KEY_ALGORITHM=" + SslContextFactory.DFLT_KEY_ALGORITHM, 2)); - log(i("KEYSTORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2)); - log(i("TRUSTSTORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2)); + log(i("SSL_KEY_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2)); + log(i("SSL_TRUST_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 2)); nl(); log("Exit codes:"); @@ -2575,7 +2625,7 @@ public class CommandHandler { boolean tryConnectAgain = true; - int tryConnectMaxCount=3; + int tryConnectMaxCount = 3; while (tryConnectAgain) { tryConnectAgain = false; @@ -2597,10 +2647,21 @@ public class CommandHandler { if (!F.isEmpty(args.sslKeyStorePath())) { GridSslBasicContextFactory factory = new GridSslBasicContextFactory(); - factory.setProtocol(args.sslProtocol()); + List<String> sslProtocols = split(args.getSslProtocol(), ","); + + String sslProtocol = F.isEmpty(sslProtocols) ? SslContextFactory.DFLT_SSL_PROTOCOL : sslProtocols.get(0); + factory.setProtocol(sslProtocol); factory.setKeyAlgorithm(args.sslKeyAlgorithm()); + if (sslProtocols.size() > 1) + factory.setProtocols(sslProtocols); + + factory.setCipherSuites(split(args.getSslCipherSuites(), ",")); + + if (args.sslKeyStorePath() == null) + throw new IllegalArgumentException("SSL key store location is not specified."); + factory.setKeyStoreFilePath(args.sslKeyStorePath()); if (args.sslKeyStorePassword() != null) @@ -2608,7 +2669,7 @@ public class CommandHandler { factory.setKeyStoreType(args.sslKeyStoreType()); - if (F.isEmpty(args.sslTrustStorePath())) + if (args.sslTrustStorePath() == null) factory.setTrustManagers(GridSslBasicContextFactory.getDisabledTrustManager()); else { factory.setTrustStoreFilePath(args.sslTrustStorePath()); @@ -2662,7 +2723,7 @@ public class CommandHandler { } catch (Throwable e) { if (tryConnectMaxCount > 0 && isAuthError(e)) { - System.out.println("Authentication error, try connection again."); + log("Authentication error, try connection again."); final Console console = System.console(); @@ -2675,13 +2736,13 @@ public class CommandHandler { else { Scanner scanner = new Scanner(System.in); - if (F.isEmpty(args.getUserName())){ - System.out.println("user: "); + if (F.isEmpty(args.getUserName())) { + log("user: "); args.setUserName(scanner.next()); } - System.out.println("password: "); + log("password: "); args.setPassword(scanner.next()); } http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/main/java/org/apache/ignite/ssl/SSLContextWrapper.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/ssl/SSLContextWrapper.java b/modules/core/src/main/java/org/apache/ignite/ssl/SSLContextWrapper.java index 901d42b..67bc834 100644 --- a/modules/core/src/main/java/org/apache/ignite/ssl/SSLContextWrapper.java +++ b/modules/core/src/main/java/org/apache/ignite/ssl/SSLContextWrapper.java @@ -20,10 +20,15 @@ package org.apache.ignite.ssl; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; -/** */ -class SSLContextWrapper extends SSLContext { - /** */ - SSLContextWrapper(SSLContext delegate, SSLParameters sslParameters) { +/** + * Wrapper for {@link SSLContext} that extend source context with custom SSL parameters. + */ +public class SSLContextWrapper extends SSLContext { + /** + * @param delegate Wrapped SSL context. + * @param sslParameters Extended SSL parameters. + */ + public SSLContextWrapper(SSLContext delegate, SSLParameters sslParameters) { super(new DelegatingSSLContextSpi(delegate, sslParameters), delegate.getProvider(), delegate.getProtocol()); http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/main/java/org/apache/ignite/ssl/SslContextFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/ssl/SslContextFactory.java b/modules/core/src/main/java/org/apache/ignite/ssl/SslContextFactory.java index edff5c9..fb370a5 100644 --- a/modules/core/src/main/java/org/apache/ignite/ssl/SslContextFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/ssl/SslContextFactory.java @@ -93,7 +93,7 @@ public class SslContextFactory implements Factory<SSLContext> { /** Enabled cipher suites. */ private String[] cipherSuites; - /** Enabled cipher suites. */ + /** Enabled protocols. */ private String[] protocols; /** @@ -289,6 +289,7 @@ public class SslContextFactory implements Factory<SSLContext> { /** * Sets enabled cipher suites. + * * @param cipherSuites enabled cipher suites. */ public void setCipherSuites(String... cipherSuites) { @@ -296,7 +297,8 @@ public class SslContextFactory implements Factory<SSLContext> { } /** - * Gets enabled cipher suites + * Gets enabled cipher suites. + * * @return enabled cipher suites */ public String[] getCipherSuites() { @@ -304,8 +306,9 @@ public class SslContextFactory implements Factory<SSLContext> { } /** - * Gets enabled cipher suites - * @return enabled cipher suites + * Gets enabled protocols. + * + * @return Enabled protocols. */ public String[] getProtocols() { return protocols; @@ -313,7 +316,8 @@ public class SslContextFactory implements Factory<SSLContext> { /** * Sets enabled protocols. - * @param protocols enabled protocols. + * + * @param protocols Enabled protocols. */ public void setProtocols(String... protocols) { this.protocols = protocols; @@ -515,4 +519,4 @@ public class SslContextFactory implements Factory<SSLContext> { throw new IgniteException(e); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/45263e2b/modules/core/src/test/java/org/apache/ignite/client/SslParametersTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/client/SslParametersTest.java b/modules/core/src/test/java/org/apache/ignite/client/SslParametersTest.java index eb577c4..20eb94c 100644 --- a/modules/core/src/test/java/org/apache/ignite/client/SslParametersTest.java +++ b/modules/core/src/test/java/org/apache/ignite/client/SslParametersTest.java @@ -32,8 +32,9 @@ import org.jetbrains.annotations.NotNull; * Tests cases when node connects to cluster with different set of cipher suites. */ public class SslParametersTest extends GridCommonAbstractTest { - + /** */ public static final String TEST_CACHE_NAME = "TEST"; + /** */ private volatile String[] cipherSuites; @@ -57,8 +58,10 @@ public class SslParametersTest extends GridCommonAbstractTest { return cfg; } - /** {@inheritDoc} */ - protected ClientConfiguration getClientConfiguration() throws Exception { + /** + * @return Client config. + */ + protected ClientConfiguration getClientConfiguration() { ClientConfiguration cfg = new ClientConfiguration(); cfg.setAddresses("127.0.0.1:10800"); @@ -70,6 +73,9 @@ public class SslParametersTest extends GridCommonAbstractTest { return cfg; } + /** + * @return SSL factory. + */ @NotNull private SslContextFactory createSslFactory() { SslContextFactory factory = (SslContextFactory)GridTestUtils.sslTrustedFactory( "node01", "trustone"); @@ -313,8 +319,6 @@ public class SslParametersTest extends GridCommonAbstractTest { this.cipherSuites = cipherSuites != null && i < cipherSuites.length ? cipherSuites[i] : null; this.protocols = protocols != null && i < protocols.length ? protocols[i] : null; - int finalI = i; - GridTestUtils.assertThrows(null, new Callable<Object>() { @Override public Object call() throws Exception { Ignition.startClient(getClientConfiguration()); @@ -324,5 +328,4 @@ public class SslParametersTest extends GridCommonAbstractTest { }, ex, msg); } } - }
