diff options
| author | Robert Gemmell <robbie@apache.org> | 2012-11-04 21:03:36 +0000 |
|---|---|---|
| committer | Robert Gemmell <robbie@apache.org> | 2012-11-04 21:03:36 +0000 |
| commit | bb9160e892017cd58a14b9eb0ebd282e787229d5 (patch) | |
| tree | f25ded28c3ada1f6611efc49addc2d56cd93cfd0 /qpid/java | |
| parent | b8ea27b54e0dc0e5ebf8d7a17e6cc68e5307a422 (diff) | |
| download | qpid-python-bb9160e892017cd58a14b9eb0ebd282e787229d5.tar.gz | |
QPID-4420: add documentation for SSL and the Anonymous + External AuthenticationManagers along with some general cleanup and expanded testing
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1405636 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
5 files changed, 356 insertions, 54 deletions
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java index 9b6f0a0b1b..f2bfc14b47 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java @@ -130,7 +130,6 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext) { - try { _acceptor = new AcceptingThread(config, factory, sslContext); @@ -141,8 +140,6 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet { throw new TransportException("Unable to start server socket", e); } - - } private class AcceptingThread extends Thread @@ -155,8 +152,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet private AcceptingThread(NetworkTransportConfiguration config, ProtocolEngineFactory factory, - SSLContext sslContext) - throws IOException + SSLContext sslContext) throws IOException { _config = config; _factory = factory; @@ -172,15 +168,19 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet { SSLServerSocketFactory socketFactory = _sslContext.getServerSocketFactory(); _serverSocket = socketFactory.createServerSocket(); - ((SSLServerSocket)_serverSocket).setNeedClientAuth(config.needClientAuth()); - ((SSLServerSocket)_serverSocket).setWantClientAuth(config.wantClientAuth()); + if(config.needClientAuth()) + { + ((SSLServerSocket)_serverSocket).setNeedClientAuth(true); + } + else if(config.wantClientAuth()) + { + ((SSLServerSocket)_serverSocket).setWantClientAuth(true); + } } _serverSocket.setReuseAddress(true); _serverSocket.bind(address); - - } @@ -224,7 +224,6 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet socket.setSendBufferSize(sendBufferSize); socket.setReceiveBufferSize(receiveBufferSize); - ProtocolEngine engine = _factory.newProtocolEngine(); NetworkConnection connection = new IoNetworkConnection(socket, engine, sendBufferSize, receiveBufferSize, TIMEOUT); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java index ee8855dc6c..4f341e3c60 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java @@ -25,11 +25,13 @@ import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; +import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.client.AMQConnectionURL; import org.apache.qpid.client.AMQTestConnection_0_10; import org.apache.qpid.test.utils.QpidBrokerTestCase; import javax.jms.Connection; +import javax.jms.JMSException; import javax.jms.Session; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -42,33 +44,24 @@ public class SSLTest extends QpidBrokerTestCase @Override protected void setUp() throws Exception { - if(isJavaBroker()) - { - setTestClientSystemProperty("profile.use_ssl", "true"); - setConfigurationProperty("connector.ssl.enabled", "true"); - setConfigurationProperty("connector.ssl.sslOnly", "true"); - setConfigurationProperty("connector.ssl.wantClientAuth", "true"); - } - - // set the ssl system properties - setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); + + setSslStoreSystemProperties(); + + //We dont call super.setUp, the tests start the broker after deciding + //whether to run and then configuring it appropriately } public void testCreateSSLConnectionUsingConnectionURLParams() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { - // Clear the ssl system properties - setSystemProperty("javax.net.ssl.keyStore", null); - setSystemProperty("javax.net.ssl.keyStorePassword", null); - setSystemProperty("javax.net.ssl.trustStore", null); - setSystemProperty("javax.net.ssl.trustStorePassword", null); + clearSslStoreSystemProperties(); + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + "?ssl='true'&ssl_verify_hostname='true'" + "&key_store='%s'&key_store_password='%s'" + @@ -82,13 +75,16 @@ public class SSLTest extends QpidBrokerTestCase assertNotNull("connection should be successful", con); Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); assertNotNull("create session should be successful", ssn); - } + } } public void testCreateSSLConnectionUsingSystemProperties() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false); + super.setUp(); String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s?ssl='true''"; @@ -103,8 +99,12 @@ public class SSLTest extends QpidBrokerTestCase public void testMultipleCertsInSingleStore() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + QpidBrokerTestCase.DEFAULT_SSL_PORT + "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP1 + "''"; @@ -127,10 +127,14 @@ public class SSLTest extends QpidBrokerTestCase } } - public void testVerifyHostNameWithIncorrectHostname() + public void testVerifyHostNameWithIncorrectHostname() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:" + QpidBrokerTestCase.DEFAULT_SSL_PORT + "?ssl='true'&ssl_verify_hostname='true''"; @@ -142,19 +146,27 @@ public class SSLTest extends QpidBrokerTestCase } catch (Exception e) { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - e.printStackTrace(new PrintStream(bout)); - String strace = bout.toString(); - assertTrue("Correct exception not thrown",strace.contains("SSL hostname verification failed")); + verifyExceptionCausesContains(e, "SSL hostname verification failed"); } - } } + + private void verifyExceptionCausesContains(Exception e, String expectedString) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bout)); + String strace = bout.toString(); + assertTrue("Correct exception not thrown", strace.contains(expectedString)); + } public void testVerifyLocalHost() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + QpidBrokerTestCase.DEFAULT_SSL_PORT + "?ssl='true'&ssl_verify_hostname='true''"; @@ -166,8 +178,12 @@ public class SSLTest extends QpidBrokerTestCase public void testVerifyLocalHostLocalDomain() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost.localdomain:" + QpidBrokerTestCase.DEFAULT_SSL_PORT + "?ssl='true'&ssl_verify_hostname='true''"; @@ -179,13 +195,14 @@ public class SSLTest extends QpidBrokerTestCase public void testCreateSSLConnectionUsingConnectionURLParamsTrustStoreOnly() throws Exception { - if (Boolean.getBoolean("profile.use_ssl")) + if (shouldPerformTest()) { - // Clear the ssl system properties - setSystemProperty("javax.net.ssl.keyStore", null); - setSystemProperty("javax.net.ssl.keyStorePassword", null); - setSystemProperty("javax.net.ssl.trustStore", null); - setSystemProperty("javax.net.ssl.trustStorePassword", null); + clearSslStoreSystemProperties(); + + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true); + super.setUp(); + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + "?ssl='true'&ssl_verify_hostname='true'" + @@ -200,4 +217,120 @@ public class SSLTest extends QpidBrokerTestCase assertNotNull("create session should be successful", ssn); } } + + /** + * Verifies that when the broker is configured to NEED client certificates, + * a client which doesn't supply one fails to connect. + */ + public void testClientCertMissingWhilstNeeding() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(true, false, false); + } + + /** + * Verifies that when the broker is configured to WANT client certificates, + * a client which doesn't supply one succeeds in connecting. + */ + public void testClientCertMissingWhilstWanting() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(false, true, true); + } + + /** + * Verifies that when the broker is configured to WANT and NEED client certificates + * that a client which doesn't supply one fails to connect. + */ + public void testClientCertMissingWhilstWantingAndNeeding() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(true, true, false); + } + + private void missingClientCertWhileNeedingOrWantingTestImpl(boolean needClientCerts, + boolean wantClientCerts, boolean shouldSucceed) throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker + configureJavaBrokerIfNecessary(true, true, needClientCerts, wantClientCerts); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + + "?ssl='true'&trust_store='%s'&trust_store_password='%s''"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,TRUSTSTORE,TRUSTSTORE_PASSWORD); + try + { + Connection con = getConnection(new AMQConnectionURL(url)); + if(!shouldSucceed) + { + fail("Connection succeeded, expected exception was not thrown"); + } + else + { + //Use the connection to verify it works + con.createSession(true, Session.SESSION_TRANSACTED); + } + } + catch(JMSException e) + { + if(shouldSucceed) + { + _logger.error("Caught unexpected exception",e); + fail("Connection failed, unexpected exception thrown"); + } + else + { + //expected + verifyExceptionCausesContains(e, "Caused by: javax.net.ssl.SSLException:"); + } + } + } + } + + private boolean shouldPerformTest() + { + // We run the SSL tests on all the Java broker profiles + if(isJavaBroker()) + { + setTestClientSystemProperty(PROFILE_USE_SSL, "true"); + } + + return Boolean.getBoolean(PROFILE_USE_SSL); + } + + private void configureJavaBrokerIfNecessary(boolean sslEnabled, boolean sslOnly, boolean needClientAuth, boolean wantClientAuth) throws ConfigurationException + { + if(isJavaBroker()) + { + setConfigurationProperty("connector.ssl.enabled", String.valueOf(sslEnabled)); + setConfigurationProperty("connector.ssl.sslOnly", String.valueOf(sslOnly)); + setConfigurationProperty("connector.ssl.needClientAuth", String.valueOf(needClientAuth)); + setConfigurationProperty("connector.ssl.wantClientAuth", String.valueOf(wantClientAuth)); + + if(needClientAuth || wantClientAuth) + { + //TODO: make a broker trust store? + setConfigurationProperty("connector.ssl.trustStorePath", TRUSTSTORE); + setConfigurationProperty("connector.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } + } + } + + private void setSslStoreSystemProperties() + { + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } + + private void clearSslStoreSystemProperties() + { + setSystemProperty("javax.net.ssl.keyStore", null); + setSystemProperty("javax.net.ssl.keyStorePassword", null); + setSystemProperty("javax.net.ssl.trustStore", null); + setSystemProperty("javax.net.ssl.trustStorePassword", null); + } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java new file mode 100644 index 0000000000..295aac9f97 --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java @@ -0,0 +1,171 @@ +/* + * 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.qpid.server.security.auth.manager; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ExternalAuthenticationTest extends QpidBrokerTestCase +{ + private static final String EXTERNAL_AUTH_MANAGER = ExternalAuthenticationManager.class.getSimpleName(); + private static final String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks"; + private static final String KEYSTORE_PASSWORD = "password"; + private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks"; + private static final String TRUSTSTORE_PASSWORD = "password"; + + @Override + protected void setUp() throws Exception + { + // not calling super.setUp() to avoid broker start-up + } + + /** + * Tests that when EXTERNAL authentication is used on the SSL port, clients presenting certificates are able to connect. + * Also, checks that default authentication manager PrincipalDatabaseAuthenticationManager is used on non SSL port. + */ + public void testExternalAuthenticationManagerOnSSLPort() throws Exception + { + setCommonBrokerSSLProperties(true); + setConfigurationProperty("security.port-mappings.port-mapping.port", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT)); + setConfigurationProperty("security.port-mappings.port-mapping.auth-manager", EXTERNAL_AUTH_MANAGER); + setConfigurationProperty("security.default-auth-manager", PrincipalDatabaseAuthenticationManager.class.getSimpleName()); + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + try + { + getConnection(); + } + catch (JMSException e) + { + fail("Should be able to create a connection with credentials to the standard port: " + e.getMessage()); + } + + } + + /** + * Tests that when EXTERNAL authentication manager is set as the default, clients presenting certificates are able to connect. + * Also, checks a client with valid username and password but not using ssl is unable to connect to the non SSL port. + */ + public void testExternalAuthenticationManagerAsDefault() throws Exception + { + setCommonBrokerSSLProperties(true); + setConfigurationProperty("security.default-auth-manager", EXTERNAL_AUTH_MANAGER); + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getConnection(); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + + try + { + getExternalSSLConnection(false); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port. " + e.getMessage()); + } + } + + /** + * Tests that when EXTERNAL authentication manager is set as the default, clients without certificates are unable to connect to the SSL port + * even with valid username and password. + */ + public void testExternalAuthenticationManagerWithoutClientKeyStore() throws Exception + { + setCommonBrokerSSLProperties(false); + setConfigurationProperty("security.default-auth-manager", EXTERNAL_AUTH_MANAGER); + super.setUp(); + + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(true); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + } + + private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception + { + String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL''"; + if (includeUserNameAndPassword) + { + url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT)); + } + else + { + url = String.format(url, ":", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT)); + } + return getConnection(new AMQConnectionURL(url)); + } + + private void setCommonBrokerSSLProperties(boolean needClientAuth) throws ConfigurationException + { + setConfigurationProperty("connector.ssl.enabled", "true"); + setConfigurationProperty("connector.ssl.sslOnly", "false"); + setConfigurationProperty("connector.ssl.trustStorePath", TRUSTSTORE); + setConfigurationProperty("connector.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + setConfigurationProperty("connector.ssl.needClientAuth", String.valueOf(needClientAuth)); + setConfigurationProperty("security.external-auth-manager", ""); + } + + private void setClientKeystoreProperties() + { + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + } + + private void setClientTrustoreProperties() + { + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + setSystemProperty("javax.net.debug", "ssl"); + } +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java index 4da3baaf73..b9f3bd7c23 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java @@ -129,6 +129,7 @@ public class QpidBrokerTestCase extends QpidTestCase private static final String BROKER_PERSITENT = "broker.persistent"; public static final String BROKER_PROTOCOL_EXCLUDES = "broker.protocol.excludes"; public static final String BROKER_PROTOCOL_INCLUDES = "broker.protocol.includes"; + public static final String PROFILE_USE_SSL = "profile.use_ssl"; // values protected static final String JAVA = "java"; @@ -1066,7 +1067,7 @@ public class QpidBrokerTestCase extends QpidTestCase _logger.info("get ConnectionFactory"); if (_connectionFactory == null) { - if (Boolean.getBoolean("profile.use_ssl")) + if (Boolean.getBoolean(PROFILE_USE_SSL)) { _connectionFactory = getConnectionFactory("default.ssl"); } @@ -1356,11 +1357,6 @@ public class QpidBrokerTestCase extends QpidTestCase _messageSize = byteSize; } - public ConnectionURL getConnectionURL() throws NamingException - { - return getConnectionFactory().getConnectionURL(); - } - public BrokerDetails getBroker() { try diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index f15673da02..fa3a2bc262 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -178,3 +178,6 @@ org.apache.qpid.systest.rest.acl.* // Exclude failover tests requiring virtual host functionality org.apache.qpid.client.failover.MultipleBrokersFailoverTest#* + +// Uses Java broker specific configuration +org.apache.qpid.client.ssl.SSLTest#testClientCertMissingWhilstWanting |
