This is an automated email from the ASF dual-hosted git repository. sk0x50 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push: new f5dfac2 IGNITE-13716 Fixed an issue where control utility did not hide sensitive information. Fixes #8471 f5dfac2 is described below commit f5dfac22bd79fd0f13cce9840fe20114ab718976 Author: Slava Koptilin <slava.kopti...@gmail.com> AuthorDate: Wed Dec 2 01:32:03 2020 +0300 IGNITE-13716 Fixed an issue where control utility did not hide sensitive information. Fixes #8471 --- .../internal/commandline/CommandHandler.java | 33 +++++++++++- .../internal/commandline/CommonArgParser.java | 15 ++++++ .../GridCommandHandlerSslWithSecurityTest.java | 59 +++++++++++++++++++++- 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java index a612e1c..14c8799 100644 --- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java +++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java @@ -46,6 +46,7 @@ import org.apache.ignite.internal.client.impl.connection.GridClientConnectionRes import org.apache.ignite.internal.client.ssl.GridSslBasicContextFactory; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; +import org.apache.ignite.internal.util.typedef.internal.SB; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.logger.java.JavaLoggerFileHandler; import org.apache.ignite.logger.java.JavaLoggerFormatter; @@ -266,7 +267,7 @@ public class CommandHandler { } logger.info("Command [" + commandName + "] started"); - logger.info("Arguments: " + String.join(" ", rawArgs)); + logger.info("Arguments: " + argumentsToString(rawArgs)); logger.info(DELIM); lastOperationRes = command.execute(clientCfg, logger, args.verbose()); @@ -455,6 +456,36 @@ public class CommandHandler { } /** + * Joins user's arguments and hides sensitive information. + * + * @param rawArgs Arguments which user has provided. + * @return String which could be shown in console and pritned to log. + */ + private String argumentsToString(List<String> rawArgs) { + boolean hide = false; + + SB sb = new SB(); + + for (int i = 0; i < rawArgs.size(); i++) { + if (hide) { + sb.a("***** "); + + hide = false; + + continue; + } + + String arg = rawArgs.get(i); + + sb.a(arg).a(' '); + + hide = CommonArgParser.isSensitiveArgument(arg); + } + + return sb.toString(); + } + + /** * Does one of three things: * <ul> * <li>returns user name from connection parameters if it is there;</li> diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java index 52e95f4..e27179d 100644 --- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java +++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommonArgParser.java @@ -103,6 +103,9 @@ public class CommonArgParser { /** List of optional auxiliary commands. */ private static final Set<String> AUX_COMMANDS = new HashSet<>(); + /** Set of sensitive arguments */ + private static final Set<String> SENSITIVE_ARGUMENTS = new HashSet<>(); + static { AUX_COMMANDS.add(CMD_HOST); AUX_COMMANDS.add(CMD_PORT); @@ -127,6 +130,18 @@ public class CommonArgParser { AUX_COMMANDS.add(CMD_TRUSTSTORE); AUX_COMMANDS.add(CMD_TRUSTSTORE_PASSWORD); AUX_COMMANDS.add(CMD_TRUSTSTORE_TYPE); + + SENSITIVE_ARGUMENTS.add(CMD_PASSWORD); + SENSITIVE_ARGUMENTS.add(CMD_KEYSTORE_PASSWORD); + SENSITIVE_ARGUMENTS.add(CMD_TRUSTSTORE_PASSWORD); + } + + /** + * @param arg To check. + * @return True if provided argument is among sensitive one and not should be displayed. + */ + public static boolean isSensitiveArgument(String arg) { + return SENSITIVE_ARGUMENTS.contains(arg); } /** diff --git a/modules/control-utility/src/test/java/org/apache/ignite/internal/processors/security/GridCommandHandlerSslWithSecurityTest.java b/modules/control-utility/src/test/java/org/apache/ignite/internal/processors/security/GridCommandHandlerSslWithSecurityTest.java index 18a60ca..a34c619 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/internal/processors/security/GridCommandHandlerSslWithSecurityTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/internal/processors/security/GridCommandHandlerSslWithSecurityTest.java @@ -17,22 +17,29 @@ package org.apache.ignite.internal.processors.security; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Handler; +import java.util.logging.Logger; import org.apache.ignite.configuration.ConnectorConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.commandline.CommandHandler; import org.apache.ignite.internal.commandline.NoopConsole; import org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; +import static org.apache.ignite.cluster.ClusterState.ACTIVE; import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK; import static org.apache.ignite.internal.commandline.CommandList.DEACTIVATE; import static org.apache.ignite.plugin.security.SecurityPermissionSetBuilder.ALLOW_ALL; +import static org.apache.ignite.testframework.GridTestUtils.assertContains; import static org.apache.ignite.testframework.GridTestUtils.keyStorePassword; import static org.apache.ignite.testframework.GridTestUtils.keyStorePath; import static org.apache.ignite.testframework.GridTestUtils.sslTrustedFactory; @@ -47,13 +54,51 @@ public class GridCommandHandlerSslWithSecurityTest extends GridCommonAbstractTes /** Password. */ private final String pwd = "testPwd"; + /** System out. */ + protected static PrintStream sysOut; + + /** + * Test out - can be injected via {@link #injectTestSystemOut()} instead of System.out and analyzed in test. + * Will be as well passed as a handler output for an anonymous logger in the test. + */ + protected static ByteArrayOutputStream testOut; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + testOut = new ByteArrayOutputStream(16 * 1024); + + sysOut = System.out; + } + /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { super.afterTest(); + System.setOut(sysOut); + + testOut.reset(); + stopAllGrids(); } + /** + * Sets test output stream. + */ + protected void injectTestSystemOut() { + System.setOut(new PrintStream(testOut)); + } + + /** + * Flushes all Logger handlers to make log data available to test. + * @param hnd Command handler. + */ + private void flushCommandOutput(CommandHandler hnd) { + Logger log = U.field(hnd, "logger"); + Arrays.stream(log.getHandlers()).forEach(Handler::flush); + } + /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { return super.getConfiguration(igniteInstanceName) @@ -77,7 +122,7 @@ public class GridCommandHandlerSslWithSecurityTest extends GridCommonAbstractTes public void testInputKeyTrustStorePwdOnlyOnce() throws Exception { IgniteEx crd = startGrid(); - crd.cluster().active(true); + crd.cluster().state(ACTIVE); CommandHandler cmd = new CommandHandler(); @@ -129,7 +174,9 @@ public class GridCommandHandlerSslWithSecurityTest extends GridCommonAbstractTes public void testConnector() throws Exception { IgniteEx crd = startGrid(); - crd.cluster().active(true); + crd.cluster().state(ACTIVE); + + injectTestSystemOut(); CommandHandler hnd = new CommandHandler(); @@ -143,5 +190,13 @@ public class GridCommandHandlerSslWithSecurityTest extends GridCommonAbstractTes "--truststore-password", keyStorePassword())); assertEquals(EXIT_CODE_OK, exitCode); + + flushCommandOutput(hnd); + + // Make sure all sensitive information is masked. + String testOutput = testOut.toString(); + assertContains(log, testOutput, "--password *****"); + assertContains(log, testOutput, "--keystore-password *****"); + assertContains(log, testOutput, "--truststore-password *****"); } }