Also relates to: https://issues.apache.org/jira/browse/AMQ-3996

Test case added

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1401511 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Timothy A. Bish 2012-10-23 23:06:50 +00:00
parent d212d3c02a
commit f8f24e8307
15 changed files with 381 additions and 31 deletions

View File

@ -673,7 +673,7 @@ public class ProtocolConverter {
connectionInfo.setResponseRequired(true);
connectionInfo.setUserName(login);
connectionInfo.setPassword(passcode);
connectionInfo.setTransportContext(stompTransport.getPeerCertificates());
connectionInfo.setTransportContext(command.getTransportContext());
sendToActiveMQ(connectionInfo, new ResponseHandler() {
public void onResponse(ProtocolConverter converter, Response response) throws IOException {

View File

@ -41,6 +41,8 @@ public class StompFrame implements Command {
private Map<String, String> headers = new HashMap<String, String>();
private byte[] content = NO_DATA;
private transient Object transportContext = null;
public StompFrame(String command) {
this(command, null, null);
}
@ -210,4 +212,26 @@ public class StompFrame implements Command {
buffer.append('\u0000');
return buffer.toString();
}
/**
* Transports may wish to associate additional data with the connection. For
* example, an SSL transport may use this field to attach the client
* certificates used when the connection was established.
*
* @return the transport context.
*/
public Object getTransportContext() {
return transportContext;
}
/**
* Transports may wish to associate additional data with the connection. For
* example, an SSL transport may use this field to attach the client
* certificates used when the connection was established.
*
* @param transportContext value used to set the transport context
*/
public void setTransportContext(Object transportContext) {
this.transportContext = transportContext;
}
}

View File

@ -16,21 +16,25 @@
*/
package org.apache.activemq.transport.stomp;
import org.apache.activemq.transport.nio.NIOSSLTransport;
import org.apache.activemq.wireformat.WireFormat;
import javax.net.SocketFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
import org.apache.activemq.transport.nio.NIOSSLTransport;
import org.apache.activemq.wireformat.WireFormat;
public class StompNIOSSLTransport extends NIOSSLTransport {
StompCodec codec;
private X509Certificate[] cachedPeerCerts;
public StompNIOSSLTransport(WireFormat wireFormat, SocketFactory socketFactory, URI remoteLocation, URI localLocation) throws UnknownHostException, IOException {
super(wireFormat, socketFactory, remoteLocation, localLocation);
}
@ -56,4 +60,15 @@ public class StompNIOSSLTransport extends NIOSSLTransport {
codec.parse(input, fill.length);
}
@Override
public void doConsume(Object command) {
StompFrame frame = (StompFrame) command;
if (cachedPeerCerts == null) {
cachedPeerCerts = getPeerCertificates();
}
frame.setTransportContext(cachedPeerCerts);
super.doConsume(command);
}
}

View File

@ -50,7 +50,7 @@ public class StompNIOSSLTransportFactory extends StompNIOTransportFactory {
@Override
public boolean isSslServer() {
return false;
return true;
}
};
}

View File

@ -16,15 +16,25 @@
*/
package org.apache.activemq.transport.stomp;
import java.io.IOException;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import org.apache.activemq.broker.BrokerContext;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.BrokerServiceAware;
import org.apache.activemq.transport.MutexTransport;
import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.tcp.SslTransport;
import org.apache.activemq.transport.tcp.SslTransportFactory;
import org.apache.activemq.transport.tcp.SslTransportServer;
import org.apache.activemq.util.IntrospectionSupport;
import org.apache.activemq.wireformat.WireFormat;
@ -41,6 +51,29 @@ public class StompSslTransportFactory extends SslTransportFactory implements Bro
return "stomp";
}
protected SslTransportServer createSslTransportServer(final URI location, SSLServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException {
return new SslTransportServer(this, location, serverSocketFactory) {
@Override
protected Transport createTransport(Socket socket, WireFormat format) throws IOException {
return new SslTransport(format, (SSLSocket)socket) {
private X509Certificate[] cachedPeerCerts;
@Override
public void doConsume(Object command) {
StompFrame frame = (StompFrame) command;
if (cachedPeerCerts == null) {
cachedPeerCerts = getPeerCertificates();
}
frame.setTransportContext(cachedPeerCerts);
super.doConsume(command);
}
};
}
};
}
@SuppressWarnings("rawtypes")
public Transport compositeConfigure(Transport transport, WireFormat format, Map options) {
transport = new StompTransportFilter(transport, format, brokerContext);

View File

@ -17,7 +17,6 @@
package org.apache.activemq.transport.stomp;
import java.io.IOException;
import java.security.cert.X509Certificate;
import org.apache.activemq.command.Command;
@ -31,8 +30,6 @@ public interface StompTransport {
public void sendToStomp(StompFrame command) throws IOException;
public X509Certificate[] getPeerCertificates();
public void onException(IOException error);
public StompInactivityMonitor getInactivityMonitor();

View File

@ -17,7 +17,6 @@
package org.apache.activemq.transport.stomp;
import java.io.IOException;
import java.security.cert.X509Certificate;
import javax.jms.JMSException;
@ -26,7 +25,6 @@ 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.activemq.wireformat.WireFormat;
import org.slf4j.Logger;
@ -41,7 +39,6 @@ import org.slf4j.LoggerFactory;
* @author <a href="http://hiramchirino.com">chirino</a>
*/
public class StompTransportFilter extends TransportFilter implements StompTransport {
private static final Logger LOG = LoggerFactory.getLogger(StompTransportFilter.class);
private static final Logger TRACE = LoggerFactory.getLogger(StompTransportFilter.class.getPackage().getName() + ".StompIO");
private final ProtocolConverter protocolConverter;
private StompInactivityMonitor monitor;
@ -98,17 +95,6 @@ public class StompTransportFilter extends TransportFilter implements StompTransp
}
}
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

@ -55,7 +55,7 @@ public class SslTransportFactory extends TcpTransportFactory {
Map<String, String> options = new HashMap<String, String>(URISupport.parseParameters(location));
ServerSocketFactory serverSocketFactory = createServerSocketFactory();
SslTransportServer server = new SslTransportServer(this, location, (SSLServerSocketFactory)serverSocketFactory);
SslTransportServer server = createSslTransportServer(location, (SSLServerSocketFactory)serverSocketFactory);
server.setWireFormatFactory(createWireFormatFactory(options));
IntrospectionSupport.setProperties(server, options);
Map<String, Object> transportOptions = IntrospectionSupport.extractProperties(options, "transport.");
@ -68,6 +68,20 @@ public class SslTransportFactory extends TcpTransportFactory {
}
}
/**
* Allows subclasses of SslTransportFactory to create custom instances of
* SslTransportServer.
*
* @param location
* @param serverSocketFactory
* @return
* @throws IOException
* @throws URISyntaxException
*/
protected SslTransportServer createSslTransportServer(final URI location, SSLServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException {
return new SslTransportServer(this, location, serverSocketFactory);
}
/**
* Overriding to allow for proper configuration through reflection but delegate to get common
* configuration

View File

@ -0,0 +1,159 @@
/**
* 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.bugs;
import java.io.File;
import java.net.Socket;
import java.net.URI;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import junit.framework.TestCase;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQSslConnectionFactory;
import org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.transport.stomp.Stomp;
import org.apache.activemq.transport.stomp.StompConnection;
import org.apache.activemq.transport.stomp.StompFrame;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
*
*/
public class AMQ4126Test {
protected BrokerService broker;
protected String java_security_auth_login_config = "java.security.auth.login.config";
protected String xbean = "xbean:";
protected String confBase = "src/test/resources/org/apache/activemq/bugs/amq4126";
protected String certBase = "src/test/resources/org/apache/activemq/security";
protected String sep = File.separator;
protected String JaasStompSSLBroker_xml = "JaasStompSSLBroker.xml";
protected StompConnection stompConnection = new StompConnection();
protected String oldLoginConf = null;
@Before
public void before() throws Exception {
if (System.getProperty(java_security_auth_login_config) != null) {
oldLoginConf = System.getProperty(java_security_auth_login_config);
}
System.setProperty(java_security_auth_login_config, confBase + sep + "login.config");
broker = BrokerFactory.createBroker(xbean + confBase + sep + JaasStompSSLBroker_xml);
broker.start();
broker.waitUntilStarted();
}
@After
public void after() throws Exception {
broker.stop();
if (oldLoginConf != null) {
System.setProperty(java_security_auth_login_config, oldLoginConf);
}
}
public Socket createSocket(String host, int port) throws Exception {
System.setProperty("javax.net.ssl.trustStore", certBase + sep + "broker1.ks");
System.setProperty("javax.net.ssl.trustStorePassword", "password");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.keyStore", certBase + sep + "client.ks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.keyStoreType", "jks");
SocketFactory factory = SSLSocketFactory.getDefault();
return factory.createSocket(host, port);
}
public void stompConnectTo(String connectorName, String extraHeaders) throws Exception {
String host = broker.getConnectorByName(connectorName).getConnectUri().getHost();
int port = broker.getConnectorByName(connectorName).getConnectUri().getPort();
stompConnection.open(createSocket(host, port));
String extra = extraHeaders != null ? extraHeaders : "\n";
stompConnection.sendFrame("CONNECT\n" + extra + "\n" + Stomp.NULL);
StompFrame f = stompConnection.receive();
TestCase.assertEquals(f.getBody(), "CONNECTED", f.getAction());
stompConnection.close();
}
@Test
public void testStompSSLWithUsernameAndPassword() throws Exception {
stompConnectTo("stomp+ssl", "login:system\n" + "passcode:manager\n");
}
@Test
public void testStompSSLWithCertificate() throws Exception {
stompConnectTo("stomp+ssl", null);
}
@Test
public void testStompNIOSSLWithUsernameAndPassword() throws Exception {
stompConnectTo("stomp+nio+ssl", "login:system\n" + "passcode:manager\n");
}
@Test
public void testStompNIOSSLWithCertificate() throws Exception {
stompConnectTo("stomp+nio+ssl", null);
}
public void openwireConnectTo(String connectorName, String username, String password) throws Exception {
URI brokerURI = broker.getConnectorByName(connectorName).getConnectUri();
String uri = "ssl://" + brokerURI.getHost() + ":" + brokerURI.getPort();
ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory(uri);
cf.setTrustStore("org/apache/activemq/security" + sep + "broker1.ks");
cf.setTrustStorePassword("password");
cf.setKeyStore("org/apache/activemq/security" + sep + "client.ks");
cf.setKeyStorePassword("password");
ActiveMQConnection connection = null;
if (username != null || password != null) {
connection = (ActiveMQConnection)cf.createConnection(username, password);
} else {
connection = (ActiveMQConnection)cf.createConnection();
}
TestCase.assertNotNull(connection);
connection.start();
connection.stop();
}
@Test
public void testOpenwireSSLWithUsernameAndPassword() throws Exception {
openwireConnectTo("openwire+ssl", "system", "manager");
}
@Test
public void testOpenwireSSLWithCertificate() throws Exception {
openwireConnectTo("openwire+ssl", null, null);
}
@Test
public void testOpenwireNIOSSLWithUsernameAndPassword() throws Exception {
openwireConnectTo("openwire+nio+ssl", "system", "mmanager");
}
@Test
public void testOpenwireNIOSSLWithCertificate() throws Exception {
openwireConnectTo("openwire+nio+ssl", null, null);
}
}

View File

@ -0,0 +1,46 @@
<?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.
-->
<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">
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="broker" id="broker" useJmx="false" persistent="false">
<plugins>
<jaasDualAuthenticationPlugin configuration="activemq-domain" sslConfiguration="activemq-ssl-domain"/>
</plugins>
<sslContext>
<sslContext
keyStore="./src/test/resources/org/apache/activemq/security/broker1.ks" keyStorePassword="password"
trustStore="./src/test/resources/org/apache/activemq/security/client.ks" trustStorePassword="password"/>
</sslContext>
<transportConnectors>
<transportConnector name="stomp+ssl" uri="stomp+ssl://0.0.0.0:0?transport.needClientAuth=true" />
<transportConnector name="stomp+nio+ssl" uri="stomp+nio+ssl://0.0.0.0:0?transport.needClientAuth=true" />
<transportConnector name="openwire+ssl" uri="ssl://0.0.0.0:0?transport.needClientAuth=true" />
<transportConnector name="openwire+nio+ssl" uri="nio+ssl://0.0.0.0:0?transport.needClientAuth=true&amp;transport.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" />
</transportConnectors>
</broker>
</beans>

View File

@ -0,0 +1,17 @@
/**
* 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.
*/
client=CN=client, OU=activemq, O=apache

View File

@ -0,0 +1,18 @@
/**
* 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.
*/
admins=system,client
guests=guest

View File

@ -0,0 +1,30 @@
/**
* 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.
*/
activemq-domain {
org.apache.activemq.jaas.PropertiesLoginModule requisite
debug=true
org.apache.activemq.jaas.properties.user="users.properties"
org.apache.activemq.jaas.properties.group="groups.properties";
};
activemq-ssl-domain {
org.apache.activemq.jaas.TextFileCertificateLoginModule required
debug=true
org.apache.activemq.jaas.textfiledn.user="dns.properties"
org.apache.activemq.jaas.textfiledn.group="groups.properties";
};

View File

@ -0,0 +1,18 @@
/**
* 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.
*/
system=manager
guest=password

View File

@ -17,11 +17,9 @@
package org.apache.activemq.transport.ws;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.concurrent.CountDownLatch;
import org.apache.activemq.command.Command;
import org.apache.activemq.command.ShutdownInfo;
import org.apache.activemq.transport.TransportSupport;
import org.apache.activemq.transport.stomp.ProtocolConverter;
import org.apache.activemq.transport.stomp.Stomp;
@ -113,11 +111,6 @@ class StompSocket extends TransportSupport implements WebSocket.OnTextMessage, S
}
}
@Override
public X509Certificate[] getPeerCertificates() {
return null;
}
@Override
public void sendToActiveMQ(Command command) {
doConsume(command);