diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java index dc3c34427f..5c37348463 100644 --- a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java @@ -361,7 +361,11 @@ public class ProtocolConverter { } for (Iterator iter = subscriptionsByConsumerId.values().iterator(); iter.hasNext();) { StompSubscription sub = iter.next(); - sub.onStompAbort(activemqTx); + try { + sub.onStompAbort(activemqTx); + } catch (Exception e) { + throw new ProtocolException("Transaction abort failed", false, e); + } } TransactionInfo tx = new TransactionInfo(); @@ -483,6 +487,7 @@ public class ProtocolConverter { connectionInfo.setResponseRequired(true); connectionInfo.setUserName(login); connectionInfo.setPassword(passcode); + connectionInfo.setTransportContext(transportFilter.getPeerCertificates()); sendToActiveMQ(connectionInfo, new ResponseHandler() { public void onResponse(ProtocolConverter converter, Response response) throws IOException { diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/StompTransportFilter.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/StompTransportFilter.java index b963958730..c07112a8e8 100644 --- a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/StompTransportFilter.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/StompTransportFilter.java @@ -17,13 +17,16 @@ package org.apache.activemq.transport.stomp; import java.io.IOException; +import java.security.cert.X509Certificate; import javax.jms.JMSException; import org.apache.activemq.command.Command; + import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.TransportFilter; import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.tcp.SslTransport; import org.apache.activemq.util.IOExceptionSupport; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,6 +67,7 @@ public class StompTransportFilter extends TransportFilter { if (trace) { LOG.trace("Received: \n" + command); } + protocolConverter.onStompCommand((StompFrame)command); } catch (IOException e) { onException(e); @@ -93,6 +97,17 @@ public class StompTransportFilter extends TransportFilter { return frameTranslator; } + public X509Certificate[] getPeerCertificates() { + if(next instanceof SslTransport) { + X509Certificate[] peerCerts = ((SslTransport)next).getPeerCertificates(); + if (trace && peerCerts != null) { + LOG.debug("Peer Identity has been verified\n"); + } + return peerCerts; + } + return null; + } + public boolean isTrace() { return trace; } diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java b/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java index 022f22b413..f10bba2a9f 100644 --- a/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java @@ -27,8 +27,8 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import org.apache.activemq.command.Command; import org.apache.activemq.command.ConnectionInfo; + import org.apache.activemq.wireformat.WireFormat; /** @@ -86,23 +86,29 @@ public class SslTransport extends TcpTransport { // now. if (command instanceof ConnectionInfo) { ConnectionInfo connectionInfo = (ConnectionInfo)command; - - SSLSocket sslSocket = (SSLSocket)this.socket; - - SSLSession sslSession = sslSocket.getSession(); - - X509Certificate[] clientCertChain; - try { - clientCertChain = (X509Certificate[])sslSession.getPeerCertificates(); - } catch (SSLPeerUnverifiedException e) { - clientCertChain = null; - } - - connectionInfo.setTransportContext(clientCertChain); - } - + connectionInfo.setTransportContext(getPeerCertificates()); + } super.doConsume(command); } + + /** + * @return peer certificate chain associated with the ssl socket + */ + public X509Certificate[] getPeerCertificates() { + + SSLSocket sslSocket = (SSLSocket)this.socket; + + SSLSession sslSession = sslSocket.getSession(); + + X509Certificate[] clientCertChain; + try { + clientCertChain = (X509Certificate[])sslSession.getPeerCertificates(); + } catch (SSLPeerUnverifiedException e) { + clientCertChain = null; + } + + return clientCertChain; + } /** * @return pretty print of 'this' diff --git a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/SamplePojo.java b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/SamplePojo.java index 7671080d1c..c5107980d9 100644 --- a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/SamplePojo.java +++ b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/SamplePojo.java @@ -22,6 +22,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("pojo") public class SamplePojo implements Serializable { + private static final long serialVersionUID = 9118938642100015088L; + @XStreamAlias("name") private String name; @XStreamAlias("city") diff --git a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompNIOTest.java b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompNIOTest.java index a0f7e5082f..873bc0aecf 100644 --- a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompNIOTest.java +++ b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompNIOTest.java @@ -16,12 +16,6 @@ */ package org.apache.activemq.transport.stomp; -import java.io.IOException; -import java.net.Socket; -import java.net.URI; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLSocketFactory; /** * @version $Revision: 732672 $ diff --git a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompSslAuthTest.java b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompSslAuthTest.java new file mode 100644 index 0000000000..f925f6dd2f --- /dev/null +++ b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompSslAuthTest.java @@ -0,0 +1,69 @@ +/** + * 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.transport.stomp; + +import java.io.IOException; +import java.net.Socket; +import java.net.URI; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + + + +/** + * @version $Revision: 1461 $ + */ +public class StompSslAuthTest extends StompTest { + + + protected void setUp() throws Exception { + + // Test mutual authentication on both stomp and standard ssl transports + bindAddress = "stomp+ssl://localhost:61612"; + confUri = "xbean:org/apache/activemq/transport/stomp/sslstomp-mutual-auth-broker.xml"; + jmsUri="ssl://localhost:61617"; + + System.setProperty("javax.net.ssl.trustStore", "src/test/resources/client.keystore"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("javax.net.ssl.keyStore", "src/test/resources/server.keystore"); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.keyStoreType", "jks"); + //System.setProperty("javax.net.debug","ssl,handshake"); + super.setUp(); + } + + protected Socket createSocket(URI connectUri) throws IOException { + SocketFactory factory = SSLSocketFactory.getDefault(); + return factory.createSocket("127.0.0.1", connectUri.getPort()); + } + + // NOOP - These operations handled by jaas cert login module + public void testConnectNotAuthenticatedWrongUser() throws Exception { + } + + public void testConnectNotAuthenticatedWrongPassword() throws Exception { + } + + public void testSendNotAuthorized() throws Exception { + } + + public void testSubscribeNotAuthorized() throws Exception { + } + +} diff --git a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompTest.java b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompTest.java index 5dc3e21b5d..74d6c977bd 100644 --- a/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompTest.java +++ b/activemq-core/src/test/java/org/apache/activemq/transport/stomp/StompTest.java @@ -50,6 +50,8 @@ public class StompTest extends CombinationTestSupport { protected String bindAddress = "stomp://localhost:61613"; protected String confUri = "xbean:org/apache/activemq/transport/stomp/stomp-auth-broker.xml"; + protected String jmsUri = "vm://localhost"; + private BrokerService broker; private StompConnection stompConnection = new StompConnection(); @@ -110,7 +112,7 @@ public class StompTest extends CombinationTestSupport { stompConnect(); - ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(jmsUri); connection = cf.createConnection("system", "manager"); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); queue = new ActiveMQQueue(getQueueName()); @@ -131,9 +133,14 @@ public class StompTest extends CombinationTestSupport { } protected void tearDown() throws Exception { - connection.close(); - stompDisconnect(); - broker.stop(); + try { + connection.close(); + stompDisconnect(); + } catch(Exception e) { + // Some tests explicitly disconnect from stomp so can ignore + } finally { + broker.stop(); + } } private void stompDisconnect() throws IOException { diff --git a/activemq-core/src/test/resources/log4j.properties b/activemq-core/src/test/resources/log4j.properties index d95fe6f509..bbf92c8720 100755 --- a/activemq-core/src/test/resources/log4j.properties +++ b/activemq-core/src/test/resources/log4j.properties @@ -18,9 +18,9 @@ # # The logging properties used during tests.. # -log4j.rootLogger=INFO, out, stdout +log4j.rootLogger=DEBUG, out, stdout -log4j.logger.org.apache.activemq.spring=WARN +log4j.logger.org.apache.activemq=DEBUG # CONSOLE appender not used by default log4j.appender.stdout=org.apache.log4j.ConsoleAppender diff --git a/activemq-core/src/test/resources/login.config b/activemq-core/src/test/resources/login.config index 11a2b5009f..fec8a393aa 100644 --- a/activemq-core/src/test/resources/login.config +++ b/activemq-core/src/test/resources/login.config @@ -20,3 +20,12 @@ activemq-domain { org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; }; + +cert-login { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; + +}; + diff --git a/activemq-core/src/test/resources/org/apache/activemq/security/groups.properties b/activemq-core/src/test/resources/org/apache/activemq/security/groups.properties index 168d7f55e9..bdec91f3db 100644 --- a/activemq-core/src/test/resources/org/apache/activemq/security/groups.properties +++ b/activemq-core/src/test/resources/org/apache/activemq/security/groups.properties @@ -15,7 +15,7 @@ ## limitations under the License. ## --------------------------------------------------------------------------- -admins=system -tempDestinationAdmins=system,user -users=system,user +admins=system,sslclient +tempDestinationAdmins=system,user,sslclient +users=system,user,sslclient guests=guest diff --git a/activemq-core/src/test/resources/org/apache/activemq/security/users.properties b/activemq-core/src/test/resources/org/apache/activemq/security/users.properties index 9b80e0a49d..cf72413658 100644 --- a/activemq-core/src/test/resources/org/apache/activemq/security/users.properties +++ b/activemq-core/src/test/resources/org/apache/activemq/security/users.properties @@ -18,3 +18,4 @@ system=manager user=password guest=password +sslclient=CN=localhost, OU=activemq.org, O=activemq.org, L=LA, ST=CA, C=US \ No newline at end of file diff --git a/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-auth-broker.xml b/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-auth-broker.xml index 1238168885..509f213f5d 100644 --- a/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-auth-broker.xml +++ b/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-auth-broker.xml @@ -25,7 +25,7 @@ org.apache.activemq.transport.stomp.SamplePojo - + @@ -65,3 +65,4 @@ + diff --git a/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-mutual-auth-broker.xml b/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-mutual-auth-broker.xml new file mode 100644 index 0000000000..bb4ef36e2a --- /dev/null +++ b/activemq-core/src/test/resources/org/apache/activemq/transport/stomp/sslstomp-mutual-auth-broker.xml @@ -0,0 +1,76 @@ + + + + + + + + + org.apache.activemq.transport.stomp.SamplePojo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +