merging 825008: https://issues.apache.org/activemq/browse/AMQ-2449 Peer certificates not propagated when using stomp+ssl w/mutual authentication

git-svn-id: https://svn.apache.org/repos/asf/activemq/branches/activemq-5.3@831960 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Bosanac Dejan 2009-11-02 16:39:08 +00:00
parent 2a4590527d
commit cd96d29a93
12 changed files with 216 additions and 31 deletions

View File

@ -361,7 +361,11 @@ public class ProtocolConverter {
}
for (Iterator<StompSubscription> 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 {

View File

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

View File

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

View File

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

View File

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

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

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.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.
## ---------------------------------------------------------------------------
admins=system
tempDestinationAdmins=system,user
users=system,user
admins=system,sslclient
tempDestinationAdmins=system,user,sslclient
users=system,user,sslclient
guests=guest

View File

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

View File

@ -25,7 +25,7 @@
<property name="annotatedClass"><value>org.apache.activemq.transport.stomp.SamplePojo</value></property>
</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>
<transportConnector name="stomp+ssl" uri="stomp+ssl://localhost:61612"/>
@ -65,3 +65,4 @@
</broker>
</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>