summaryrefslogtreecommitdiff
path: root/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java')
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java485
1 files changed, 485 insertions, 0 deletions
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
new file mode 100644
index 0000000000..eb61e5a084
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
@@ -0,0 +1,485 @@
+/*
+ *
+ * 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.client.ssl;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
+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 java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.AMQTestConnection_0_10;
+import org.apache.qpid.jms.ConnectionURL;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SSLTest extends QpidBrokerTestCase
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(SSLTest.class);
+
+ private static final String CERT_ALIAS_APP1 = "app1";
+ private static final String CERT_ALIAS_APP2 = "app2";
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+
+ 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 (shouldPerformTest())
+ {
+ clearSslStoreSystemProperties();
+
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" +
+ "?ssl='true'" +
+ "&key_store='%s'&key_store_password='%s'" +
+ "&trust_store='%s'&trust_store_password='%s'" +
+ "'";
+
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,
+ KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+ }
+ }
+
+ public void testHostVerificationIsOnByDefault() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ clearSslStoreSystemProperties();
+
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" +
+ "?ssl='true'" +
+ "&key_store='%s'&key_store_password='%s'" +
+ "&trust_store='%s'&trust_store_password='%s'" +
+ "'";
+
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,
+ KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD);
+
+ try
+ {
+ getConnection(new AMQConnectionURL(url));
+ }
+ catch(JMSException e)
+ {
+ assertTrue("Unexpected exception message", e.getMessage().contains("SSL hostname verification failed"));
+ }
+
+ url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" +
+ "?ssl='true'&ssl_verify_hostname='false'" +
+ "&key_store='%s'&key_store_password='%s'" +
+ "&trust_store='%s'&trust_store_password='%s'" +
+ "'";
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,
+ KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+ }
+ }
+
+ /**
+ * Create an SSL connection using the SSL system properties for the trust and key store, but using
+ * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level,
+ * without specifying anything at the {@link ConnectionURL#OPTIONS_BROKERLIST} level.
+ */
+ public void testSslConnectionOption() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ //Create URL enabling SSL at the connection rather than brokerlist level
+ String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s'";
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+ }
+ }
+
+ /**
+ * Create an SSL connection using the SSL system properties for the trust and key store, but using
+ * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level,
+ * overriding the false setting at the {@link ConnectionURL#OPTIONS_BROKERLIST} level.
+ */
+ public void testSslConnectionOptionOverridesBrokerlistOption() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ //Create URL enabling SSL at the connection, overriding the false at the brokerlist level
+ String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s?ssl='false''";
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ 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 (shouldPerformTest())
+ {
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s?ssl='true''";
+
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+ }
+ }
+
+ public void testMultipleCertsInSingleStore() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ QpidBrokerTestCase.DEFAULT_SSL_PORT +
+ "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP1 + "''";
+
+ AMQTestConnection_0_10 con = new AMQTestConnection_0_10(url);
+ org.apache.qpid.transport.Connection transportCon = con.getConnection();
+ String userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app1@acme.org",userID);
+ con.close();
+
+ url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ QpidBrokerTestCase.DEFAULT_SSL_PORT +
+ "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP2 + "''";
+
+ con = new AMQTestConnection_0_10(url);
+ transportCon = con.getConnection();
+ userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app2@acme.org",userID);
+ con.close();
+ }
+ }
+
+ public void testVerifyHostNameWithIncorrectHostname() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ //Start the broker (WANTing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, false, true, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:" +
+ QpidBrokerTestCase.DEFAULT_SSL_PORT +
+ "?ssl='true''";
+
+ try
+ {
+ getConnection(new AMQConnectionURL(url));
+ fail("Hostname verification failed. No exception was thrown");
+ }
+ catch (Exception e)
+ {
+ verifyExceptionCausesContains(e, "SSL hostname verification failed");
+ }
+ }
+ }
+
+ private void verifyExceptionCausesContains(Exception e, String expectedString)
+ {
+ LOGGER.debug("verifying that the following exception contains " + expectedString, e);
+ 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 (shouldPerformTest())
+ {
+ //Start the broker (WANTing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, false, true, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ QpidBrokerTestCase.DEFAULT_SSL_PORT +
+ "?ssl='true''";
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should have been created", con);
+ }
+ }
+
+ public void testVerifyLocalHostLocalDomain() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ //Start the broker (WANTing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, false, true, false);
+ super.setUp();
+
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost.localdomain:" +
+ QpidBrokerTestCase.DEFAULT_SSL_PORT +
+ "?ssl='true''";
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should have been created", con);
+ }
+ }
+
+ public void testCreateSSLConnectionUsingConnectionURLParamsTrustStoreOnly() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ clearSslStoreSystemProperties();
+
+ //Start the broker (WANTing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, false, true, false);
+ 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);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ 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, false);
+ 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:");
+ }
+ }
+ }
+ }
+
+ /**
+ * Test running TLS and unencrypted on the same port works and both TLS and non-TLS connections can be established
+ *
+ */
+ public void testCreateSSLandTCPonSamePort() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ clearSslStoreSystemProperties();
+
+ //Start the broker (NEEDing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, false, false, false, true);
+ 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'" +
+ "&trust_store='%s'&trust_store_password='%s'" +
+ "'";
+
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,
+ KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD);
+
+ Connection con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+
+ url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s'";
+
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT);
+
+ con = getConnection(new AMQConnectionURL(url));
+ assertNotNull("connection should be successful", con);
+ ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+
+ }
+ }
+
+
+ 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,
+ boolean samePort) throws Exception
+ {
+ if(isJavaBroker())
+ {
+ Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
+ sslPortAttributes.put(Port.TRANSPORTS, samePort ? Arrays.asList(Transport.SSL, Transport.TCP)
+ : Collections.singleton(Transport.SSL));
+ sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ sslPortAttributes.put(Port.NEED_CLIENT_AUTH, needClientAuth);
+ sslPortAttributes.put(Port.WANT_CLIENT_AUTH, wantClientAuth);
+ sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
+ getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes);
+ }
+ }
+
+ 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);
+ }
+}