Repository: ignite
Updated Branches:
  refs/heads/master 47b1be6d9 -> 9098813d6


IGNITE-10189 Implemented support for multiple protocols and cipher suites for 
utilities that work via o.a.i.internal.client.GridClient. This closes #5617.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/9098813d
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/9098813d
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/9098813d

Branch: refs/heads/master
Commit: 9098813d6cbaa354f9ff1fef3dc4f17a499aa4d5
Parents: 47b1be6
Author: Alexey Kuznetsov <[email protected]>
Authored: Wed Dec 12 14:07:52 2018 +0700
Committer: Alexey Kuznetsov <[email protected]>
Committed: Wed Dec 12 14:07:52 2018 +0700

----------------------------------------------------------------------
 .../client/ClientSslParametersTest.java         | 335 +++++++++++++++++++
 .../client/suite/IgniteClientTestSuite.java     |   4 +
 .../client/ssl/GridSslBasicContextFactory.java  |  88 ++++-
 .../ignite/internal/commandline/Arguments.java  |  38 ++-
 .../internal/commandline/CommandHandler.java    | 110 ++++--
 .../apache/ignite/ssl/SSLContextWrapper.java    |  13 +-
 .../apache/ignite/ssl/SslContextFactory.java    |  16 +-
 .../apache/ignite/client/SslParametersTest.java | 146 ++++----
 .../ignite/util/GridCommandHandlerSslTest.java  | 104 +++++-
 9 files changed, 708 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/9098813d/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..d865e5d
--- /dev/null
+++ 
b/modules/clients/src/test/java/org/apache/ignite/internal/client/ClientSslParametersTest.java
@@ -0,0 +1,335 @@
+/*
+ * 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.internal.util.typedef.F;
+import org.apache.ignite.ssl.SslContextFactory;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests cases when node connects to cluster with different set of cipher 
suites.
+ */
+@RunWith(JUnit4.class)
+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);
+
+        cfg.setSslContextFactory(createSslFactory());
+
+        cfg.setConnectorConfiguration(new ConnectorConfiguration()
+            .setSslEnabled(true)
+            .setSslClientAuth(true));
+
+        cfg.setCacheConfiguration(new CacheConfiguration(TEST_CACHE_NAME));
+
+        return cfg;
+    }
+
+    /**
+     * @return Client configuration.
+     */
+    protected GridClientConfiguration getClientConfiguration() {
+        GridClientConfiguration cfg = new GridClientConfiguration();
+
+        cfg.setServers(Collections.singleton("127.0.0.1:11211"));
+
+        cfg.setSslContextFactory(createOldSslFactory());
+
+        return cfg;
+    }
+
+    /**
+     * @return SSL factory.
+     */
+    @NotNull private SslContextFactory createSslFactory() {
+        SslContextFactory factory = 
(SslContextFactory)GridTestUtils.sslFactory();
+
+        factory.setCipherSuites(cipherSuites);
+
+        factory.setProtocols(protocols);
+
+        return factory;
+    }
+
+    /**
+     * @return SSL Factory.
+     */
+    @NotNull private GridSslBasicContextFactory createOldSslFactory() {
+        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.
+     */
+    @Test
+    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[] {
+                "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.
+     */
+    @Test
+    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[] {
+                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
+            },
+            null
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testNoCommonCipherSuite() throws Exception {
+        cipherSuites = new String[] {
+            "TLS_RSA_WITH_AES_128_GCM_SHA256"
+        };
+
+        startGrid();
+        
+        checkClientStartFailure(
+            new String[] {
+                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
+            },
+            null
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10245";)
+    public void testNonExistentCipherSuite() throws Exception {
+        cipherSuites = new String[] {
+            "TLS_RSA_WITH_AES_128_GCM_SHA256"
+        };
+
+        startGrid();
+        
+        checkClientStartFailure(
+            new String[] {
+                "TLC_FAKE_CIPHER",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
+            },
+            null,
+            "Unsupported ciphersuite"
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testNoCommonProtocols() throws Exception {
+        protocols = new String[] {
+            "TLSv1.1",
+            "SSLv3"
+        };
+
+        startGrid();
+
+        checkClientStartFailure(
+            null,
+            new String[] {
+                "TLSv1",
+                "TLSv1.2"
+            }
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    @Ignore("https://issues.apache.org/jira/browse/IGNITE-10245";)
+    public void testNonExistentProtocol() throws Exception {
+        protocols = new String[] {
+            "SSLv3"
+        };
+
+        startGrid();
+
+        checkClientStartFailure(
+            null,
+            new String[] {
+                "SSLv3",
+                "SSLvDoesNotExist"
+            },
+            "SSLvDoesNotExist"
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testSameProtocols() throws Exception {
+        protocols = new String[] {
+            "TLSv1.1",
+            "TLSv1.2"
+        };
+
+        startGrid();
+
+        checkSuccessfulClientStart(
+            null,
+            new String[] {
+                "TLSv1.1",
+                "TLSv1.2"
+            }
+        );
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testOneCommonProtocol() throws Exception {
+        protocols = new String[] {
+            "TLSv1",
+            "TLSv1.1",
+            "TLSv1.2"
+        };
+
+        startGrid();
+
+        checkSuccessfulClientStart(
+            null,
+            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 {
+        this.cipherSuites = F.isEmpty(cipherSuites) ? null : cipherSuites;
+        this.protocols = F.isEmpty(protocols) ? null : protocols;
+
+        try (GridClient client = 
GridClientFactory.start(getClientConfiguration())) {
+            List<GridClientNode> top = client.compute().refreshTopology(false, 
false);
+
+            assertEquals(1, top.size());
+        }
+    }
+
+    /**
+     * @param cipherSuites list of cipher suites
+     * @param protocols list of protocols
+     */
+    private void checkClientStartFailure(String[] cipherSuites, String[] 
protocols) {
+        checkClientStartFailure(cipherSuites, protocols, "Latest topology 
update failed.");
+    }
+
+    /**
+     * @param cipherSuites list of cipher suites
+     * @param protocols list of protocols
+     * @param msg exception message
+     */
+    private void checkClientStartFailure(String[] cipherSuites, String[] 
protocols, String msg) {
+        this.cipherSuites = F.isEmpty(cipherSuites) ? null : cipherSuites;
+        this.protocols = F.isEmpty(protocols) ? null : protocols;
+
+        GridTestUtils.assertThrows(
+            null,
+            new Callable<Object>() {
+                @Override public Object call() throws Exception {
+                    GridClient client = 
GridClientFactory.start(getClientConfiguration());
+
+                    client.compute().refreshTopology(false, false);
+
+                    return null;
+                }
+            },
+            GridClientException.class,
+            msg
+            );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/9098813d/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/9098813d/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/9098813d/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..abd27bd 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
@@ -71,15 +71,18 @@ public class Arguments {
      */
     private String walArgs;
 
-    /** Ping timeout for grid client. See {@link 
GridClientConfiguration#pingTimeout}. */
+    /** Ping timeout for grid client. See {@link 
GridClientConfiguration#getPingTimeout()}. */
     private long pingTimeout;
 
-    /** Ping interval for grid client. See {@link 
GridClientConfiguration#pingInterval}. */
+    /** Ping interval for grid client. See {@link 
GridClientConfiguration#getPingInterval()}. */
     private long pingInterval;
 
     /** SSL Protocol. */
     private String sslProtocol;
 
+    /** SSL Cipher suites. */
+    private String sslCipherSuites;
+
     /** SSL Key Algorithm. */
     private String sslKeyAlgorithm;
 
@@ -113,10 +116,11 @@ public class Arguments {
      * @param cacheArgs --cache subcommand arguments.
      * @param walAct WAL action.
      * @param walArgs WAL args.
-     * @param pingTimeout Ping timeout. See {@link 
GridClientConfiguration#pingTimeout}.
-     * @param pingInterval Ping interval. See {@link 
GridClientConfiguration#pingInterval}.
+     * @param pingTimeout Ping timeout. See {@link 
GridClientConfiguration#getPingTimeout()}.
+     * @param pingInterval Ping interval. See {@link 
GridClientConfiguration#getPingInterval()}.
      * @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,39 @@ 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.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;
@@ -246,7 +261,7 @@ public class Arguments {
     }
 
     /**
-     * See {@link GridClientConfiguration#pingTimeout}.
+     * See {@link GridClientConfiguration#getPingInterval()}.
      *
      * @return Ping timeout.
      */
@@ -255,7 +270,7 @@ public class Arguments {
     }
 
     /**
-     * See {@link GridClientConfiguration#pingInterval}.
+     * See {@link GridClientConfiguration#getPingInterval()}.
      *
      * @return Ping interval.
      */
@@ -278,6 +293,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/9098813d/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 2a71800..2cfce37 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
@@ -208,6 +208,9 @@ public class CommandHandler {
     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";
 
     /** */
@@ -233,21 +236,29 @@ 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_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. */
@@ -356,13 +367,14 @@ 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_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);
@@ -1040,10 +1052,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);
-
     }
 
     /**
@@ -1828,18 +1839,20 @@ public class CommandHandler {
 
         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()) {
@@ -1959,38 +1972,43 @@ public class CommandHandler {
 
                         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;
 
@@ -2015,9 +2033,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,
+            sslProtocol, sslCipherSuites,
+            sslKeyAlgorithm, sslKeyStorePath, sslKeyStorePassword, 
sslKeyStoreType,
             sslTrustStorePath, sslTrustStorePassword, sslTrustStoreType);
     }
 
@@ -2506,6 +2528,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.
@@ -2551,8 +2590,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("KEY_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 
2));
+                log(i("TRUST_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 
2));
                 nl();
 
                 log("Exit codes:");
@@ -2589,7 +2628,7 @@ public class CommandHandler {
 
             boolean tryConnectAgain = true;
 
-            int tryConnectMaxCount=3;
+            int tryConnectMaxCount = 3;
 
             while (tryConnectAgain) {
                 tryConnectAgain = false;
@@ -2611,10 +2650,21 @@ public class CommandHandler {
                 if (!F.isEmpty(args.sslKeyStorePath())) {
                     GridSslBasicContextFactory factory = new 
GridSslBasicContextFactory();
 
-                    factory.setProtocol(args.sslProtocol());
+                    List<String> sslProtocols = split(args.sslProtocol(), ",");
 
+                    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)
@@ -2676,7 +2726,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();
 
@@ -2689,13 +2739,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/9098813d/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/9098813d/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/9098813d/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 132f0d8..9817120 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
@@ -23,6 +23,7 @@ import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ClientConfiguration;
 import org.apache.ignite.configuration.ClientConnectorConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.ssl.SslContextFactory;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -36,8 +37,9 @@ import org.junit.runners.JUnit4;
  */
 @RunWith(JUnit4.class)
 public class SslParametersTest extends GridCommonAbstractTest {
-
+    /** */
     public static final String TEST_CACHE_NAME = "TEST";
+
     /** */
     private volatile String[] cipherSuites;
 
@@ -61,8 +63,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");
@@ -74,9 +78,11 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         return cfg;
     }
 
+    /**
+     * @return SSL factory.
+     */
     @NotNull private SslContextFactory createSslFactory() {
-        SslContextFactory factory = 
(SslContextFactory)GridTestUtils.sslTrustedFactory(
-            "node01", "trustone");
+        SslContextFactory factory = 
(SslContextFactory)GridTestUtils.sslTrustedFactory("node01", "trustone");
 
         factory.setCipherSuites(cipherSuites);
         factory.setProtocols(protocols);
@@ -95,7 +101,7 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
     /**
      * @throws Exception If failed.
      */
-    @Test
+        @Test
     public void testSameCipherSuite() throws Exception {
         cipherSuites = new String[] {
             "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@@ -106,12 +112,10 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         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"
-                }
+            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
         );
@@ -130,11 +134,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         startGrid();
 
         checkSuccessfulClientStart(
-            new String[][] {
-                new String[] {
-                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
-                    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
-                }
+            new String[] {
+                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
             },
             null
         );
@@ -152,11 +154,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         startGrid();
 
         checkClientStartFailure(
-            new String[][] {
-                new String[] {
-                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
-                    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
-                }
+            new String[] {
+                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
             },
             null
         );
@@ -174,11 +174,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         startGrid();
 
         checkClientStartFailure(
-            new String[][] {
-                new String[] {
-                    "TLC_FAKE_CIPHER",
-                    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
-                }
+            new String[] {
+                "TLC_FAKE_CIPHER",
+                "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
             },
             null,
             IllegalArgumentException.class,
@@ -200,11 +198,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
 
         checkClientStartFailure(
             null,
-            new String[][] {
-                new String[] {
-                    "TLSv1",
-                    "TLSv1.2",
-                }
+            new String[] {
+                "TLSv1",
+                "TLSv1.2"
             }
         );
     }
@@ -222,11 +218,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
 
         checkClientStartFailure(
             null,
-            new String[][] {
-                new String[] {
-                    "SSLv3",
-                    "SSLvDoesNotExist"
-                }
+            new String[] {
+                "SSLv3",
+                "SSLvDoesNotExist"
             },
             IllegalArgumentException.class,
             "SSLvDoesNotExist"
@@ -240,17 +234,15 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
     public void testSameProtocols() throws Exception {
         protocols = new String[] {
             "TLSv1.1",
-            "TLSv1.2",
+            "TLSv1.2"
         };
 
         startGrid();
 
         checkSuccessfulClientStart(null,
-            new String[][] {
-                new String[] {
-                    "TLSv1.1",
-                    "TLSv1.2",
-                }
+            new String[] {
+                "TLSv1.1",
+                "TLSv1.2"
             }
         );
     }
@@ -269,11 +261,9 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
         startGrid();
 
         checkSuccessfulClientStart(null,
-            new String[][] {
-                new String[] {
-                    "TLSv1.1",
-                    "SSLv3"
-                }
+            new String[] {
+                "TLSv1.1",
+                "SSLv3"
             }
         );
     }
@@ -283,30 +273,26 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
      * @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;
-
-            IgniteClient client = 
Ignition.startClient(getClientConfiguration());
+    private void checkSuccessfulClientStart(String[] cipherSuites, String[] 
protocols) throws Exception {
+        this.cipherSuites = F.isEmpty(cipherSuites) ? null : cipherSuites;
+        this.protocols = F.isEmpty(protocols) ? null : protocols;
 
+        try (IgniteClient client = 
Ignition.startClient(getClientConfiguration())) {
             client.getOrCreateCache(TEST_CACHE_NAME);
-
-            client.close();
         }
     }
 
     /**
      * @param cipherSuites list of cipher suites
      * @param protocols list of protocols
-     * @throws Exception If failed.
      */
-    private void checkClientStartFailure(String[][] cipherSuites, String[][] 
protocols) throws Exception {
-        checkClientStartFailure(cipherSuites, protocols, 
ClientConnectionException.class, "Ignite cluster is unavailable");
+    private void checkClientStartFailure(String[] cipherSuites, String[] 
protocols) {
+        checkClientStartFailure(
+            cipherSuites,
+            protocols,
+            ClientConnectionException.class,
+            "Ignite cluster is unavailable"
+        );
     }
 
     /**
@@ -314,27 +300,27 @@ public class SslParametersTest extends 
GridCommonAbstractTest {
      * @param protocols list of protocols
      * @param ex expected exception class
      * @param msg exception message
-     * @throws Exception If failed.
      */
-    private void checkClientStartFailure(String[][] cipherSuites, String[][] 
protocols, Class<? extends Throwable> ex, String msg) 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;
-
-            int finalI = i;
-
-            GridTestUtils.assertThrows(null, new Callable<Object>() {
-                @Override public Object call() throws Exception {
+    private void checkClientStartFailure(
+        String[] cipherSuites,
+        String[] protocols,
+        Class<? extends Throwable> ex,
+        String msg
+    ) {
+        this.cipherSuites = F.isEmpty(cipherSuites) ? null : cipherSuites;
+        this.protocols = F.isEmpty(protocols) ? null : protocols;
+
+        GridTestUtils.assertThrows(
+            null,
+            new Callable<Object>() {
+                @Override public Object call() {
                     Ignition.startClient(getClientConfiguration());
 
                     return null;
                 }
-            }, ex, msg);
-        }
+            },
+            ex,
+            msg
+        );
     }
-
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/9098813d/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
 
b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
index 16f576d..9616d51 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java
@@ -17,14 +17,19 @@
 
 package org.apache.ignite.util;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.configuration.ConnectorConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.commandline.CommandHandler;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.ssl.SslContextFactory;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -33,16 +38,18 @@ import static 
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_CO
 import static 
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
 
 /**
- * Command line handler test.
+ * Command line handler test with SSL.
  */
 @RunWith(JUnit4.class)
 public class GridCommandHandlerSslTest extends GridCommonAbstractTest {
+    /** */
+    private volatile String[] cipherSuites;
+
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         cleanPersistenceDir();
 
         stopAllGrids();
-
     }
 
     /** {@inheritDoc} */
@@ -50,7 +57,17 @@ public class GridCommandHandlerSslTest extends 
GridCommonAbstractTest {
         stopAllGrids();
 
         cleanPersistenceDir();
+    }
+
+    /**
+     * @return SSL factory.
+     */
+    @NotNull private SslContextFactory createSslFactory() {
+        SslContextFactory factory = 
(SslContextFactory)GridTestUtils.sslFactory();
+
+        factory.setCipherSuites(cipherSuites);
 
+        return factory;
     }
 
     /** {@inheritDoc} */
@@ -63,31 +80,94 @@ public class GridCommandHandlerSslTest extends 
GridCommonAbstractTest {
 
         cfg.setConnectorConfiguration(new ConnectorConfiguration());
         cfg.getConnectorConfiguration().setSslEnabled(true);
-        cfg.setSslContextFactory(GridTestUtils.sslFactory());
+        cfg.setSslContextFactory(createSslFactory());
 
         return cfg;
     }
 
     /**
-     * Test activation works via control.sh
-     *
+     * @param nodeCipherSuite Ciphers suites to set on node.
+     * @param utilityCipherSuite Ciphers suites to set on utility.
+     * @param expRes Expected result.
      * @throws Exception If failed.
      */
-    @Test
-    public void testActivate() throws Exception {
+    private void activate(String nodeCipherSuite, String utilityCipherSuite, 
int expRes) throws Exception {
+        cipherSuites = F.isEmpty(nodeCipherSuite) ? null : 
nodeCipherSuite.split(",");
+
         Ignite ignite = startGrids(1);
 
         assertFalse(ignite.cluster().active());
 
         final CommandHandler cmd = new CommandHandler();
-        assertEquals(EXIT_CODE_OK, cmd.execute(Arrays.asList(
-            "--activate",
-            "--keystore", GridTestUtils.keyStorePath("node01"),
-            "--keystore-password", GridTestUtils.keyStorePassword())));
 
-        assertTrue(ignite.cluster().active());
+        List<String> params = new ArrayList<>();
+        params.add("--activate");
+        params.add("--keystore");
+        params.add(GridTestUtils.keyStorePath("node01"));
+        params.add("--keystore-password");
+        params.add(GridTestUtils.keyStorePassword());
+
+        if (!F.isEmpty(utilityCipherSuite)) {
+            params.add("--ssl-cipher-suites");
+            params.add(utilityCipherSuite);
+        }
+
+        assertEquals(expRes, cmd.execute(params));
+
+        if (expRes == EXIT_CODE_OK)
+            assertTrue(ignite.cluster().active());
+        else
+            assertFalse(ignite.cluster().active());
 
         assertEquals(EXIT_CODE_CONNECTION_FAILED, 
cmd.execute(Arrays.asList("--deactivate", "--yes")));
     }
 
+    /**
+     * @throws Exception If test failed.
+     */
+    @Test
+    public void testDefaultCipherSuite() throws Exception {
+        cipherSuites = null;
+
+        activate(null, null, EXIT_CODE_OK);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testSameCipherSuite() throws Exception {
+        String ciphers = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," +
+            "TLS_RSA_WITH_AES_128_GCM_SHA256," +
+            "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+
+        activate(ciphers, ciphers, EXIT_CODE_OK);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testOneCommonCipherSuite() throws Exception {
+        String nodeCipherSuites = "TLS_RSA_WITH_AES_128_GCM_SHA256," +
+            "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+
+        String utilityCipherSuites = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," +
+            "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+
+        activate(nodeCipherSuites, utilityCipherSuites, EXIT_CODE_OK);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testNoCommonCipherSuite() throws Exception {
+        String nodeCipherSuites = "TLS_RSA_WITH_AES_128_GCM_SHA256";
+
+        String utilityCipherSuites = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," +
+            "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+
+        activate(nodeCipherSuites, utilityCipherSuites, 
EXIT_CODE_CONNECTION_FAILED);
+    }
 }

Reply via email to