https://issues.apache.org/jira/browse/AMQ-4298 Add mutual authentication (needClientAuth) to https transport added tests as well

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1445299 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Christian Posta 2013-02-12 18:27:53 +00:00
parent cd5e1f3d99
commit 571d452053
9 changed files with 379 additions and 6 deletions

View File

@ -31,6 +31,10 @@ public class SecureSocketConnectorFactory extends SocketConnectorFactory {
private String keyPassword = System.getProperty("javax.net.ssl.keyPassword");
private String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
private String keyStore = System.getProperty("javax.net.ssl.keyStore");
private String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
private String trustStore = System.getProperty("javax.net.ssl.trustStore");
private boolean needClientAuth;
private boolean wantClientAuth;
private String keyStoreType;
private String secureRandomCertficateAlgorithm;
private String trustCertificateAlgorithm;
@ -94,8 +98,18 @@ public class SecureSocketConnectorFactory extends SocketConnectorFactory {
if (protocol != null) {
factory.setProtocol(protocol);
}
if (trustStore != null) {
factory.setTrustStore(trustStore);
}
if (trustStorePassword != null) {
factory.setTrustStorePassword(trustStorePassword);
}
}
factory.setNeedClientAuth(needClientAuth);
factory.setWantClientAuth(wantClientAuth);
return sslConnector;
}
@ -179,4 +193,36 @@ public class SecureSocketConnectorFactory extends SocketConnectorFactory {
public void setAuth(String auth) {
this.auth = auth;
}
public boolean isWantClientAuth() {
return wantClientAuth;
}
public void setWantClientAuth(boolean wantClientAuth) {
this.wantClientAuth = wantClientAuth;
}
public boolean isNeedClientAuth() {
return needClientAuth;
}
public void setNeedClientAuth(boolean needClientAuth) {
this.needClientAuth = needClientAuth;
}
public String getTrustStore() {
return trustStore;
}
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}
public String getTrustStorePassword() {
return trustStorePassword;
}
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}
}

View File

@ -45,6 +45,7 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.BasicResponseHandler;
@ -80,7 +81,7 @@ public class HttpClientTransport extends HttpTransportSupport {
private int soTimeout = MAX_CLIENT_TIMEOUT;
private boolean useCompression = false;
private boolean canSendCompressed = false;
protected boolean canSendCompressed = false;
private int minSendAsCompressedSize = 0;
public HttpClientTransport(TextWireFormat wireFormat, URI remoteUrl) {
@ -285,7 +286,7 @@ public class HttpClientTransport extends HttpTransportSupport {
}
protected HttpClient createHttpClient() {
DefaultHttpClient client = new DefaultHttpClient(new PoolingClientConnectionManager());
DefaultHttpClient client = new DefaultHttpClient(createClientConnectionManager());
if (useCompression) {
client.addRequestInterceptor( new HttpRequestInterceptor() {
@Override
@ -308,6 +309,10 @@ public class HttpClientTransport extends HttpTransportSupport {
return client;
}
protected ClientConnectionManager createClientConnectionManager() {
return new PoolingClientConnectionManager();
}
protected void configureMethod(AbstractHttpMessage method) {
method.setHeader("clientID", clientID);
}

View File

@ -17,14 +17,46 @@
*/
package org.apache.activemq.transport.https;
import java.net.URI;
import org.apache.activemq.transport.http.HttpClientTransport;
import org.apache.activemq.transport.util.TextWireFormat;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
import java.security.KeyStore;
public class HttpsClientTransport extends HttpClientTransport {
public HttpsClientTransport(TextWireFormat wireFormat, URI remoteUrl) {
super(wireFormat, remoteUrl);
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(createSchemeRegistry());
return connectionManager;
}
private SchemeRegistry createSchemeRegistry() {
SchemeRegistry schemeRegistry = new SchemeRegistry();
try {
// register the default socket factory so that it looks at the javax.net.ssl.keyStore,
// javax.net.ssl.trustStore, etc, properties by default
SSLSocketFactory sslSocketFactory =
new SSLSocketFactory((javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
schemeRegistry.register(new Scheme("https", getRemoteUrl().getPort(), sslSocketFactory));
return schemeRegistry;
} catch (Exception e) {
throw new IllegalStateException("Failure trying to create scheme registry", e);
}
}
}

View File

@ -0,0 +1,62 @@
/**
* 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.https;
import junit.framework.Test;
import junit.textui.TestRunner;
import org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.transport.http.HttpTransportBrokerTest;
import java.net.URI;
/**
* @author <a href="http://www.christianposta.com/blog">Christian Posta</a>
*/
public class HttpsNeedClientAuthBrokerTest extends HttpTransportBrokerTest {
private static final String HTTPS_TRANSPORT_URL = "https://localhost:8161?transport.needClientAuth=true";
protected String getBindLocation() {
return "https://localhost:8161";
}
protected void setUp() throws Exception {
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");
super.setUp();
}
@Override
protected BrokerService createBroker() throws Exception {
BrokerService broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false&useJmx=false"));
connector = broker.addConnector(HTTPS_TRANSPORT_URL);
return broker;
}
public static Test suite() {
return suite(HttpsNeedClientAuthBrokerTest.class);
}
public static void main(String[] args) {
TestRunner.run(suite());
}
}

View File

@ -0,0 +1,70 @@
/**
* 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.https;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.JmsTopicSendReceiveTest;
import org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
/**
* @author <a href="http://www.christianposta.com/blog">Christian Posta</a>
*/
public class HttpsNeedClientAuthSendAndReceiveTest extends JmsTopicSendReceiveTest {
public static final String KEYSTORE_TYPE = "jks";
public static final String PASSWORD = "password";
public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore";
public static final String KEYSTORE = "src/test/resources/server.keystore";
private BrokerService broker;
// set up broker with https first...
@Override
protected void setUp() throws Exception {
broker = BrokerFactory.createBroker("xbean:activemq-https-need-client-auth.xml");
broker.setPersistent(false);
broker.start();
broker.waitUntilStarted();
// these are used for the client side... for the server side, the SSL context
// will be configured through the <sslContext> spring beans
System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE);
System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);
System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE);
System.setProperty("javax.net.ssl.keyStore", KEYSTORE);
System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD);
System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE);
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
if (broker != null) {
broker.stop();
}
}
@Override
protected ActiveMQConnectionFactory createConnectionFactory() throws Exception {
return new ActiveMQConnectionFactory("https://localhost:8161");
}
}

View File

@ -0,0 +1,70 @@
/**
* 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.https;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.JmsTopicSendReceiveTest;
import org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
/**
* @author <a href="http://www.christianposta.com/blog">Christian Posta</a>
*/
public class HttpsWantClientAuthSendAndReceiveTest extends JmsTopicSendReceiveTest {
public static final String KEYSTORE_TYPE = "jks";
public static final String PASSWORD = "password";
public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore";
public static final String KEYSTORE = "src/test/resources/server.keystore";
private BrokerService broker;
// set up broker with https first...
@Override
protected void setUp() throws Exception {
broker = BrokerFactory.createBroker("xbean:activemq-https-want-client-auth.xml");
broker.setPersistent(false);
broker.start();
broker.waitUntilStarted();
// these are used for the client side... for the server side, the SSL context
// will be configured through the <sslContext> spring beans
System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE);
System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);
System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE);
// System.setProperty("javax.net.ssl.keyStore", KEYSTORE);
// System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD);
// System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE);
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
if (broker != null) {
broker.stop();
}
}
@Override
protected ActiveMQConnectionFactory createConnectionFactory() throws Exception {
return new ActiveMQConnectionFactory("https://localhost:8161");
}
}

View File

@ -0,0 +1,41 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:amq="http://activemq.apache.org/schema/core"
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.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<amq:broker brokerName="localhost" useJmx="false">
<amq:sslContext>
<amq:sslContext keyStorePassword="password"
keyStore="src/test/resources/server.keystore"
trustStore="src/test/resources/client.keystore"
trustStorePassword="password" />
</amq:sslContext>
<amq:transportConnectors>
<amq:transportConnector name="https"
uri="https://localhost:8161?transport.needClientAuth=true" />
</amq:transportConnectors>
</amq:broker>
</beans>

View File

@ -0,0 +1,41 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:amq="http://activemq.apache.org/schema/core"
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.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<amq:broker brokerName="localhost" useJmx="false">
<amq:sslContext>
<amq:sslContext keyStorePassword="password"
keyStore="src/test/resources/server.keystore"
trustStore="src/test/resources/client.keystore"
trustStorePassword="password" />
</amq:sslContext>
<amq:transportConnectors>
<amq:transportConnector name="https"
uri="https://localhost:8161?transport.wantClientAuth=true" />
</amq:transportConnectors>
</amq:broker>
</beans>

View File

@ -80,7 +80,7 @@ public class SslBrokerServiceTest extends TransportBrokerTestSupport {
return service;
}
public void testNeedClientAuth() throws Exception {
public void testNeedClientAuthReject() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
// no client cert
context.init(null, getTrustManager(), null);
@ -94,6 +94,12 @@ public class SslBrokerServiceTest extends TransportBrokerTestSupport {
// should work with regular connector
makeSSLConnection(context, null, connector);
}
public void testNeedClientAuthSucceed() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
context.init(getKeyManager(), getTrustManager(), null);
makeSSLConnection(context, null, needClientAuthConnector);
}
public void testCipherSuitesDisabled() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");