This commit is contained in:
Clebert Suconic 2019-12-19 17:53:52 -05:00
commit 73156cb79d
8 changed files with 157 additions and 1 deletions

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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()))) {

View File

@ -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);

View File

@ -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

View File

@ -255,6 +255,36 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
Assert.assertEquals(text, m.getBodyBuffer().readString());
}
@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();
@ -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();

View File

@ -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;
}
}