IGNITE-10257 control.sh utility should request SSL keystore and truststore 
passwords if necessary - Fixes #5647.

Signed-off-by: Alexey Goncharuk <[email protected]>


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

Branch: refs/heads/ignite-10639
Commit: ece5869bb9e7ff638352f07b63192ec2867afb8a
Parents: afe23b6
Author: Sergey Antonov <[email protected]>
Authored: Tue Dec 18 17:48:48 2018 +0300
Committer: Alexey Goncharuk <[email protected]>
Committed: Tue Dec 18 17:48:48 2018 +0300

----------------------------------------------------------------------
 .../internal/commandline/CommandHandler.java    | 208 ++++++++++++-------
 1 file changed, 129 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ece5869b/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 44f652c..9923fb4 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
@@ -155,6 +155,7 @@ import static 
org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.V
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.CACHES;
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.GROUPS;
 import static org.apache.ignite.internal.visor.verify.VisorViewCacheCmd.SEQ;
+import static org.apache.ignite.ssl.SslContextFactory.DFLT_SSL_PROTOCOL;
 
 /**
  * Class that execute several commands passed via command line.
@@ -367,14 +368,7 @@ 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"),
-        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"));
+    private static final String COMMON_OPTIONS = String.join(" ", 
getCommonOptions());
 
     /** Utility name with common options. */
     private static final String UTILITY_NAME_WITH_COMMON_OPTIONS = 
String.join(" ", UTILITY_NAME, COMMON_OPTIONS);
@@ -401,6 +395,34 @@ public class CommandHandler {
     private final boolean enableExperimental = 
IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND, false);
 
     /**
+     * Creates list of common utility options.
+     *
+     * @return List of common utility options.
+     */
+    private static List<String> getCommonOptions() {
+        List<String> list = new ArrayList<>(32);
+
+        list.add(op(CMD_HOST, "HOST_OR_IP"));
+        list.add(op(CMD_PORT, "PORT"));
+        list.add(op(CMD_USER, "USER"));
+        list.add(op(CMD_PASSWORD, "PASSWORD"));
+        list.add(op(CMD_PING_INTERVAL, "PING_INTERVAL"));
+        list.add(op(CMD_PING_TIMEOUT, "PING_TIMEOUT"));
+
+        list.add(op(CMD_SSL_PROTOCOL, "SSL_PROTOCOL[, SSL_PROTOCOL_2, ...]"));
+        list.add(op(CMD_SSL_CIPHER_SUITES, "SSL_CIPHER_1[, SSL_CIPHER_2, 
...]"));
+        list.add(op(CMD_SSL_KEY_ALGORITHM, "SSL_KEY_ALGORITHM"));
+        list.add(op(CMD_KEYSTORE_TYPE, "KEYSTORE_TYPE"));
+        list.add(op(CMD_KEYSTORE, "KEYSTORE"));
+        list.add(op(CMD_KEYSTORE_PASSWORD, "KEYSTORE_PASSWORD"));
+        list.add(op(CMD_TRUSTSTORE_TYPE, "TRUSTSTORE_TYPE"));
+        list.add(op(CMD_TRUSTSTORE, "TRUSTSTORE"));
+        list.add(op(CMD_TRUSTSTORE_PASSWORD, "TRUSTSTORE_PASSWORD"));
+
+        return list;
+    }
+
+    /**
      * Output specified string to console.
      *
      * @param s String to output.
@@ -649,7 +671,9 @@ public class CommandHandler {
      * @return List of hosts.
      */
     private Stream<IgniteBiTuple<GridClientNode, String>> listHosts(GridClient 
client) throws GridClientException {
-        return client.compute().nodes(GridClientNode::connectable).stream()
+        return client.compute()
+            .nodes(GridClientNode::connectable)
+            .stream()
             .flatMap(node -> Stream.concat(
                 node.tcpAddresses() == null ? Stream.empty() : 
node.tcpAddresses().stream(),
                 node.tcpHostNames() == null ? Stream.empty() : 
node.tcpHostNames().stream()
@@ -661,14 +685,17 @@ public class CommandHandler {
      * @param client Client.
      * @return List of hosts.
      */
-    private Stream<IgniteBiTuple<GridClientNode, List<String>>> 
listHostsByClientNode(GridClient client) throws GridClientException {
+    private Stream<IgniteBiTuple<GridClientNode, List<String>>> 
listHostsByClientNode(
+        GridClient client
+    ) throws GridClientException {
         return client.compute().nodes(GridClientNode::connectable).stream()
             .map(node -> new IgniteBiTuple<>(node,
                 Stream.concat(
                     node.tcpAddresses() == null ? Stream.empty() : 
node.tcpAddresses().stream(),
                     node.tcpHostNames() == null ? Stream.empty() : 
node.tcpHostNames().stream()
                 )
-                .map(addr -> addr + ":" + 
node.tcpPort()).collect(Collectors.toList())));
+                .map(addr -> addr + ":" + 
node.tcpPort()).collect(Collectors.toList()))
+            );
     }
 
     /**
@@ -1835,7 +1862,7 @@ public class CommandHandler {
 
         VisorTxTaskArg txArgs = null;
 
-        String sslProtocol = SslContextFactory.DFLT_SSL_PROTOCOL;
+        String sslProtocol = DFLT_SSL_PROTOCOL;
 
         String sslCipherSuites = "";
 
@@ -2416,6 +2443,41 @@ public class CommandHandler {
     }
 
     /**
+     * Requests password from console with message.
+     *
+     * @param msg Message.
+     * @return Password.
+     */
+    private char[] requestPasswordFromConsole(String msg) {
+        Console console = System.console();
+
+        if (console == null)
+            throw new UnsupportedOperationException("Failed to securely read 
password (console is unavailable): " + msg);
+        else
+            return console.readPassword(msg);
+    }
+
+    /**
+     * Requests user data from console with message.
+     *
+     * @param msg Message.
+     * @return Input user data.
+     */
+    private String requestDataFromConsole(String msg) {
+        Console console = System.console();
+
+        if (console != null)
+            return console.readLine(msg);
+        else {
+            Scanner scanner = new Scanner(System.in);
+
+            log(msg);
+
+            return scanner.nextLine();
+        }
+    }
+
+    /**
      * Check if raw arg is command or option.
      *
      * @return {@code true} If raw arg is command, overwise {@code false}.
@@ -2542,6 +2604,52 @@ public class CommandHandler {
             .collect(Collectors.toList());
     }
 
+    /** */
+    private void printHelp() {
+        log("This utility can do the following commands:");
+
+        usage(i("Activate cluster:"), ACTIVATE);
+        usage(i("Deactivate cluster:"), DEACTIVATE, op(CMD_AUTO_CONFIRMATION));
+        usage(i("Print current cluster state:"), STATE);
+        usage(i("Print cluster baseline topology:"), BASELINE);
+        usage(i("Add nodes into baseline topology:"), BASELINE, BASELINE_ADD, 
"consistentId1[,consistentId2,....,consistentIdN]", op(CMD_AUTO_CONFIRMATION));
+        usage(i("Remove nodes from baseline topology:"), BASELINE, 
BASELINE_REMOVE, "consistentId1[,consistentId2,....,consistentIdN]", 
op(CMD_AUTO_CONFIRMATION));
+        usage(i("Set baseline topology:"), BASELINE, BASELINE_SET, 
"consistentId1[,consistentId2,....,consistentIdN]", op(CMD_AUTO_CONFIRMATION));
+        usage(i("Set baseline topology based on version:"), BASELINE, 
BASELINE_SET_VERSION + " topologyVersion", op(CMD_AUTO_CONFIRMATION));
+        usage(i("List or kill transactions:"), TX, op(TX_XID, "XID"), 
op(TX_DURATION, "SECONDS"), op(TX_SIZE, "SIZE"), op(TX_LABEL, "PATTERN_REGEX"), 
op(or(TX_SERVERS, TX_CLIENTS)), op(TX_NODES, 
"consistentId1[,consistentId2,....,consistentIdN]"), op(TX_LIMIT, "NUMBER"), 
op(TX_ORDER, or("DURATION", "SIZE", CMD_TX_ORDER_START_TIME)), op(TX_KILL), 
op(CMD_AUTO_CONFIRMATION));
+
+        if (enableExperimental) {
+            usage(i("Print absolute paths of unused archived wal segments on 
each node:"), WAL, WAL_PRINT, 
"[consistentId1,consistentId2,....,consistentIdN]");
+            usage(i("Delete unused archived wal segments on each node:"), WAL, 
WAL_DELETE, "[consistentId1,consistentId2,....,consistentIdN] ", 
op(CMD_AUTO_CONFIRMATION));
+        }
+
+        log(i("View caches information in a cluster. For more details type:"));
+        log(i(String.join(" ", UTILITY_NAME, CACHE.text(), HELP.text()), 2));
+        nl();
+
+        log("By default commands affecting the cluster require interactive 
confirmation.");
+        log("Use " + CMD_AUTO_CONFIRMATION + " option to disable it.");
+        nl();
+
+        log("Default values:");
+        log(i("HOST_OR_IP=" + DFLT_HOST, 2));
+        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=" + DFLT_SSL_PROTOCOL, 2));
+        log(i("SSL_KEY_ALGORITHM=" + SslContextFactory.DFLT_KEY_ALGORITHM, 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:");
+        log(i(EXIT_CODE_OK + " - successful execution.", 2));
+        log(i(EXIT_CODE_INVALID_ARGUMENTS + " - invalid arguments.", 2));
+        log(i(EXIT_CODE_CONNECTION_FAILED + " - connection failed.", 2));
+        log(i(ERR_AUTHENTICATION_FAILED + " - authentication failed.", 2));
+        log(i(EXIT_CODE_UNEXPECTED_ERROR + " - unexpected error.", 2));
+    }
+
     /**
      * Parse and execute command.
      *
@@ -2556,48 +2664,7 @@ public class CommandHandler {
 
         try {
             if (F.isEmpty(rawArgs) || (rawArgs.size() == 1 && 
CMD_HELP.equalsIgnoreCase(rawArgs.get(0)))) {
-                log("This utility can do the following commands:");
-
-                usage(i("Activate cluster:"), ACTIVATE);
-                usage(i("Deactivate cluster:"), DEACTIVATE, 
op(CMD_AUTO_CONFIRMATION));
-                usage(i("Print current cluster state:"), STATE);
-                usage(i("Print cluster baseline topology:"), BASELINE);
-                usage(i("Add nodes into baseline topology:"), BASELINE, 
BASELINE_ADD, "consistentId1[,consistentId2,....,consistentIdN]", 
op(CMD_AUTO_CONFIRMATION));
-                usage(i("Remove nodes from baseline topology:"), BASELINE, 
BASELINE_REMOVE, "consistentId1[,consistentId2,....,consistentIdN]", 
op(CMD_AUTO_CONFIRMATION));
-                usage(i("Set baseline topology:"), BASELINE, BASELINE_SET, 
"consistentId1[,consistentId2,....,consistentIdN]", op(CMD_AUTO_CONFIRMATION));
-                usage(i("Set baseline topology based on version:"), BASELINE, 
BASELINE_SET_VERSION + " topologyVersion", op(CMD_AUTO_CONFIRMATION));
-                usage(i("List or kill transactions:"), TX, op(TX_XID, "XID"), 
op(TX_DURATION, "SECONDS"), op(TX_SIZE, "SIZE"), op(TX_LABEL, "PATTERN_REGEX"), 
op(or(TX_SERVERS, TX_CLIENTS)), op(TX_NODES, 
"consistentId1[,consistentId2,....,consistentIdN]"), op(TX_LIMIT, "NUMBER"), 
op(TX_ORDER, or("DURATION", "SIZE", CMD_TX_ORDER_START_TIME)), op(TX_KILL), 
op(CMD_AUTO_CONFIRMATION));
-
-                if (enableExperimental) {
-                    usage(i("Print absolute paths of unused archived wal 
segments on each node:"), WAL, WAL_PRINT, 
"[consistentId1,consistentId2,....,consistentIdN]");
-                    usage(i("Delete unused archived wal segments on each 
node:"), WAL, WAL_DELETE, "[consistentId1,consistentId2,....,consistentIdN] ", 
op(CMD_AUTO_CONFIRMATION));
-                }
-
-                log(i("View caches information in a cluster. For more details 
type:"));
-                log(i(String.join(" ", UTILITY_NAME, CACHE.text(), 
HELP.text()), 2));
-                nl();
-
-                log("By default commands affecting the cluster require 
interactive confirmation.");
-                log("Use " + CMD_AUTO_CONFIRMATION + " option to disable it.");
-                nl();
-
-                log("Default values:");
-                log(i("HOST_OR_IP=" + DFLT_HOST, 2));
-                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("KEY_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 
2));
-                log(i("TRUST_STORE_TYPE=" + SslContextFactory.DFLT_STORE_TYPE, 
2));
-                nl();
-
-                log("Exit codes:");
-                log(i(EXIT_CODE_OK + " - successful execution.", 2));
-                log(i(EXIT_CODE_INVALID_ARGUMENTS + " - invalid arguments.", 
2));
-                log(i(EXIT_CODE_CONNECTION_FAILED + " - connection failed.", 
2));
-                log(i(ERR_AUTHENTICATION_FAILED + " - authentication failed.", 
2));
-                log(i(EXIT_CODE_UNEXPECTED_ERROR + " - unexpected error.", 2));
+                printHelp();
 
                 return EXIT_CODE_OK;
             }
@@ -2650,7 +2717,7 @@ public class CommandHandler {
 
                     List<String> sslProtocols = split(args.sslProtocol(), ",");
 
-                    String sslProtocol = F.isEmpty(sslProtocols) ? 
SslContextFactory.DFLT_SSL_PROTOCOL : sslProtocols.get(0);
+                    String sslProtocol = F.isEmpty(sslProtocols) ? 
DFLT_SSL_PROTOCOL : sslProtocols.get(0);
 
                     factory.setProtocol(sslProtocol);
                     factory.setKeyAlgorithm(args.sslKeyAlgorithm());
@@ -2660,13 +2727,12 @@ public class CommandHandler {
 
                     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)
                         
factory.setKeyStorePassword(args.sslKeyStorePassword());
+                    else
+                        
factory.setKeyStorePassword(requestPasswordFromConsole("SSL keystore password: 
"));
 
                     factory.setKeyStoreType(args.sslKeyStoreType());
 
@@ -2677,6 +2743,8 @@ public class CommandHandler {
 
                         if (args.sslTrustStorePassword() != null)
                             
factory.setTrustStorePassword(args.sslTrustStorePassword());
+                        else
+                            
factory.setTrustStorePassword(requestPasswordFromConsole("SSL truststore 
password: "));
 
                         factory.setTrustStoreType(args.sslTrustStoreType());
                     }
@@ -2726,27 +2794,10 @@ public class CommandHandler {
                     if (tryConnectMaxCount > 0 && isAuthError(e)) {
                         log("Authentication error, try connection again.");
 
-                        final Console console = System.console();
-
-                        if (console != null) {
-                            if (F.isEmpty(args.getUserName()))
-                                args.setUserName(console.readLine("user: "));
+                        if (F.isEmpty(args.getUserName()))
+                            args.setUserName(requestDataFromConsole("user: "));
 
-                            args.setPassword(new 
String(console.readPassword("password: ")));
-                        }
-                        else {
-                            Scanner scanner = new Scanner(System.in);
-
-                            if (F.isEmpty(args.getUserName())) {
-                                log("user: ");
-
-                                args.setUserName(scanner.next());
-                            }
-
-                            log("password: ");
-
-                            args.setPassword(scanner.next());
-                        }
+                        args.setPassword(new 
String(requestPasswordFromConsole("password: ")));
 
                         tryConnectAgain = true;
 
@@ -2791,7 +2842,6 @@ public class CommandHandler {
      *
      * @return Last operation result;
      */
-    @SuppressWarnings("unchecked")
     public <T> T getLastOperationResult() {
         return (T)lastOperationRes;
     }

Reply via email to