This is an automated email from the ASF dual-hosted git repository.
clebertsuconic pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/artemis.git
The following commit(s) were added to refs/heads/main by this push:
new bae1c1ada8 ARTEMIS-6049 mask cluster-password input from CLI
bae1c1ada8 is described below
commit bae1c1ada82ccd67e709dec51d04774ccd608a47
Author: Justin Bertram <[email protected]>
AuthorDate: Tue May 5 15:50:22 2026 -0500
ARTEMIS-6049 mask cluster-password input from CLI
---
.../activemq/artemis/cli/commands/Create.java | 21 ++++-
.../artemis/cli/commands/InputAbstract.java | 12 ++-
.../cli/commands/CreateTestIndividualSettings.java | 101 +++++++++++++++++++++
3 files changed, 130 insertions(+), 4 deletions(-)
diff --git
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java
index 32f70c1c89..1dc72c3b19 100644
---
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java
+++
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java
@@ -35,6 +35,7 @@ import
org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancing
import org.apache.activemq.artemis.nativo.jlibaio.LibaioContext;
import org.apache.activemq.artemis.nativo.jlibaio.LibaioFile;
import org.apache.activemq.artemis.utils.FileUtil;
+import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@@ -444,10 +445,24 @@ public class Create extends InstallAbstract {
return clusterUser;
}
- private String getClusterPassword() {
+ protected void setClusterPassword(String clusterPassword) {
+ this.clusterPassword = clusterPassword;
+ }
+
+ protected String getClusterPassword() {
if (clusterPassword == null) {
clusterPassword = inputPassword("--cluster-password", "What is the
cluster password?", "password-admin");
}
+ if (!PasswordMaskingUtil.isEncMasked(clusterPassword)) {
+ try {
+ clusterPassword =
PasswordMaskingUtil.wrap(PasswordMaskingUtil.getDefaultCodec().encode(clusterPassword));
+ getActionContext().out.println("Using masked cluster-password: " +
clusterPassword);
+ } catch (Exception e) {
+ getActionContext().err.println("Warning: Failed to mask
password.");
+ getActionContext().err.println("Reason: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
return clusterPassword;
}
@@ -489,7 +504,9 @@ public class Create extends InstallAbstract {
password = inputPassword("--password", "What is the default
password?", "admin");
}
- password = HashUtil.tryHash(getActionContext(), password);
+ if (!PasswordMaskingUtil.isEncMasked(password)) {
+ password = HashUtil.tryHash(getActionContext(), password);
+ }
return password;
}
diff --git
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InputAbstract.java
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InputAbstract.java
index 602d81cdf3..c320be6f22 100644
---
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InputAbstract.java
+++
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/InputAbstract.java
@@ -31,13 +31,17 @@ public class InputAbstract extends ActionAbstract {
private static boolean inputEnabled = false;
/**
- * Test cases validating or using the CLI cannot deal with inputs, so they
are generally disabled, however the main
- * method from the CLI will enable it back.
+ * Test cases validating or using the CLI usually don't deal with inputs,
so they are generally disabled, however
+ * the main method from the CLI will enable it back.
*/
public static void enableInput() {
inputEnabled = true;
}
+ public static void disableInput() {
+ inputEnabled = false;
+ }
+
@Option(names = "--silent", description = "Disable all the inputs, and make
a best guess for any required input.")
private boolean silentInput = false;
@@ -145,4 +149,8 @@ public class InputAbstract extends ActionAbstract {
return null;
}
+
+ public void setLineReader(InputReader lineReader) {
+ this.lineReader = lineReader;
+ }
}
diff --git
a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/CreateTestIndividualSettings.java
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/CreateTestIndividualSettings.java
index 20a8868358..ddd1466ec4 100644
---
a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/CreateTestIndividualSettings.java
+++
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/commands/CreateTestIndividualSettings.java
@@ -20,14 +20,21 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.util.Map;
+import org.apache.activemq.artemis.cli.commands.util.input.InputReader;
import org.apache.activemq.artemis.tests.extensions.TargetTempDirFactory;
+import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
+import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
import org.apache.activemq.artemis.utils.RandomUtil;
+import org.apache.activemq.artemis.utils.SensitiveDataCodec;
import org.apache.activemq.cli.test.TestActionContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mockito;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -84,4 +91,98 @@ public class CreateTestIndividualSettings {
}
return false;
}
+
+ @Test
+ public void testMaskClusterPasswordUserInput() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+
+ Create c = new Create();
+ Create.enableInput();
+ try {
+ InputReader inputReader = Mockito.mock(InputReader.class);
+
Mockito.when(inputReader.readPassword(Mockito.anyString())).thenReturn(password);
+ c.setLineReader(inputReader);
+
+
assertEquals(PasswordMaskingUtil.wrap(PasswordMaskingUtil.getDefaultCodec().encode(password)),
c.getClusterPassword());
+ } finally {
+ Create.disableInput();
+ }
+ }
+
+ @Test
+ public void testMaskClusterPasswordSwitch() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+
+ Create c = new Create();
+ c.setClusterPassword(password);
+
assertEquals(PasswordMaskingUtil.wrap(PasswordMaskingUtil.getDefaultCodec().encode(password)),
c.getClusterPassword());
+ }
+
+ @Test
+ public void testMaskClusterPasswordAlreadyEncoded() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+ final String encodedPassword =
PasswordMaskingUtil.wrap(PasswordMaskingUtil.getDefaultCodec().encode(password));
+
+ Create c = new Create();
+ c.setClusterPassword(encodedPassword);
+ assertEquals(encodedPassword, c.getClusterPassword());
+ }
+
+ @Test
+ public void testMaskClusterPasswordMultipleGets() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+ final String encodedPassword =
PasswordMaskingUtil.wrap(PasswordMaskingUtil.getDefaultCodec().encode(password));
+
+ Create c = new Create();
+ c.setClusterPassword(password);
+ assertEquals(encodedPassword, c.getClusterPassword());
+ assertEquals(encodedPassword, c.getClusterPassword());
+ }
+
+ @Test
+ public void testMaskAdminPasswordUserInput() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+
+ Create c = new Create();
+ Create.enableInput();
+ try {
+ InputReader inputReader = Mockito.mock(InputReader.class);
+
Mockito.when(inputReader.readPassword(Mockito.anyString())).thenReturn(password);
+ c.setLineReader(inputReader);
+
+
assertTrue(PasswordMaskingUtil.getDefaultCodec(Map.of(DefaultSensitiveStringCodec.ALGORITHM,
DefaultSensitiveStringCodec.ONE_WAY)).verify(password.toCharArray(),
PasswordMaskingUtil.unwrap(c.getPassword())));
+ } finally {
+ Create.disableInput();
+ }
+ }
+
+ @Test
+ public void testMaskAdminPasswordSwitch() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+
+ Create c = new Create();
+ c.setPassword(password);
+
assertTrue(PasswordMaskingUtil.getDefaultCodec(Map.of(DefaultSensitiveStringCodec.ALGORITHM,
DefaultSensitiveStringCodec.ONE_WAY)).verify(password.toCharArray(),
PasswordMaskingUtil.unwrap(c.getPassword())));
+ }
+
+ @Test
+ public void testMaskAdminPasswordAlreadyHashed() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+ final String hashedPassword =
PasswordMaskingUtil.getHashProcessor().hash(password);
+
+ Create c = new Create();
+ c.setPassword(hashedPassword);
+ assertEquals(hashedPassword, c.getPassword());
+ }
+
+ @Test
+ public void testMaskAdminPasswordMultipleGets() throws Exception {
+ final String password = RandomUtil.randomUUIDString();
+ final SensitiveDataCodec<String> codec =
PasswordMaskingUtil.getDefaultCodec(Map.of(DefaultSensitiveStringCodec.ALGORITHM,
DefaultSensitiveStringCodec.ONE_WAY));
+
+ Create c = new Create();
+ c.setPassword(password);
+ assertTrue(codec.verify(password.toCharArray(),
PasswordMaskingUtil.unwrap(c.getPassword())));
+ assertTrue(codec.verify(password.toCharArray(),
PasswordMaskingUtil.unwrap(c.getPassword())));
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]