Repository: ignite Updated Branches: refs/heads/master a79d1ec69 -> 3d32ac403
IGNITE-9298 SSL support in control.sh - Fixes #5516. Signed-off-by: Ilya Kasnacheev <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3d32ac40 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3d32ac40 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3d32ac40 Branch: refs/heads/master Commit: 3d32ac4033f00cb0619ee2f2c2f19115f29d54b2 Parents: a79d1ec Author: Ilya Kasnacheev <[email protected]> Authored: Fri Nov 30 16:40:40 2018 +0300 Committer: Ilya Kasnacheev <[email protected]> Committed: Fri Nov 30 16:40:40 2018 +0300 ---------------------------------------------------------------------- .../ignite/internal/commandline/Arguments.java | 100 ++++++++++++- .../internal/commandline/CommandHandler.java | 139 ++++++++++++++++++- .../commandline/CommandHandlerParsingTest.java | 39 ++++++ .../IgniteBasicWithPersistenceTestSuite.java | 2 + .../ignite/util/GridCommandHandlerSslTest.java | 88 ++++++++++++ 5 files changed, 363 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/3d32ac40/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 6367eef..07e7b10 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 @@ -77,6 +77,30 @@ public class Arguments { /** Ping interval for grid client. See {@link GridClientConfiguration#pingInterval}. */ private long pingInterval; + /** SSL Protocol. */ + private String sslProtocol; + + /** SSL Key Algorithm. */ + private String sslKeyAlgorithm; + + /** Keystore. */ + private String sslKeyStorePath; + + /** Keystore Type. */ + private String sslKeyStoreType; + + /** Keystore Password. */ + private char[] sslKeyStorePassword; + + /** Truststore. */ + private String sslTrustStorePath; + + /** Truststore Type. */ + private String sslTrustStoreType; + + /** Truststore Password. */ + private char[] sslTrustStorePassword; + /** * @param cmd Command. * @param host Host. @@ -92,10 +116,20 @@ public class Arguments { * @param pingTimeout Ping timeout. See {@link GridClientConfiguration#pingTimeout}. * @param pingInterval Ping interval. See {@link GridClientConfiguration#pingInterval}. * @param autoConfirmation Auto confirmation flag. + * @param sslProtocol SSL Protocol. + * @param sslKeyAlgorithm SSL Key Algorithm. + * @param sslKeyStorePath Keystore. + * @param sslKeyStorePassword Keystore Password. + * @param sslKeyStoreType Keystore Type. + * @param sslTrustStorePath Truststore. + * @param sslTrustStorePassword Truststore Password. + * @param sslTrustStoreType Truststore Type. */ 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) { + Long pingTimeout, Long pingInterval, boolean autoConfirmation, String sslProtocol, String sslKeyAlgorithm, + String sslKeyStorePath, char[] sslKeyStorePassword, String sslKeyStoreType, + String sslTrustStorePath, char[] sslTrustStorePassword, String sslTrustStoreType) { this.cmd = cmd; this.host = host; this.port = port; @@ -110,6 +144,14 @@ public class Arguments { this.pingTimeout = pingTimeout; this.pingInterval = pingInterval; this.autoConfirmation = autoConfirmation; + this.sslProtocol = sslProtocol; + this.sslKeyAlgorithm = sslKeyAlgorithm; + this.sslKeyStorePath = sslKeyStorePath; + this.sslKeyStoreType = sslKeyStoreType; + this.sslKeyStorePassword = sslKeyStorePassword; + this.sslTrustStorePath = sslTrustStorePath; + this.sslTrustStoreType = sslTrustStoreType; + this.sslTrustStorePassword = sslTrustStorePassword; } /** @@ -227,4 +269,60 @@ public class Arguments { public boolean autoConfirmation() { return autoConfirmation; } + + /** + * @return SSL protocol + */ + public String sslProtocol() { + return sslProtocol; + } + + /** + * @return SSL Key Algorithm + */ + public String sslKeyAlgorithm() { + return sslKeyAlgorithm; + } + + /** + * @return Keystore + */ + public String sslKeyStorePath() { + return sslKeyStorePath; + } + + /** + * @return Keystore type + */ + public String sslKeyStoreType() { + return sslKeyStoreType; + } + + /** + * @return Keystore password + */ + public char[] sslKeyStorePassword() { + return sslKeyStorePassword; + } + + /** + * @return Truststore + */ + public String sslTrustStorePath() { + return sslTrustStorePath; + } + + /** + * @return Truststore type + */ + public String sslTrustStoreType() { + return sslTrustStoreType; + } + + /** + * @return Truststore password + */ + public char[] sslTrustStorePassword() { + return sslTrustStorePassword; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/3d32ac40/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 e9a4281..56f278b 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 @@ -54,6 +54,7 @@ import org.apache.ignite.internal.client.GridClientHandshakeException; import org.apache.ignite.internal.client.GridClientNode; import org.apache.ignite.internal.client.GridServerUnreachableException; import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException; +import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory; import org.apache.ignite.internal.commandline.cache.CacheArguments; import org.apache.ignite.internal.commandline.cache.CacheCommand; import org.apache.ignite.internal.commandline.cache.distribution.CacheDistributionTask; @@ -124,6 +125,7 @@ import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.plugin.security.SecurityCredentials; import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider; import org.apache.ignite.plugin.security.SecurityCredentialsProvider; +import org.apache.ignite.ssl.SslContextFactory; import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND; import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR; @@ -196,6 +198,32 @@ public class CommandHandler { /** */ private static final String CMD_USER_ATTRIBUTES = "--user-attributes"; + // SSL configuration section + + /** */ + private static final String CMD_SSL_PROTOCOL = "--ssl-protocol"; + + /** */ + private static final String CMD_SSL_KEY_ALGORITHM = "--ssl-key-algorithm"; + + /** */ + private static final String CMD_KEYSTORE = "--keystore"; + + /** */ + private static final String CMD_KEYSTORE_PASSWORD = "--keystore-password"; + + /** */ + private static final String CMD_KEYSTORE_TYPE = "--keystore-type"; + + /** */ + private static final String CMD_TRUSTSTORE = "--truststore"; + + /** */ + private static final String CMD_TRUSTSTORE_PASSWORD = "--truststore-password"; + + /** */ + private static final String CMD_TRUSTSTORE_TYPE = "--truststore-type"; + /** List of optional auxiliary commands. */ private static final Set<String> AUX_COMMANDS = new HashSet<>(); @@ -208,6 +236,14 @@ public class CommandHandler { 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_KEY_ALGORITHM); + AUX_COMMANDS.add(CMD_KEYSTORE); + AUX_COMMANDS.add(CMD_KEYSTORE_PASSWORD); + AUX_COMMANDS.add(CMD_KEYSTORE_TYPE); + AUX_COMMANDS.add(CMD_TRUSTSTORE); + AUX_COMMANDS.add(CMD_TRUSTSTORE_PASSWORD); + AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE); } /** Broadcast uuid. */ @@ -316,7 +352,13 @@ 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"), op(CMD_PING_INTERVAL, "PING_INTERVAL"), op(CMD_PING_TIMEOUT, "PING_TIMEOUT")); + 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")); /** Utility name with common options. */ private static final String UTILITY_NAME_WITH_COMMON_OPTIONS = String.join(" ", UTILITY_NAME, COMMON_OPTIONS); @@ -1776,6 +1818,22 @@ public class CommandHandler { VisorTxTaskArg txArgs = null; + String sslProtocol = SslContextFactory.DFLT_SSL_PROTOCOL; + + String sslKeyAlgorithm = SslContextFactory.DFLT_KEY_ALGORITHM; + + String sslKeyStorePath = null; + + String sslKeyStoreType = SslContextFactory.DFLT_STORE_TYPE; + + char sslKeyStorePassword[] = null; + + String sslTrustStorePath = null; + + String sslTrustStoreType = SslContextFactory.DFLT_STORE_TYPE; + + char sslTrustStorePassword[] = null; + while (hasNextArg()) { String str = nextArg("").toLowerCase(); @@ -1888,6 +1946,46 @@ public class CommandHandler { break; + case CMD_SSL_PROTOCOL: + sslProtocol = nextArg("Expected SSL protocol"); + + break; + + case CMD_SSL_KEY_ALGORITHM: + sslKeyAlgorithm = nextArg("Expected SSL key algorithm"); + + break; + + case CMD_KEYSTORE: + sslKeyStorePath = nextArg("Expected keystore path"); + + break; + + case CMD_KEYSTORE_PASSWORD: + sslKeyStorePassword = nextArg("Expected keystore password").toCharArray(); + + break; + + case CMD_KEYSTORE_TYPE: + sslKeyStoreType = nextArg("Expected keystore type"); + + break; + + case CMD_TRUSTSTORE: + sslTrustStorePath = nextArg("Expected truststore path"); + + break; + + case CMD_TRUSTSTORE_PASSWORD: + sslTrustStorePassword = nextArg("Expected truststore password").toCharArray(); + + break; + + case CMD_TRUSTSTORE_TYPE: + sslTrustStoreType = nextArg("Expected truststore type"); + + break; + case CMD_AUTO_CONFIRMATION: autoConfirmation = true; @@ -1910,7 +2008,9 @@ public class CommandHandler { Command cmd = commands.get(0); return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, txArgs, cacheArgs, walAct, walArgs, - pingTimeout, pingInterval, autoConfirmation); + pingTimeout, pingInterval, autoConfirmation, + sslProtocol, sslKeyAlgorithm, sslKeyStorePath, sslKeyStorePassword, sslKeyStoreType, + sslTrustStorePath, sslTrustStorePassword, sslTrustStoreType); } /** @@ -2435,6 +2535,10 @@ public class CommandHandler { log(i("PORT=" + DFLT_PORT, 2)); log(i("PING_INTERVAL=" + DFLT_PING_INTERVAL, 2)); 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)); nl(); log("Exit codes:"); @@ -2481,8 +2585,7 @@ public class CommandHandler { if (securityCredential == null) { securityCredential = new SecurityCredentialsBasicProvider( - new SecurityCredentials(args.getUserName(), args.getPassword()) - ); + new SecurityCredentials(args.getUserName(), args.getPassword())); clientCfg.setSecurityCredentialsProvider(securityCredential); } @@ -2491,6 +2594,34 @@ public class CommandHandler { credential.setPassword(args.getPassword()); } + if (!F.isEmpty(args.sslKeyStorePath())) { + GridSslBasicContextFactory factory = new GridSslBasicContextFactory(); + + factory.setProtocol(args.sslProtocol()); + + factory.setKeyAlgorithm(args.sslKeyAlgorithm()); + + factory.setKeyStoreFilePath(args.sslKeyStorePath()); + + if (args.sslKeyStorePassword() != null) + factory.setKeyStorePassword(args.sslKeyStorePassword()); + + factory.setKeyStoreType(args.sslKeyStoreType()); + + if (F.isEmpty(args.sslTrustStorePath())) + factory.setTrustManagers(GridSslBasicContextFactory.getDisabledTrustManager()); + else { + factory.setTrustStoreFilePath(args.sslTrustStorePath()); + + if (args.sslTrustStorePassword() != null) + factory.setTrustStorePassword(args.sslTrustStorePassword()); + + factory.setTrustStoreType(args.sslTrustStoreType()); + } + + clientCfg.setSslContextFactory(factory); + } + try (GridClient client = GridClientFactory.start(clientCfg)) { switch (args.command()) { case ACTIVATE: http://git-wip-us.apache.org/repos/asf/ignite/blob/3d32ac40/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java index bda24d1..e5ff639 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java @@ -38,6 +38,7 @@ import static org.apache.ignite.internal.commandline.CommandHandler.VI_CHECK_FIR import static org.apache.ignite.internal.commandline.CommandHandler.VI_CHECK_THROUGH; import static org.apache.ignite.internal.commandline.CommandHandler.WAL_DELETE; import static org.apache.ignite.internal.commandline.CommandHandler.WAL_PRINT; +import static org.junit.Assert.assertArrayEquals; /** * Tests Command Handler parsing arguments. @@ -167,6 +168,44 @@ public class CommandHandlerParsingTest extends TestCase { } /** + * Tests parsing and validation for the SSL arguments. + */ + public void testParseAndValidateSSLArguments() { + CommandHandler hnd = new CommandHandler(); + + for (Command cmd : Command.values()) { + + if (cmd == Command.CACHE || cmd == Command.WAL) + continue; // --cache subcommand requires its own specific arguments. + + try { + hnd.parseAndValidate(asList("--truststore")); + + fail("expected exception: Expected truststore"); + } + catch (IllegalArgumentException e) { + e.printStackTrace(); + } + + Arguments args = hnd.parseAndValidate(asList("--keystore", "testKeystore", "--keystore-password", "testKeystorePassword", "--keystore-type", "testKeystoreType", + "--truststore", "testTruststore", "--truststore-password", "testTruststorePassword", "--truststore-type", "testTruststoreType", + "--ssl-key-algorithm", "testSSLKeyAlgorithm", "--ssl-protocol", "testSSLProtocol", cmd.text())); + + assertEquals("testSSLProtocol", args.sslProtocol()); + assertEquals("testSSLKeyAlgorithm", args.sslKeyAlgorithm()); + assertEquals("testKeystore", args.sslKeyStorePath()); + assertArrayEquals("testKeystorePassword".toCharArray(), args.sslKeyStorePassword()); + assertEquals("testKeystoreType", args.sslKeyStoreType()); + assertEquals("testTruststore", args.sslTrustStorePath()); + assertArrayEquals("testTruststorePassword".toCharArray(), args.sslTrustStorePassword()); + assertEquals("testTruststoreType", args.sslTrustStoreType()); + + assertEquals(cmd, args.command()); + } + } + + + /** * Tests parsing and validation for user and password arguments. */ public void testParseAndValidateUserAndPassword() { http://git-wip-us.apache.org/repos/asf/ignite/blob/3d32ac40/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java index 68085db..36f77cc 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java @@ -34,6 +34,7 @@ import org.apache.ignite.internal.GridNodeMetricsLogPdsSelfTest; import org.apache.ignite.internal.processors.service.ServiceDeploymentOnActivationTest; import org.apache.ignite.internal.processors.service.ServiceDeploymentOutsideBaselineTest; import org.apache.ignite.marshaller.GridMarshallerMappingConsistencyTest; +import org.apache.ignite.util.GridCommandHandlerSslTest; import org.apache.ignite.util.GridCommandHandlerTest; import org.apache.ignite.util.GridInternalTaskUnusedWalSegmentsTest; import org.jetbrains.annotations.Nullable; @@ -67,6 +68,7 @@ public class IgniteBasicWithPersistenceTestSuite extends TestSuite { suite.addTestSuite(FailureHandlingConfigurationTest.class); suite.addTestSuite(GridCommandHandlerTest.class); + suite.addTestSuite(GridCommandHandlerSslTest.class); suite.addTestSuite(GridInternalTaskUnusedWalSegmentsTest.class); suite.addTestSuite(GridNodeMetricsLogPdsSelfTest.class); http://git-wip-us.apache.org/repos/asf/ignite/blob/3d32ac40/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 new file mode 100644 index 0000000..59155e5 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerSslTest.java @@ -0,0 +1,88 @@ +/* + * 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.util; + +import java.util.Arrays; +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.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_CONNECTION_FAILED; +import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK; + +/** + * Command line handler test. + */ +public class GridCommandHandlerSslTest extends GridCommonAbstractTest { + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + cleanPersistenceDir(); + + stopAllGrids(); + + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setDataStorageConfiguration(new DataStorageConfiguration()); + cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().setMaxSize(100 * 1024 * 1024); + cfg.getDataStorageConfiguration().getDefaultDataRegionConfiguration().setPersistenceEnabled(true); + + cfg.setConnectorConfiguration(new ConnectorConfiguration()); + cfg.getConnectorConfiguration().setSslEnabled(true); + cfg.setSslContextFactory(GridTestUtils.sslFactory()); + + return cfg; + } + + /** + * Test activation works via control.sh + * + * @throws Exception If failed. + */ + public void testActivate() throws Exception { + 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()); + + assertEquals(EXIT_CODE_CONNECTION_FAILED, cmd.execute(Arrays.asList("--deactivate", "--yes"))); + } + +}
