git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@825008 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Davies 2009-10-14 05:07:45 +00:00
parent 43bd686a2c
commit f866f770e3
13 changed files with 218 additions and 33 deletions

View File

@ -361,7 +361,11 @@ public class ProtocolConverter {
} }
for (Iterator<StompSubscription> iter = subscriptionsByConsumerId.values().iterator(); iter.hasNext();) { for (Iterator<StompSubscription> iter = subscriptionsByConsumerId.values().iterator(); iter.hasNext();) {
StompSubscription sub = iter.next(); 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(); TransactionInfo tx = new TransactionInfo();
@ -483,6 +487,7 @@ public class ProtocolConverter {
connectionInfo.setResponseRequired(true); connectionInfo.setResponseRequired(true);
connectionInfo.setUserName(login); connectionInfo.setUserName(login);
connectionInfo.setPassword(passcode); connectionInfo.setPassword(passcode);
connectionInfo.setTransportContext(transportFilter.getPeerCertificates());
sendToActiveMQ(connectionInfo, new ResponseHandler() { sendToActiveMQ(connectionInfo, new ResponseHandler() {
public void onResponse(ProtocolConverter converter, Response response) throws IOException { public void onResponse(ProtocolConverter converter, Response response) throws IOException {

View File

@ -17,13 +17,16 @@
package org.apache.activemq.transport.stomp; package org.apache.activemq.transport.stomp;
import java.io.IOException; import java.io.IOException;
import java.security.cert.X509Certificate;
import javax.jms.JMSException; import javax.jms.JMSException;
import org.apache.activemq.command.Command; import org.apache.activemq.command.Command;
import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.TransportFilter; import org.apache.activemq.transport.TransportFilter;
import org.apache.activemq.transport.TransportListener; import org.apache.activemq.transport.TransportListener;
import org.apache.activemq.transport.tcp.SslTransport;
import org.apache.activemq.util.IOExceptionSupport; import org.apache.activemq.util.IOExceptionSupport;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -64,6 +67,7 @@ public class StompTransportFilter extends TransportFilter {
if (trace) { if (trace) {
LOG.trace("Received: \n" + command); LOG.trace("Received: \n" + command);
} }
protocolConverter.onStompCommand((StompFrame)command); protocolConverter.onStompCommand((StompFrame)command);
} catch (IOException e) { } catch (IOException e) {
onException(e); onException(e);
@ -93,6 +97,17 @@ public class StompTransportFilter extends TransportFilter {
return frameTranslator; 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() { public boolean isTrace() {
return trace; return trace;
} }

View File

@ -27,8 +27,8 @@ import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import org.apache.activemq.command.Command;
import org.apache.activemq.command.ConnectionInfo; import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.wireformat.WireFormat; import org.apache.activemq.wireformat.WireFormat;
/** /**
@ -86,23 +86,29 @@ public class SslTransport extends TcpTransport {
// now. // now.
if (command instanceof ConnectionInfo) { if (command instanceof ConnectionInfo) {
ConnectionInfo connectionInfo = (ConnectionInfo)command; ConnectionInfo connectionInfo = (ConnectionInfo)command;
connectionInfo.setTransportContext(getPeerCertificates());
SSLSocket sslSocket = (SSLSocket)this.socket; }
SSLSession sslSession = sslSocket.getSession();
X509Certificate[] clientCertChain;
try {
clientCertChain = (X509Certificate[])sslSession.getPeerCertificates();
} catch (SSLPeerUnverifiedException e) {
clientCertChain = null;
}
connectionInfo.setTransportContext(clientCertChain);
}
super.doConsume(command); 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' * @return pretty print of 'this'

View File

@ -22,6 +22,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("pojo") @XStreamAlias("pojo")
public class SamplePojo implements Serializable { public class SamplePojo implements Serializable {
private static final long serialVersionUID = 9118938642100015088L;
@XStreamAlias("name") @XStreamAlias("name")
private String name; private String name;
@XStreamAlias("city") @XStreamAlias("city")

View File

@ -16,12 +16,6 @@
*/ */
package org.apache.activemq.transport.stomp; 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 $ * @version $Revision: 732672 $

View File

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

View File

@ -50,6 +50,8 @@ public class StompTest extends CombinationTestSupport {
protected String bindAddress = "stomp://localhost:61613"; protected String bindAddress = "stomp://localhost:61613";
protected String confUri = "xbean:org/apache/activemq/transport/stomp/stomp-auth-broker.xml"; protected String confUri = "xbean:org/apache/activemq/transport/stomp/stomp-auth-broker.xml";
protected String jmsUri = "vm://localhost";
private BrokerService broker; private BrokerService broker;
private StompConnection stompConnection = new StompConnection(); private StompConnection stompConnection = new StompConnection();
@ -110,7 +112,7 @@ public class StompTest extends CombinationTestSupport {
stompConnect(); stompConnect();
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(jmsUri);
connection = cf.createConnection("system", "manager"); connection = cf.createConnection("system", "manager");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
queue = new ActiveMQQueue(getQueueName()); queue = new ActiveMQQueue(getQueueName());
@ -131,9 +133,14 @@ public class StompTest extends CombinationTestSupport {
} }
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
connection.close(); try {
stompDisconnect(); connection.close();
broker.stop(); stompDisconnect();
} catch(Exception e) {
// Some tests explicitly disconnect from stomp so can ignore
} finally {
broker.stop();
}
} }
private void stompDisconnect() throws IOException { private void stompDisconnect() throws IOException {

View File

@ -18,9 +18,9 @@
# #
# The logging properties used during tests.. # 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 # CONSOLE appender not used by default
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout=org.apache.log4j.ConsoleAppender

View File

@ -20,3 +20,12 @@ activemq-domain {
org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties"
org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.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";
};

View File

@ -15,7 +15,7 @@
## limitations under the License. ## limitations under the License.
## --------------------------------------------------------------------------- ## ---------------------------------------------------------------------------
admins=system admins=system,sslclient
tempDestinationAdmins=system,user tempDestinationAdmins=system,user,sslclient
users=system,user users=system,user,sslclient
guests=guest guests=guest

View File

@ -18,3 +18,4 @@
system=manager system=manager
user=password user=password
guest=password guest=password
sslclient=CN=localhost, OU=activemq.org, O=activemq.org, L=LA, ST=CA, C=US

View File

@ -25,7 +25,7 @@
<property name="annotatedClass"><value>org.apache.activemq.transport.stomp.SamplePojo</value></property> <property name="annotatedClass"><value>org.apache.activemq.transport.stomp.SamplePojo</value></property>
</bean> </bean>
<broker useJmx="true" persistent="false" xmlns="http://activemq.apache.org/schema/core" populateJMSXUserID="true"> <broker start="false" useJmx="true" persistent="false" xmlns="http://activemq.apache.org/schema/core" populateJMSXUserID="true">
<transportConnectors> <transportConnectors>
<transportConnector name="stomp+ssl" uri="stomp+ssl://localhost:61612"/> <transportConnector name="stomp+ssl" uri="stomp+ssl://localhost:61612"/>
@ -65,3 +65,4 @@
</broker> </broker>
</beans> </beans>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<!-- this file can only be parsed using the xbean-spring library -->
<!-- START SNIPPET: example -->
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<bean class="org.apache.activemq.util.XStreamFactoryBean" name="xstream">
<property name="annotatedClass"><value>org.apache.activemq.transport.stomp.SamplePojo</value></property>
</bean>
<!-- lets create an embedded ActiveMQ Broker -->
<amq:broker useJmx="true" persistent="false" start="false">
<amq:sslContext>
<amq:sslContext
keyStore="server.keystore" keyStorePassword="password"
trustStore="client.keystore" trustStorePassword="password"/>
</amq:sslContext>
<amq:transportConnectors>
<amq:transportConnector name="stomp+ssl" uri="stomp+ssl://localhost:61612?needClientAuth=true"/>
<amq:transportConnector name="ssl" uri="ssl://localhost:61617?needClientAuth=true"/>
</amq:transportConnectors>
<amq:plugins>
<amq:jaasCertificateAuthenticationPlugin configuration="cert-login"/>
<!-- lets configure a destination based authorization mechanism -->
<amq:authorizationPlugin>
<amq:map>
<amq:authorizationMap>
<amq:authorizationEntries>
<amq:authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
<amq:authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />
<amq:authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<amq:authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<amq:authorizationEntry topic="USERS.>" read="users" write="users" admin="users" />
<amq:authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<amq:authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</amq:authorizationEntries>
<!-- let's assign roles to temporary destinations. comment this entry if we don't want any roles assigned to temp destinations -->
<amq:tempDestinationAuthorizationEntry>
<amq:tempDestinationAuthorizationEntry read="tempDestinationAdmins" write="tempDestinationAdmins" admin="tempDestinationAdmins"/>
</amq:tempDestinationAuthorizationEntry>
</amq:authorizationMap>
</amq:map>
</amq:authorizationPlugin>
</amq:plugins>
</amq:broker>
</beans>