You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by jb...@apache.org on 2022/12/17 01:16:02 UTC

[activemq-artemis] branch main updated: ARTEMIS-3794 System Property Encryption Support

This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 51c1504b05 ARTEMIS-3794 System Property Encryption Support
51c1504b05 is described below

commit 51c1504b058f7038de9b7ad07b2772972cbea171
Author: Ryan Highley <rh...@redhat.com>
AuthorDate: Mon Jun 27 20:54:24 2022 -0500

    ARTEMIS-3794 System Property Encryption Support
    
    Adds support for standard Java TLS and ActiveMQ Artemis-specific override
    encrypted system property values for the key store and trust store
    passwords, including a separate codec property
---
 .../core/remoting/impl/netty/NettyConnector.java   |  33 ++-
 .../remoting/impl/netty/TransportConstants.java    |   3 +
 .../remoting/impl/netty/NettyConnectorTest.java    | 225 ++++++++++++++++++++-
 3 files changed, 256 insertions(+), 5 deletions(-)

diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java
index d8458523c8..64862632d3 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyConnector.java
@@ -123,6 +123,7 @@ import org.apache.activemq.artemis.spi.core.remoting.ssl.SSLContextFactoryProvid
 import org.apache.activemq.artemis.utils.ConfigurationHelper;
 import org.apache.activemq.artemis.utils.FutureLatch;
 import org.apache.activemq.artemis.utils.IPV6Util;
+import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.lang.invoke.MethodHandles;
@@ -153,6 +154,7 @@ public class NettyConnector extends AbstractConnector {
    public static final String ACTIVEMQ_TRUSTSTORE_TYPE_PROP_NAME = "org.apache.activemq.ssl.trustStoreType";
    public static final String ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME = "org.apache.activemq.ssl.trustStore";
    public static final String ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME = "org.apache.activemq.ssl.trustStorePassword";
+   public static final String ACTIVEMQ_SSL_PASSWORD_CODEC_CLASS_PROP_NAME = "org.apache.activemq.ssl.passwordCodec";
 
    // Constants for HTTP upgrade
    // These constants are exposed publicly as they are used on the server-side to fetch
@@ -178,7 +180,6 @@ public class NettyConnector extends AbstractConnector {
       DEFAULT_CONFIG = Collections.unmodifiableMap(config);
    }
 
-
    private final boolean serverConnection;
 
    private Class<? extends Channel> channelClazz;
@@ -230,6 +231,8 @@ public class NettyConnector extends AbstractConnector {
 
    private int localPort;
 
+   private String passwordCodecClass;
+
    private String keyStoreProvider;
 
    private String keyStoreType;
@@ -324,6 +327,7 @@ public class NettyConnector extends AbstractConnector {
                          final ClientProtocolManager protocolManager) {
       this(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager, false);
    }
+
    public NettyConnector(final Map<String, Object> configuration,
                          final BufferHandler handler,
                          final BaseConnectionLifeCycleListener<?> listener,
@@ -395,6 +399,8 @@ public class NettyConnector extends AbstractConnector {
 
       localPort = ConfigurationHelper.getIntProperty(TransportConstants.LOCAL_PORT_PROP_NAME, TransportConstants.DEFAULT_LOCAL_PORT, configuration);
       if (sslEnabled) {
+         passwordCodecClass = ConfigurationHelper.getStringProperty(ActiveMQDefaultConfiguration.getPropPasswordCodec(), TransportConstants.DEFAULT_PASSWORD_CODEC_CLASS, configuration);
+
          keyStoreProvider = ConfigurationHelper.getStringProperty(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, TransportConstants.DEFAULT_KEYSTORE_PROVIDER, configuration);
 
          keyStoreType = ConfigurationHelper.getStringProperty(TransportConstants.KEYSTORE_TYPE_PROP_NAME, TransportConstants.DEFAULT_KEYSTORE_TYPE, configuration);
@@ -438,6 +444,7 @@ public class NettyConnector extends AbstractConnector {
          keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
          keyStorePassword = TransportConstants.DEFAULT_KEYSTORE_PASSWORD;
          keyStoreAlias = TransportConstants.DEFAULT_KEYSTORE_ALIAS;
+         passwordCodecClass = TransportConstants.DEFAULT_PASSWORD_CODEC_CLASS;
          trustStoreProvider = TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER;
          trustStoreType = TransportConstants.DEFAULT_TRUSTSTORE_TYPE;
          trustStorePath = TransportConstants.DEFAULT_TRUSTSTORE_PATH;
@@ -592,8 +599,14 @@ public class NettyConnector extends AbstractConnector {
             realTrustStoreType = trustStoreType;
             realTrustStorePassword = trustStorePassword;
          } else {
+            String tempPasswordCodecClass = Stream.of(System.getProperty(ACTIVEMQ_SSL_PASSWORD_CODEC_CLASS_PROP_NAME), passwordCodecClass).map(v -> useDefaultSslContext ? passwordCodecClass : v).filter(Objects::nonNull).findFirst().orElse(null);
+
             realKeyStorePath = Stream.of(System.getProperty(ACTIVEMQ_KEYSTORE_PATH_PROP_NAME), System.getProperty(JAVAX_KEYSTORE_PATH_PROP_NAME), keyStorePath).map(v -> useDefaultSslContext ? keyStorePath : v).filter(Objects::nonNull).findFirst().orElse(null);
-            realKeyStorePassword = Stream.of(System.getProperty(ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME), System.getProperty(JAVAX_KEYSTORE_PASSWORD_PROP_NAME), keyStorePassword).map(v -> useDefaultSslContext ? keyStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
+            String tempKeyStorePassword = Stream.of(System.getProperty(ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME), System.getProperty(JAVAX_KEYSTORE_PASSWORD_PROP_NAME), keyStorePassword).map(v -> useDefaultSslContext ? keyStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
+            if (tempKeyStorePassword != null && !tempKeyStorePassword.equals(keyStorePassword)) {
+               tempKeyStorePassword = processSslPasswordProperty(tempKeyStorePassword, tempPasswordCodecClass);
+            }
+            realKeyStorePassword = tempKeyStorePassword;
             realKeyStoreAlias = keyStoreAlias;
 
             Pair<String, String> keyStoreCompat = SSLSupport.getValidProviderAndType(Stream.of(System.getProperty(ACTIVEMQ_KEYSTORE_PROVIDER_PROP_NAME), System.getProperty(JAVAX_KEYSTORE_PROVIDER_PROP_NAME), keyStoreProvider).map(v -> useDefaultSslContext ? keyStoreProvider : v).filter(Objects::nonNull).findFirst().orElse(null),
@@ -602,7 +615,11 @@ public class NettyConnector extends AbstractConnector {
             realKeyStoreType = keyStoreCompat.getB();
 
             realTrustStorePath = Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME), System.getProperty(JAVAX_TRUSTSTORE_PATH_PROP_NAME), trustStorePath).map(v -> useDefaultSslContext ? trustStorePath : v).filter(Objects::nonNull).findFirst().orElse(null);
-            realTrustStorePassword = Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME), System.getProperty(JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME), trustStorePassword).map(v -> useDefaultSslContext ? trustStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
+            String tempTrustStorePassword = Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME), System.getProperty(JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME), trustStorePassword).map(v -> useDefaultSslContext ? trustStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
+            if (tempTrustStorePassword != null && !tempTrustStorePassword.equals(trustStorePassword)) {
+               tempTrustStorePassword = processSslPasswordProperty(tempTrustStorePassword, tempPasswordCodecClass);
+            }
+            realTrustStorePassword = tempTrustStorePassword;
 
             Pair<String, String> trustStoreCompat = SSLSupport.getValidProviderAndType(Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_PROVIDER_PROP_NAME), System.getProperty(JAVAX_TRUSTSTORE_PROVIDER_PROP_NAME), trustStoreProvider).map(v -> useDefaultSslContext ? trustStoreProvider : v).filter(Objects::nonNull).findFirst().orElse(null),
                                                                                        Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_TYPE_PROP_NAME), System.getProperty(JAVAX_TRUSTSTORE_TYPE_PROP_NAME), trustStoreType).map(v -> useDefaultSslContext ? trustStoreType : v).filter(Objects::nonNull).findFirst().orElse(null));
@@ -755,6 +772,15 @@ public class NettyConnector extends AbstractConnector {
       logger.debug("Started {} Netty Connector version {} to {}:{}", connectorType, TransportConstants.NETTY_VERSION, host, port);
    }
 
+   private String processSslPasswordProperty(String password, String codecClass) {
+      try {
+         return PasswordMaskingUtil.resolveMask(password, codecClass);
+      } catch (Exception e) {
+         ActiveMQClientLogger.LOGGER.errorCreatingNettyConnection(e);
+         throw new RuntimeException(e);
+      }
+   }
+
    private SSLEngine loadJdkSslEngine(final SSLContextConfig sslContextConfig) throws Exception {
       final SSLContext context = SSLContextFactoryProvider.getSSLContextFactory()
          .getSSLContext(sslContextConfig, configuration);
@@ -1366,4 +1392,3 @@ public class NettyConnector extends AbstractConnector {
       }
    }
 }
-
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java
index 9f6b590357..3edf16f755 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/TransportConstants.java
@@ -23,6 +23,7 @@ import java.util.Set;
 import io.netty.handler.codec.socksx.SocksVersion;
 import io.netty.util.Version;
 import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
+import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.lang.invoke.MethodHandles;
@@ -264,6 +265,8 @@ public class TransportConstants {
 
    public static final String DEFAULT_KEYSTORE_ALIAS = null;
 
+   public static final String DEFAULT_PASSWORD_CODEC_CLASS = DefaultSensitiveStringCodec.class.getName();
+
    public static final boolean DEFAULT_TCP_NODELAY = true;
 
    public static final int DEFAULT_TCP_SENDBUFFER_SIZE = 1024 * 1024;
diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/remoting/impl/netty/NettyConnectorTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/remoting/impl/netty/NettyConnectorTest.java
index 599feaf5b6..566a6743a8 100644
--- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/remoting/impl/netty/NettyConnectorTest.java
+++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/remoting/impl/netty/NettyConnectorTest.java
@@ -38,6 +38,9 @@ import org.apache.activemq.artemis.spi.core.remoting.ClientProtocolManager;
 import org.apache.activemq.artemis.spi.core.remoting.Connection;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
 import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
+import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
+import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
+import org.apache.activemq.artemis.utils.SensitiveDataCodec;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -171,6 +174,70 @@ public class NettyConnectorTest extends ActiveMQTestBase {
 
    }
 
+   /**
+    * that encrypted java system properties are read
+    */
+   @Test
+   public void testEncryptedJavaSystemProperty() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+
+      DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
+
+      System.setProperty(NettyConnector.JAVAX_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.JAVAX_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+      System.setProperty(NettyConnector.JAVAX_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Connection c = connector.createConnection();
+      assertNotNull(c);
+      c.close();
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+
+   }
+
+   /**
+    * that bad value encrypted java system properties are read but fail
+    */
+   @Test
+   public void testEncryptedJavaSystemPropertyFail() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+
+      DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
+
+      System.setProperty(NettyConnector.JAVAX_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.JAVAX_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("bad password")));
+      System.setProperty(NettyConnector.JAVAX_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("bad password")));
+
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Assert.assertNull(connector.createConnection());
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+
+   }
+
    @Test
    public void testOverridesJavaSystemPropertyFail() throws Exception {
       BufferHandler handler = new BufferHandler() {
@@ -310,7 +377,7 @@ public class NettyConnectorTest extends ActiveMQTestBase {
    }
 
    @Test
-   public void tesActiveMQSystemProperties() throws Exception {
+   public void testActiveMQSystemProperties() throws Exception {
       BufferHandler handler = new BufferHandler() {
          @Override
          public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
@@ -334,6 +401,162 @@ public class NettyConnectorTest extends ActiveMQTestBase {
       Assert.assertFalse(connector.isStarted());
    }
 
+   @Test
+   public void testEncryptedActiveMQSystemProperties() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
+
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Connection c = connector.createConnection();
+      assertNotNull(c);
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+   }
+
+   @Test
+   public void testEncryptedActiveMQSystemPropertiesFail() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
+
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("bad password")));
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("bad password")));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Assert.assertNull(connector.createConnection());
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+   }
+
+   public static class NettyConnectorTestPasswordCodec implements SensitiveDataCodec<String> {
+
+      private static final String MASK = "supersecureish";
+      private static final String CLEARTEXT = "securepass";
+
+      @Override
+      public String decode(Object mask) throws Exception {
+         if (!MASK.equals(mask)) {
+            return mask.toString();
+         }
+         return CLEARTEXT;
+      }
+
+      @Override
+      public String encode(Object secret) throws Exception {
+         if (!CLEARTEXT.equals(secret)) {
+            return secret.toString();
+         }
+         return MASK;
+      }
+   }
+
+   @Test
+   public void testEncryptedActiveMQSystemPropertiesWithWrappedPasswordsAndCodec() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      NettyConnectorTestPasswordCodec codec = new NettyConnectorTestPasswordCodec();
+
+      System.setProperty(NettyConnector.ACTIVEMQ_SSL_PASSWORD_CODEC_CLASS_PROP_NAME, NettyConnectorTestPasswordCodec.class.getName());
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Connection c = connector.createConnection();
+      assertNotNull(c);
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+   }
+
+   @Test
+   public void testEncryptedActiveMQSystemPropertiesWithBarePasswordsAndCodec() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      System.setProperty(NettyConnector.ACTIVEMQ_SSL_PASSWORD_CODEC_CLASS_PROP_NAME, NettyConnectorTestPasswordCodec.class.getName());
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME, "securepass");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME, "securepass");
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Connection c = connector.createConnection();
+      assertNotNull(c);
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+   }
+
+   @Test
+   public void testEncryptedActiveMQSystemPropertiesWithCodecFail() throws Exception {
+      BufferHandler handler = new BufferHandler() {
+         @Override
+         public void bufferReceived(final Object connectionID, final ActiveMQBuffer buffer) {
+         }
+      };
+      Map<String, Object> params = new HashMap<>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+
+      NettyConnector connector = new NettyConnector(params, handler, listener, executorService, Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())), Executors.newScheduledThreadPool(5, ActiveMQThreadFactory.defaultThreadFactory(getClass().getName())));
+
+      DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
+
+      System.setProperty(NettyConnector.ACTIVEMQ_SSL_PASSWORD_CODEC_CLASS_PROP_NAME, NettyConnectorTestPasswordCodec.class.getName());
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PATH_PROP_NAME, "client-keystore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME, "server-ca-truststore.jks");
+      System.setProperty(NettyConnector.ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME, PasswordMaskingUtil.wrap(codec.encode("securepass")));
+
+      connector.start();
+      Assert.assertTrue(connector.isStarted());
+      Assert.assertNull(connector.createConnection());
+      connector.close();
+      Assert.assertFalse(connector.isStarted());
+   }
+
    @Test
    public void testActiveMQOverridesSystemProperty() throws Exception {
       BufferHandler handler = new BufferHandler() {