From 4f945cf7e13dafc24d55ef9d5e4a9128af371a6a Mon Sep 17 00:00:00 2001 From: "Hiram R. Chirino" Date: Mon, 18 Sep 2006 22:42:30 +0000 Subject: [PATCH] Commiting awesome patch by Sepand Mavandadi to add ActiveMQ support for SSL authentication and authorization: https://issues.apache.org/activemq/browse/AMQ-912 git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@447607 13f79535-47bb-0310-9956-ffa450edef68 --- .../activemq/ActiveMQConnectionFactory.java | 21 ++- .../security/JaasAuthenticationBroker.java | 2 + .../security/JaasAuthenticationPlugin.java | 5 +- .../transport/tcp/SslTransportFactory.java | 170 +++++++++++++++++- 4 files changed, 186 insertions(+), 12 deletions(-) diff --git a/activemq-core/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java b/activemq-core/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java index 9ef6a73a0b..fd5a492e69 100755 --- a/activemq-core/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java +++ b/activemq-core/src/main/java/org/apache/activemq/ActiveMQConnectionFactory.java @@ -211,6 +211,25 @@ public class ActiveMQConnectionFactory extends JNDIBaseStorable implements Conne protected ActiveMQConnection createActiveMQConnection() throws JMSException { return createActiveMQConnection(userName, password); } + + /** + * Creates a Transport based on this object's connection settings. + * + * Separated from createActiveMQConnection to allow for subclasses to + * override. + * + * @return The newly created Transport. + * @throws JMSException If unable to create trasnport. + * + * @author sepandm@gmail.com + */ + protected Transport createTransport() throws JMSException { + try { + return TransportFactory.connect(brokerURL,DEFAULT_CONNECTION_EXECUTOR); + } catch (Exception e) { + throw JMSExceptionSupport.create("Could not create Transport. Reason: " + e, e); + } + } /** * @return Returns the Connection. @@ -221,7 +240,7 @@ public class ActiveMQConnectionFactory extends JNDIBaseStorable implements Conne } Transport transport; try { - transport = TransportFactory.connect(brokerURL,DEFAULT_CONNECTION_EXECUTOR); + transport = createTransport(); ActiveMQConnection connection = createActiveMQConnection(transport, factoryStats); connection.setUserName(userName); diff --git a/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationBroker.java b/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationBroker.java index bec5e1fb3a..b5a6f8fe2c 100644 --- a/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationBroker.java +++ b/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationBroker.java @@ -28,6 +28,8 @@ import org.apache.activemq.broker.BrokerFilter; import org.apache.activemq.broker.ConnectionContext; import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.jaas.JassCredentialCallback; + import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList; diff --git a/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationPlugin.java b/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationPlugin.java index cf5f3a5714..968d5dabcf 100644 --- a/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationPlugin.java +++ b/activemq-core/src/main/java/org/apache/activemq/security/JaasAuthenticationPlugin.java @@ -30,9 +30,8 @@ import java.net.URL; * @version $Revision$ */ public class JaasAuthenticationPlugin implements BrokerPlugin { - - private String configuration = "activemq-domain"; - private boolean discoverLoginConfig = true; + protected String configuration = "activemq-domain"; + protected boolean discoverLoginConfig = true; public Broker installPlugin(Broker broker) { initialiseJaas(); diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransportFactory.java b/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransportFactory.java index f3704e3a69..51910a9eeb 100644 --- a/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransportFactory.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransportFactory.java @@ -16,27 +16,181 @@ */ package org.apache.activemq.transport.tcp; +import org.apache.activemq.wireformat.WireFormat; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.InactivityMonitor; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportLogger; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.transport.WireFormatNegotiator; +import org.apache.activemq.util.IOExceptionSupport; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.URISupport; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + import javax.net.ServerSocketFactory; import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; /** - * An implementation of the TCP Transport using SSL + * An implementation of the TcpTransportFactory using SSL. * + * The major contribution from this class is that it is aware of SslTransportServer and SslTransport classes. + * All Transports and TransportServers created from this factory will have their needClientAuth option set to false. + * + * @author sepandm@gmail.com (Sepand) * @version $Revision: $ */ public class SslTransportFactory extends TcpTransportFactory { - + // The context used to creat ssl sockets. + private SSLContext sslContext = null; + + // The log this uses., + private static final Log log = LogFactory.getLog(SslTransportFactory.class); + + /** + * Constructor. Nothing special. + * + */ public SslTransportFactory() { } + + /** + * Overriding to use SslTransportServer and allow for proper reflection. + */ + public TransportServer doBind(String brokerId, final URI location) throws IOException { + try { + Map options = new HashMap(URISupport.parseParamters(location)); - protected ServerSocketFactory createServerSocketFactory() { - return SSLServerSocketFactory.getDefault(); - } - - protected SocketFactory createSocketFactory() { - return SSLSocketFactory.getDefault(); + ServerSocketFactory serverSocketFactory = createServerSocketFactory(); + SslTransportServer server = + new SslTransportServer(this, location, (SSLServerSocketFactory)serverSocketFactory); + server.setWireFormatFactory(createWireFormatFactory(options)); + IntrospectionSupport.setProperties(server, options); + Map transportOptions = IntrospectionSupport.extractProperties(options, "transport."); + server.setTransportOption(transportOptions); + server.bind(); + + return server; + } + catch (URISyntaxException e) { + throw IOExceptionSupport.create(e); + } } + /** + * Overriding to allow for proper configuration through reflection. + */ + public Transport compositeConfigure(Transport transport, WireFormat format, Map options) { + + SslTransport sslTransport = (SslTransport) transport.narrow(SslTransport.class); + IntrospectionSupport.setProperties(sslTransport, options); + + Map socketOptions = IntrospectionSupport.extractProperties(options, "socket."); + + sslTransport.setSocketOptions(socketOptions); + + if (sslTransport.isTrace()) { + transport = new TransportLogger(transport); + } + + transport = new InactivityMonitor(transport); + + // Only need the WireFormatNegotiator if using openwire + if (format instanceof OpenWireFormat) { + transport = new WireFormatNegotiator(transport, (OpenWireFormat)format, sslTransport.getMinmumWireFormatVersion()); + } + + return transport; + } + + /** + * Overriding to use SslTransports. + */ + protected Transport createTransport(URI location,WireFormat wf) throws UnknownHostException,IOException{ + URI localLocation = null; + String path = location.getPath(); + // see if the path is a local URI location + if (path != null && path.length() > 0) { + int localPortIndex = path.indexOf(':'); + try { + Integer.parseInt(path.substring((localPortIndex + 1), path.length())); + String localString = location.getScheme() + ":/" + path; + localLocation = new URI(localString); + } + catch (Exception e) { + log.warn("path isn't a valid local location for SslTransport to use", e); + } + } + SocketFactory socketFactory = createSocketFactory(); + return new SslTransport(wf, (SSLSocketFactory)socketFactory, location, localLocation, false); + } + + /** + * Sets the key and trust managers used in constructed socket factories. + * + * Passes given arguments to SSLContext.init(...). + * + * @param km The sources of authentication keys or null. + * @param tm The sources of peer authentication trust decisions or null. + * @param random The source of randomness for this generator or null. + */ + public void setKeyAndTrustManagers(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws KeyManagementException { + // Killing old context and making a new one just to be safe. + try { + sslContext = SSLContext.getInstance("TLS"); + } catch (NoSuchAlgorithmException e) { + // This should not happen unless this class is improperly modified. + throw new RuntimeException("Unknown SSL algorithm encountered.", e); + } + sslContext.init(km, tm, random); + } + + /** + * Creates a new SSL ServerSocketFactory. + * + * The given factory will use user-provided key and trust managers (if the user provided them). + * + * @return Newly created (Ssl)ServerSocketFactory. + */ + protected ServerSocketFactory createServerSocketFactory() { + if (sslContext == null) { + return SSLServerSocketFactory.getDefault(); + } + else + return sslContext.getServerSocketFactory(); + } + + /** + * Creates a new SSL SocketFactory. + * + * The given factory will use user-provided key and trust managers (if the user provided them). + * + * @return Newly created (Ssl)SocketFactory. + */ + protected SocketFactory createSocketFactory() { + if ( sslContext == null ) { + return SSLSocketFactory.getDefault(); + } + else + return sslContext.getSocketFactory(); + } + + }