ARTEMIS-3069 Add option to mask using the configured password-codec

This commit is contained in:
Domenico Francesco Bruscino 2021-01-15 18:05:59 +01:00
parent 697886a87c
commit 1f825ee424
4 changed files with 156 additions and 28 deletions

View File

@ -23,6 +23,7 @@ import java.util.Map;
import io.airlift.airline.Option;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
@ -79,13 +80,8 @@ public abstract class ActionAbstract implements Action {
protected String getBrokerURLInstance() {
if (getBrokerInstance() != null) {
try {
FileConfiguration fileConfiguration = new FileConfiguration();
String brokerConfiguration = new File(new File(getBrokerEtc()), "broker.xml").toURI().toASCIIString();
FileDeploymentManager fileDeploymentManager = new FileDeploymentManager(brokerConfiguration);
fileDeploymentManager.addDeployable(fileConfiguration);
fileDeploymentManager.readConfiguration();
for (TransportConfiguration acceptorConfiguration: fileConfiguration.getAcceptorConfigurations()) {
Configuration brokerConfiguration = getBrokerConfiguration();
for (TransportConfiguration acceptorConfiguration: brokerConfiguration.getAcceptorConfigurations()) {
if (acceptorConfiguration.getName().equals("artemis")) {
Map<String, Object> acceptorParams = acceptorConfiguration.getParams();
String scheme = ConfigurationHelper.getStringProperty(TransportConstants.SCHEME_PROP_NAME, SchemaConstants.TCP, acceptorParams);
@ -110,6 +106,17 @@ public abstract class ActionAbstract implements Action {
}
protected Configuration getBrokerConfiguration() throws Exception {
FileConfiguration fileConfiguration = new FileConfiguration();
String brokerConfiguration = new File(new File(getBrokerEtc()), "broker.xml").toURI().toASCIIString();
FileDeploymentManager fileDeploymentManager = new FileDeploymentManager(brokerConfiguration);
fileDeploymentManager.addDeployable(fileConfiguration);
fileDeploymentManager.readConfiguration();
return fileConfiguration;
}
public String getBrokerEtc() {
if (brokerEtc == null) {
brokerEtc = System.getProperty("artemis.instance.etc");

View File

@ -16,18 +16,19 @@
*/
package org.apache.activemq.artemis.cli.commands;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import io.airlift.airline.Arguments;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
import org.apache.activemq.artemis.utils.SensitiveDataCodec;
@Command(name = "mask", description = "mask a password and print it out")
public class Mask implements Action {
public class Mask extends ActionAbstract {
@Arguments(description = "The password to be masked", required = true)
String password;
@ -38,7 +39,10 @@ public class Mask implements Action {
@Option(name = "--key", description = "the key (Blowfish) to mask a password")
String key;
private DefaultSensitiveStringCodec codec;
@Option(name = "--password-codec", description = "whether to use password codec defined in the configuration, default false")
boolean passwordCodec = false;
private SensitiveDataCodec<String> codec;
@Override
public Object execute(ActionContext context) throws Exception {
@ -56,7 +60,12 @@ public class Mask implements Action {
}
}
if (passwordCodec) {
Configuration brokerConfiguration = getBrokerConfiguration();
codec = PasswordMaskingUtil.getCodec(brokerConfiguration.getPasswordCodec());
} else {
codec = PasswordMaskingUtil.getDefaultCodec();
}
codec.init(params);
String masked = codec.encode(password);
@ -69,20 +78,6 @@ public class Mask implements Action {
return false;
}
@Override
public void setHomeValues(File brokerHome, File brokerInstance) {
}
@Override
public String getBrokerInstance() {
return null;
}
@Override
public String getBrokerHome() {
return null;
}
public void setPassword(String password) {
this.password = password;
}
@ -95,7 +90,11 @@ public class Mask implements Action {
this.key = key;
}
public DefaultSensitiveStringCodec getCodec() {
public void setPasswordCodec(boolean passwordCodec) {
this.passwordCodec = passwordCodec;
}
public SensitiveDataCodec<String> getCodec() {
return codec;
}

View File

@ -38,6 +38,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@ -79,6 +80,7 @@ import org.apache.activemq.artemis.nativo.jlibaio.LibaioContext;
import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
import org.apache.activemq.artemis.utils.HashProcessor;
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
import org.apache.activemq.artemis.utils.SensitiveDataCodec;
import org.apache.activemq.artemis.utils.StringUtil;
import org.apache.activemq.artemis.utils.Wait;
import org.apache.commons.configuration2.PropertiesConfiguration;
@ -1108,8 +1110,9 @@ public class ArtemisTest extends CliTestBase {
mask.setHash(true);
result = (String) mask.execute(context);
log.debug(context.getStdout());
DefaultSensitiveStringCodec codec = mask.getCodec();
codec.verify(password1.toCharArray(), result);
SensitiveDataCodec<String> codec = mask.getCodec();
Assert.assertEquals(DefaultSensitiveStringCodec.class, codec.getClass());
Assert.assertTrue(((DefaultSensitiveStringCodec)codec).verify(password1.toCharArray(), result));
context = new TestActionContext();
mask = new Mask();
@ -1120,6 +1123,33 @@ public class ArtemisTest extends CliTestBase {
assertEquals(encrypt2, result);
}
@Test
public void testMaskCommandWithPasswordCodec() throws Exception {
File instanceWithPasswordCodec = new File(temporaryFolder.getRoot(), "instance_with_password_codec");
Files.createDirectories(Paths.get(instanceWithPasswordCodec.getAbsolutePath(), "etc"));
Files.copy(Paths.get(ArtemisTest.class.getClassLoader().getResource("broker-with-password-codec.xml").toURI()),
Paths.get(instanceWithPasswordCodec.getAbsolutePath(), "etc", "broker.xml"));
System.setProperty("artemis.instance", instanceWithPasswordCodec.getAbsolutePath());
String password = "password";
String encrypt = "3a34fd21b82bf2a822fa49a8d8fa115d";
TestActionContext context = new TestActionContext();
Mask mask = new Mask();
mask.setPassword(password);
String result = (String) mask.execute(context);
assertEquals(DefaultSensitiveStringCodec.class, mask.getCodec().getClass());
assertEquals(encrypt, result);
context = new TestActionContext();
mask = new Mask();
mask.setPassword(password);
mask.setPasswordCodec(true);
result = (String) mask.execute(context);
assertEquals(TestPasswordCodec.class, mask.getCodec().getClass());
assertEquals(result, result);
}
@Test
public void testSimpleRun() throws Exception {
testSimpleRun("server");
@ -1841,4 +1871,17 @@ public class ArtemisTest extends CliTestBase {
}
}
public static class TestPasswordCodec implements SensitiveDataCodec<String> {
@Override
public String decode(Object mask) throws Exception {
return mask.toString();
}
@Override
public String encode(Object secret) throws Exception {
return secret.toString();
}
}
}

View File

@ -0,0 +1,79 @@
<?xml version='1.0'?>
<!--
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.
-->
<configuration xmlns="urn:activemq">
<jms xmlns="urn:activemq:jms">
<queue name="DLQ"/>
<queue name="ExpiryQueue"/>
</jms>
<core xmlns="urn:activemq:core">
<paging-directory>./target/paging</paging-directory>
<bindings-directory>./target/bindings</bindings-directory>
<journal-directory>./target/journal</journal-directory>
<journal-min-files>2</journal-min-files>
<large-messages-directory>./target/large-messages</large-messages-directory>
<password-codec>org.apache.activemq.cli.test.ArtemisTest$TestPasswordCodec</password-codec>
<connectors>
<!-- Default Connector. Returned to clients during broadcast and distributed around cluster. See broadcast and discovery-groups -->
<connector name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</connector>
</connectors>
<acceptors>
<!-- Default ActiveMQ Artemis Acceptor. Multi-protocol adapter. Currently supports Core, OpenWire, Stomp and AMQP. -->
<acceptor name="activemq">tcp://${activemq.remoting.default.host:localhost}:${activemq.remoting.default.port:61616}</acceptor>
<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic.-->
<acceptor name="amqp">tcp://${activemq.remoting.amqp.host:localhost}:${activemq.remoting.amqp.port:5672}?protocols=AMQP</acceptor>
<!-- STOMP Acceptor. -->
<acceptor name="stomp">tcp://${activemq.remoting.stomp.host:localhost}:${activemq.remoting.stomp.port:61613}?protocols=STOMP</acceptor>
<!-- HornetQ Compatibility Acceptor. Enables ActiveMQ Artemis Core and STOMP for legacy HornetQ clients. -->
<acceptor name="hornetq">tcp://${activemq.remoting.hornetq.host:localhost}:${activemq.remoting.hornetq.port:5445}?protocols=CORE,STOMP</acceptor>
</acceptors>
<security-settings>
<security-setting match="#">
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="send" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>10Mb</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>BLOCK</address-full-policy>
</address-setting>
</address-settings>
</core>
</configuration>