You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2019/12/19 22:54:00 UTC
[activemq-artemis] branch master updated: ARTEMIS-2580 support
pluggable SSL TrustManagerFactory
This is an automated email from the ASF dual-hosted git repository.
clebertsuconic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/master by this push:
new 8d8eaeb ARTEMIS-2580 support pluggable SSL TrustManagerFactory
new 73156cb This closes #2923
8d8eaeb is described below
commit 8d8eaebb65b4a3be7f27fb004301b5b0e76a421c
Author: Justin Bertram <jb...@apache.org>
AuthorDate: Thu Dec 19 09:03:57 2019 -0600
ARTEMIS-2580 support pluggable SSL TrustManagerFactory
---
.../api/core/TrustManagerFactoryPlugin.java | 28 +++++++++++++++
.../core/remoting/impl/netty/NettyConnector.java | 7 ++++
.../remoting/impl/netty/TransportConstants.java | 6 ++++
.../artemis/core/remoting/impl/ssl/SSLSupport.java | 15 +++++++-
.../core/remoting/impl/netty/NettyAcceptor.java | 7 ++++
docs/user-manual/en/configuring-transports.md | 17 +++++++++
.../ssl/CoreClientOverOneWaySSLTest.java | 42 ++++++++++++++++++++++
.../ssl/TestTrustManagerFactoryPlugin.java | 36 +++++++++++++++++++
8 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TrustManagerFactoryPlugin.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TrustManagerFactoryPlugin.java
new file mode 100644
index 0000000..707c698
--- /dev/null
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/TrustManagerFactoryPlugin.java
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+package org.apache.activemq.artemis.api.core;
+
+import javax.net.ssl.TrustManagerFactory;
+
+public interface TrustManagerFactoryPlugin {
+
+ /**
+ * @return the TrustManagerFactory used when invoking javax.net.ssl.TrustManagerFactory#getTrustManagers() to initialize the SSLContext
+ */
+ TrustManagerFactory getTrustManagerFactory();
+}
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 29cc9cd..ecccf00 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
@@ -222,6 +222,8 @@ public class NettyConnector extends AbstractConnector {
private String sslProvider;
+ private String trustManagerFactoryPlugin;
+
private boolean verifyHost;
private boolean trustAll;
@@ -371,6 +373,8 @@ public class NettyConnector extends AbstractConnector {
kerb5Config = ConfigurationHelper.getStringProperty(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, TransportConstants.DEFAULT_SSL_KRB5_CONFIG, configuration);
useDefaultSslContext = ConfigurationHelper.getBooleanProperty(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME, TransportConstants.DEFAULT_USE_DEFAULT_SSL_CONTEXT, configuration);
+
+ trustManagerFactoryPlugin = ConfigurationHelper.getStringProperty(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME, TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN, configuration);
} else {
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
@@ -385,6 +389,7 @@ public class NettyConnector extends AbstractConnector {
trustAll = TransportConstants.DEFAULT_TRUST_ALL;
sniHost = TransportConstants.DEFAULT_SNIHOST_CONFIG;
useDefaultSslContext = TransportConstants.DEFAULT_USE_DEFAULT_SSL_CONTEXT;
+ trustManagerFactoryPlugin = TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN;
}
tcpNoDelay = ConfigurationHelper.getBooleanProperty(TransportConstants.TCP_NODELAY_PROPNAME, TransportConstants.DEFAULT_TCP_NODELAY, configuration);
@@ -634,6 +639,7 @@ public class NettyConnector extends AbstractConnector {
.setTruststorePassword(truststorePassword)
.setTrustAll(trustAll)
.setCrlPath(crlPath)
+ .setTrustManagerFactoryPlugin(trustManagerFactoryPlugin)
.createContext();
}
Subject subject = null;
@@ -675,6 +681,7 @@ public class NettyConnector extends AbstractConnector {
.setTruststorePassword(truststorePassword)
.setSslProvider(sslProvider)
.setTrustAll(trustAll)
+ .setTrustManagerFactoryPlugin(trustManagerFactoryPlugin)
.createNettyClientContext();
Subject subject = null;
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 5b06415..d9d2d12 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
@@ -122,6 +122,8 @@ public class TransportConstants {
public static final String SSL_PROVIDER = "sslProvider";
+ public static final String TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME = "trustManagerFactoryPlugin";
+
public static final String NETTY_VERSION;
/**
@@ -218,6 +220,8 @@ public class TransportConstants {
public static final boolean DEFAULT_TRUST_ALL = false;
+ public static final String DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN = null;
+
public static final boolean DEFAULT_FORCE_SSL_PARAMETERS = false;
public static final boolean DEFAULT_USE_DEFAULT_SSL_CONTEXT = false;
@@ -364,6 +368,7 @@ public class TransportConstants {
allowableAcceptorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
allowableAcceptorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
allowableAcceptorKeys.add(TransportConstants.SSL_PROVIDER);
+ allowableAcceptorKeys.add(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME);
allowableAcceptorKeys.add(TransportConstants.SHUTDOWN_TIMEOUT);
allowableAcceptorKeys.add(TransportConstants.QUIET_PERIOD);
@@ -413,6 +418,7 @@ public class TransportConstants {
allowableConnectorKeys.add(TransportConstants.NETTY_CONNECT_TIMEOUT);
allowableConnectorKeys.add(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME);
allowableConnectorKeys.add(TransportConstants.SSL_PROVIDER);
+ allowableConnectorKeys.add(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME);
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
allowableConnectorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/ssl/SSLSupport.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/ssl/SSLSupport.java
index 507f8ea..9e2d319 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/ssl/SSLSupport.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/impl/ssl/SSLSupport.java
@@ -44,6 +44,7 @@ import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import org.apache.activemq.artemis.api.core.TrustManagerFactoryPlugin;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.utils.ClassloadingUtil;
@@ -63,6 +64,7 @@ public class SSLSupport {
private String crlPath = TransportConstants.DEFAULT_CRL_PATH;
private String sslProvider = TransportConstants.DEFAULT_SSL_PROVIDER;
private boolean trustAll = TransportConstants.DEFAULT_TRUST_ALL;
+ private String trustManagerFactoryPlugin = TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN;
public String getKeystoreProvider() {
return keystoreProvider;
@@ -145,6 +147,15 @@ public class SSLSupport {
return this;
}
+ public String getTrustManagerFactoryPlugin() {
+ return trustManagerFactoryPlugin;
+ }
+
+ public SSLSupport setTrustManagerFactoryPlugin(String trustManagerFactoryPlugin) {
+ this.trustManagerFactoryPlugin = trustManagerFactoryPlugin;
+ return this;
+ }
+
public SSLContext createContext() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
KeyManager[] keyManagers = loadKeyManagers();
@@ -190,7 +201,9 @@ public class SSLSupport {
// Private -------------------------------------------------------
private TrustManagerFactory loadTrustManagerFactory() throws Exception {
- if (trustAll) {
+ if (trustManagerFactoryPlugin != null) {
+ return AccessController.doPrivileged((PrivilegedAction<TrustManagerFactory>) () -> ((TrustManagerFactoryPlugin) ClassloadingUtil.newInstanceFromClassLoader(SSLSupport.class, trustManagerFactoryPlugin)).getTrustManagerFactory());
+ } else if (trustAll) {
//This is useful for testing but not should be used outside of that purpose
return InsecureTrustManagerFactory.INSTANCE;
} else if (truststorePath == null && (truststoreProvider == null || !"PKCS11".equals(truststoreProvider.toUpperCase()))) {
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java
index 0bc99c6..a528099 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/remoting/impl/netty/NettyAcceptor.java
@@ -177,6 +177,8 @@ public class NettyAcceptor extends AbstractAcceptor {
private final boolean verifyHost;
+ private final String trustManagerFactoryPlugin;
+
private final String kerb5Config;
private String sniHost;
@@ -303,6 +305,8 @@ public class NettyAcceptor extends AbstractAcceptor {
sslProvider = ConfigurationHelper.getStringProperty(TransportConstants.SSL_PROVIDER, TransportConstants.DEFAULT_SSL_PROVIDER, configuration);
sniHost = ConfigurationHelper.getStringProperty(TransportConstants.SNIHOST_PROP_NAME, TransportConstants.DEFAULT_SNIHOST_CONFIG, configuration);
+
+ trustManagerFactoryPlugin = ConfigurationHelper.getStringProperty(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME, TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN, configuration);
} else {
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
@@ -318,6 +322,7 @@ public class NettyAcceptor extends AbstractAcceptor {
verifyHost = TransportConstants.DEFAULT_VERIFY_HOST;
sslProvider = TransportConstants.DEFAULT_SSL_PROVIDER;
sniHost = TransportConstants.DEFAULT_SNIHOST_CONFIG;
+ trustManagerFactoryPlugin = TransportConstants.DEFAULT_TRUST_MANAGER_FACTORY_PLUGIN;
}
tcpNoDelay = ConfigurationHelper.getBooleanProperty(TransportConstants.TCP_NODELAY_PROPNAME, TransportConstants.DEFAULT_TCP_NODELAY, configuration);
@@ -580,6 +585,7 @@ public class NettyAcceptor extends AbstractAcceptor {
.setTruststorePath(trustStorePath)
.setTruststorePassword(trustStorePassword)
.setCrlPath(crlPath)
+ .setTrustManagerFactoryPlugin(trustManagerFactoryPlugin)
.createContext();
} catch (Exception e) {
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
@@ -619,6 +625,7 @@ public class NettyAcceptor extends AbstractAcceptor {
.setTruststorePath(trustStorePath)
.setTruststorePassword(trustStorePassword)
.setSslProvider(sslProvider)
+ .setTrustManagerFactoryPlugin(trustManagerFactoryPlugin)
.createNettyContext();
} catch (Exception e) {
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
diff --git a/docs/user-manual/en/configuring-transports.md b/docs/user-manual/en/configuring-transports.md
index 00df421..c941735 100644
--- a/docs/user-manual/en/configuring-transports.md
+++ b/docs/user-manual/en/configuring-transports.md
@@ -472,6 +472,23 @@ additional properties:
When used on a `connector` the `sniHost` value is used for the `server_name`
extension on the SSL connection.
+- `trustManagerFactoryPlugin`
+
+ This is valid on either an `acceptor` or `connector`. It defines the name
+ of the class which implements `org.apache.activemq.artemis.api.core.TrustManagerFactoryPlugin`.
+ This is a simple interface with a single method which returns a
+ `javax.net.ssl.TrustManagerFactory`. The `TrustManagerFactory` will be used
+ when the underlying `javax.net.ssl.SSLContext` is initialized. This allows
+ fine-grained customization of who/what the broker & client trusts.
+
+ This value takes precedence of all other SSL parameters which apply to the
+ trust manager (i.e. `trustAll`, `truststoreProvider`, `truststorePath`,
+ `truststorePassword`, `crlPath`).
+
+ Any plugin specified will need to be placed on the
+ [broker's classpath](using-server.md#adding-runtime-dependencies).
+
+
### Configuring Netty HTTP
Netty HTTP tunnels packets over the HTTP protocol. It can be useful in
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
index c6457c6..26c84e2 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
@@ -256,6 +256,36 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
}
@Test
+ public void testOneWaySSLwithTrustManagerPlugin() throws Exception {
+ createCustomSslServer(null, null, false, null, TestTrustManagerFactoryPlugin.class.getName());
+ String text = RandomUtil.randomString();
+
+ tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+ tc.getParams().put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, storeType);
+ tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, CLIENT_SIDE_TRUSTSTORE);
+ tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, PASSWORD);
+
+ ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
+ ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator));
+
+ assertTrue(TestTrustManagerFactoryPlugin.triggered.get());
+
+ ClientSession session = addClientSession(sf.createSession(false, true, true));
+ session.createQueue(CoreClientOverOneWaySSLTest.QUEUE, CoreClientOverOneWaySSLTest.QUEUE, false);
+ ClientProducer producer = addClientProducer(session.createProducer(CoreClientOverOneWaySSLTest.QUEUE));
+
+ ClientMessage message = createTextMessage(session, text);
+ producer.send(message);
+
+ ClientConsumer consumer = addClientConsumer(session.createConsumer(CoreClientOverOneWaySSLTest.QUEUE));
+ session.start();
+
+ ClientMessage m = consumer.receive(1000);
+ Assert.assertNotNull(m);
+ Assert.assertEquals(text, m.getBodyBuffer().readString());
+ }
+
+ @Test
public void testOneWaySSLwithURL() throws Exception {
createCustomSslServer();
String text = RandomUtil.randomString();
@@ -880,6 +910,14 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
String protocols,
boolean useVerifiedKeystore,
String sniHost) throws Exception {
+ createCustomSslServer(null, null, useVerifiedKeystore, null, null);
+ }
+
+ private void createCustomSslServer(String cipherSuites,
+ String protocols,
+ boolean useVerifiedKeystore,
+ String sniHost,
+ String trustManagerFactoryPlugin) throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
params.put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, storeType);
@@ -904,6 +942,10 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
params.put(TransportConstants.ENABLED_PROTOCOLS_PROP_NAME, protocols);
}
+ if (trustManagerFactoryPlugin != null) {
+ params.put(TransportConstants.TRUST_MANAGER_FACTORY_PLUGIN_PROP_NAME, trustManagerFactoryPlugin);
+ }
+
ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "nettySSL"));
server = createServer(false, config);
server.start();
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/TestTrustManagerFactoryPlugin.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/TestTrustManagerFactoryPlugin.java
new file mode 100644
index 0000000..b5391ba
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/TestTrustManagerFactoryPlugin.java
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+package org.apache.activemq.artemis.tests.integration.ssl;
+
+import javax.net.ssl.TrustManagerFactory;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import org.apache.activemq.artemis.api.core.TrustManagerFactoryPlugin;
+
+public class TestTrustManagerFactoryPlugin implements TrustManagerFactoryPlugin {
+
+ public static AtomicBoolean triggered = new AtomicBoolean(false);
+
+ @Override
+ public TrustManagerFactory getTrustManagerFactory() {
+ triggered.set(true);
+ return InsecureTrustManagerFactory.INSTANCE;
+ }
+}