You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2012/11/04 22:03:37 UTC

svn commit: r1405636 - in /qpid/trunk/qpid: doc/book/src/java-broker/ java/common/src/main/java/org/apache/qpid/transport/network/io/ java/systests/src/main/java/org/apache/qpid/client/ssl/ java/systests/src/main/java/org/apache/qpid/server/security/au...

Author: robbie
Date: Sun Nov  4 21:03:36 2012
New Revision: 1405636

URL: http://svn.apache.org/viewvc?rev=1405636&view=rev
Log:
QPID-4420: add documentation for SSL and the Anonymous + External AuthenticationManagers along with some general cleanup and expanded testing

Added:
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java
Modified:
    qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-Authentication-Providers.xml
    qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-SSL.xml
    qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
    qpid/trunk/qpid/java/test-profiles/CPPExcludes

Modified: qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-Authentication-Providers.xml
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-Authentication-Providers.xml?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-Authentication-Providers.xml (original)
+++ qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-Authentication-Providers.xml Sun Nov  4 21:03:36 2012
@@ -26,55 +26,22 @@
   <para>
     In order to successfully establish a connection to the Java Broker, the connection must be
     authenticated. The Java Broker supports a number of different authentication schemes, each
-    with its own "authentication manager". Different managers may be used on different ports.
-    Each manager has its own configuration element, the presence of which within the
-    &lt;security&gt; section denotes the use of that authentication provider. Where only one
-    such manager is configured, that manager will be used on all ports (including JMX). Where
-    more than one authentication manager is configured the configuration must define which
-    manager is the "default", and (if required) the mapping of non-default authentication
-    managers to other ports.
-  </para>
-  <para>
-    The following configuration sets up three authentication managers, using a password file as
-    the default (e.g. for the JMX port), Kerberos on port 5672 and Anonymous on 5673.
+    with its own "authentication manager". Each of these are outlined below, along with details
+    of <link linkend="MultipleAuthProviders"> using more than one at a time</link>.
   </para>
 
-  <example>
-    <title>Configuring different authentication schemes on different ports</title>
-    <programlisting><![CDATA[
-<security>
-    <pd-auth-manager>
-	<principal-database>
-	    <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
-	    <attributes>
-		<attribute>
-		    <name>passwordFile</name>
-		    <value>${conf}/passwd</value>
-		</attribute>
-	    </attributes>
-	</principal-database>
-    </pd-auth-manager>
-    <kerberos-auth-manager><auth-name>sib</auth-name></kerberos-auth-manager>
-    <anonymous-auth-manager></anonymous-auth-manager>
-    <default-auth-manager>PrincipalDatabaseAuthenticationManager</default-auth-manager>
-    <port-mappings>
-	<port-mapping>
-	    <port>5672</port>
-	    <auth-manager>KerberosAuthenticationManager</auth-manager>
-	</port-mapping>
-	<port-mapping>
-	    <port>5673</port>
-	    <auth-manager>AnonymousAuthenticationManager</auth-manager>
-	</port-mapping>
-    </port-mappings>
-</security>]]>
-    </programlisting>
-  </example>
+  <section>
+    <title>Password File</title>
+    <para>
+      TODO
+    </para>
 
-  <section><title>Password File</title></section>
-  <section><title>LDAP</title>
+  </section>
+
+  <section>
+  <title>LDAP</title>
   <example>
-    <title>Configuring a LDAP authentication</title>
+    <title>Configuring LDAP authentication</title>
     <programlisting><![CDATA[
 <security>
     <simple-ldap-auth-manager>
@@ -82,8 +49,8 @@
       <search-context>dc=example\,dc=com</search-context>
       <search-filter>(uid={0})</search-filter>
     </simple-ldap-auth-manager>
-</security>]]>
-    </programlisting>
+    ...
+</security>]]></programlisting>
   </example>
 
   <para>
@@ -111,9 +78,10 @@
     By default com.sun.jndi.ldap.LdapCtxFactory is used to create the context, however this can be
     overridden by specifying &lt;ldap-context-factory&gt; in the configuration.
   </para>
-
   </section>
-  <section><title>Kerberos</title>
+
+  <section>
+  <title>Kerberos</title>
 
   <para>
     Kereberos Authentication is configured using the &lt;kerberos-auth-manager&gt; element within
@@ -128,30 +96,30 @@
   </para>
 
   <example>
-    <title>Configuring a Kerberos authentication</title>
+    <title>Configuring Kerberos authentication</title>
     <programlisting><![CDATA[
 <security>
-    <pd-auth-manager>
-	<principal-database>
-	    <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
-	    <attributes>
-		<attribute>
-		    <name>passwordFile</name>
-		    <value>${conf}/passwd</value>
-		</attribute>
-	    </attributes>
-	</principal-database>
-    </pd-auth-manager>
-    <kerberos-auth-manager></kerberos-auth-manager>
-    <default-auth-manager>PrincipalDatabaseAuthenticationManager</default-auth-manager>
-    <port-mappings>
-	<port-mapping>
-	    <port>5672</port>
-	    <auth-manager>KerberosAuthenticationManager</auth-manager>
-	</port-mapping>
-    </port-mappings>
-</security>]]>
-    </programlisting>
+  <pd-auth-manager>
+    <principal-database>
+      <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+      <attributes>
+        <attribute>
+          <name>passwordFile</name>
+          <value>${conf}/passwd</value>
+        </attribute>
+      </attributes>
+    </principal-database>
+  </pd-auth-manager>
+  <kerberos-auth-manager/>
+  <default-auth-manager>PrincipalDatabaseAuthenticationManager</default-auth-manager>
+  <port-mappings>
+    <port-mapping>
+      <port>5672</port>
+      <auth-manager>KerberosAuthenticationManager</auth-manager>
+    </port-mapping>
+  </port-mappings>
+  ...
+</security>]]></programlisting>
   </example>
 
   <para>
@@ -177,8 +145,7 @@ com.sun.security.jgss.accept {
     kdc="kerberos.example.com"
     keyTab="/path/to/keytab-file"
     principal="<name>/<host>";
-};]]>
-  </programlisting>
+};]]></programlisting>
 
   <para>
     Where realm, kdc, keyTab and principal should obviously be set correctly for the environment
@@ -191,7 +158,137 @@ com.sun.security.jgss.accept {
     Jurisdiction Policy Files" appropriate for your JDK in order to get Kerberos support working.
   </para>
   </section>
-  <section><title>SSL Client Certificates</title></section>
-  <section><title>Anonymous</title></section>
+
+  <section id="ExternalAuthManager">
+    <title>External (SSL Client Certificates)</title>
+
+    <para>
+      When <link linkend="SSL-Truststore-ClientCertificate"> requiring SSL Client Certificates</link> be
+      presented the ExternalAuthenticationManager can be used, such that the user is authenticated based on
+      trust of their certificate alone, and the X500Principal from the SSL session is then used as the username
+      for the connection, instead of also requiring the user to present a valid username and password.
+    </para>
+
+    <para>
+      The ExternalAuthenticationManager may be enabled by adding an empty &lt;external-auth-manager&gt; element to
+      the &lt;security&gt; section, as shown below. When referencing it from the default-auth-manager or port-mapping
+      sections, its name is ExternalAuthenticationManager.
+    </para>
+
+    <para>
+      <emphasis role="bold">Note:</emphasis> The ExternalAuthenticationManager should typically only be used on the
+      AMQP ports, in conjunction with <link linkend="SSL-Truststore-ClientCertificate">SSL client certificate
+      authentication</link>. It is not intended for other uses such as the JMX management port and will treat any
+      non-sasl authentication processes on these ports as successfull with the given username. As such you should
+      <link linkend="MultipleAuthProviders">include another Authentication Manager for use on non-AMQP ports</link>,
+      as is done in the example below. Perhaps the only exception to this would be where the broker is embedded in a
+      container that is itself externally protecting the HTTP interface and then providing the remote users name.
+    </para>
+
+    <example>
+      <title>Configuring external authentication (SSL client auth)</title>
+      <programlisting><![CDATA[
+<security>
+  <pd-auth-manager>
+    <principal-database>
+      <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+      <attributes>
+        <attribute>
+          <name>passwordFile</name>
+          <value>${conf}/passwd</value>
+        </attribute>
+      </attributes>
+    </principal-database>
+  </pd-auth-manager>
+  <external-auth-manager/>
+  <default-auth-manager>PrincipalDatabaseAuthenticationManager</default-auth-manager>
+  <port-mappings>
+    <port-mapping>
+      <port>5672</port>
+      <auth-manager>ExternalAuthenticationManager</auth-manager>
+    </port-mapping>
+  </port-mappings>
+  ...
+</security>]]></programlisting>
+    </example>
+
+  </section>
+
+  <section id="AnonymousAuthManager">
+    <title>Anonymous</title>
+
+    <para>
+      The AnonymousAuthenticationManager will allow users to connect with or without credentials and result
+      in their identification on the broker as the user ANONYMOUS. It may be enabled by adding an empty
+      anonymous-auth-manager element to the security configuration section, as shown below.
+    </para>
+
+    <example>
+      <title>Configuring anonymous authentication</title>
+
+      <programlisting><![CDATA[
+<security>
+  <anonymous-auth-manager/>
+  ...
+</security>]]></programlisting>
+    </example>
+
+    <para>
+      When referencing it from the default-auth-manager or port-mapping sections, its name is
+      AnonymousAuthenticationManager.
+    </para>
+  </section>
+
+  <section id="MultipleAuthProviders">
+    <title>Configuring multiple Authentication Providers</title>
+    <para>
+      Different managers may be used on different ports. Each manager has its own configuration element,
+      the presence of which within the &lt;security&gt; section denotes the use of that authentication
+      provider. Where only one such manager is configured, it will be used on all ports (including JMX
+      and HTTP). Where more than one authentication manager is configured the configuration must define
+      which is the "default", and (if required) the mapping of non-default authentication managers to
+      other ports.
+    </para>
+    <para>
+      The following configuration sets up three authentication managers, using a password file as the
+      default (e.g. for the JMX and HTTP ports), Kerberos on port 5672 (the regular AMQP port) and Anonymous
+      on port 5673 (e.g a second AMQP port the broker could have been configured with).
+    </para>
+
+    <example>
+      <title>Configuring multiple (per-port) authentication schemes</title>
+      <programlisting><![CDATA[
+<security>
+  <pd-auth-manager>
+    <principal-database>
+      <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>
+      <attributes>
+        <attribute>
+          <name>passwordFile</name>
+          <value>${conf}/passwd</value>
+        </attribute>
+      </attributes>
+    </principal-database>
+  </pd-auth-manager>
+  <kerberos-auth-manager>
+    <auth-name>sib</auth-name>
+  </kerberos-auth-manager>
+  <anonymous-auth-manager/>
+  <default-auth-manager>PrincipalDatabaseAuthenticationManager</default-auth-manager>
+  <port-mappings>
+    <port-mapping>
+      <port>5672</port>
+        <auth-manager>KerberosAuthenticationManager</auth-manager>
+      </port-mapping>
+    <port-mapping>
+      <port>5673</port>
+        <auth-manager>AnonymousAuthenticationManager</auth-manager>
+    </port-mapping>
+  </port-mappings>
+  ...
+</security>]]></programlisting>
+    </example>
+  </section>
+
 </section>
 

Modified: qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-SSL.xml
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-SSL.xml?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-SSL.xml (original)
+++ qpid/trunk/qpid/doc/book/src/java-broker/Java-Broker-Security-SSL.xml Sun Nov  4 21:03:36 2012
@@ -21,6 +21,85 @@
 -->
 
 <section id="Java-Broker-Security-SSL">
-<title>SSL</title>
+    <title>SSL</title>
 
+    <para>
+        This section will show how to use SSL to enable secure
+        connections between an AMQP message client and the broker.
+    </para>
+    <section role="h2" id="SSL-Keystore">
+        <title>Keystore Configuration</title>
+        <para>
+            The broker configuration file (config.xml) needs to be updated to include the required SSL keystore
+            configuration, an example of which can be found below.
+        </para>
+
+        <example>
+        <title>Configuring an SSL Keystore</title>
+        <programlisting><![CDATA[
+<connector>
+  ...
+  <ssl>
+    <enabled>true</enabled>
+    <port>5671</port>
+    <sslOnly>false</sslOnly>
+    <keyStorePath>/path/to/keystore.ks</keyStorePath>
+    <keyStorePassword>keystorepass</keyStorePassword>
+    <certAlias>alias<certAlias>
+  </ssl>
+  ...
+<connector>]]></programlisting>
+        </example>
+
+        <para>
+            The certAlias element is an optional way of specifying which certificate the broker should use
+            if the keystore contains multiple entries.
+        </para>
+
+        <para>
+            The sslOnly element controls whether the broker will <emphasis role="bold">only</emphasis> bind
+            the configured SSL port(s) or will also bind the non-SSL port(s). Setting sslOnly to true will
+            disable the non-SSL ports.
+        </para>
+    </section>
+
+    <section role="h2" id="SSL-Truststore-ClientCertificate">
+        <title>Truststore / Client Certificate Authentication</title>
+        <para>
+            The SSL trustore and related Client Certificate Authentication behaviour can be configured with
+            additional configuration as shown in the example below, in which the broker requires client
+            certificate authentication.
+        </para>
+
+        <example>
+        <title>Configuring an SSL Truststore and client auth</title>
+        <programlisting><![CDATA[
+<connector>
+  ...
+  <ssl>
+    ...
+    <trustStorePath>/path/to/truststore.ks</trustStorePath>
+    <trustStorePassword>truststorepass</trustStorePassword>
+    <needClientAuth>true</needClientAuth>
+    <wantClientAuth>false</wantClientAuth>
+    ...
+  </ssl>
+  ...
+<connector>]]></programlisting>
+        </example>
+
+        <para>
+            The needClientAuth and wantClientAuth elements allow control of whether the client must present an
+            SSL certificate. Only one of these elements is needed but both may be used at the same time.
+            A socket's client authentication setting is one of three states: required (needClientAuth = true),
+            requested (wantClientAuth = true), or none desired (both false, the default). If both elements are
+            set to true, needClientAuth takes precedence.
+        </para>
+
+        <para>
+            When using Client Certificate Authentication it may be desirable to use the External Authentication
+            Manager, for details see <xref linkend="ExternalAuthManager"></xref>
+        </para>
+
+    </section>
 </section>

Modified: qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java (original)
+++ qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java Sun Nov  4 21:03:36 2012
@@ -130,7 +130,6 @@ public class IoNetworkTransport implemen
 
     public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext)
     {
-
         try
         {
             _acceptor = new AcceptingThread(config, factory, sslContext);
@@ -141,8 +140,6 @@ public class IoNetworkTransport implemen
         {
             throw new TransportException("Unable to start server socket", e);
         }
-
-
     }
 
     private class AcceptingThread extends Thread
@@ -155,8 +152,7 @@ public class IoNetworkTransport implemen
 
         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 implemen
             {
                 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 implemen
                         socket.setSendBufferSize(sendBufferSize);
                         socket.setReceiveBufferSize(receiveBufferSize);
 
-
                         ProtocolEngine engine = _factory.newProtocolEngine();
 
                         NetworkConnection connection = new IoNetworkConnection(socket, engine, sendBufferSize, receiveBufferSize, TIMEOUT);

Modified: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java (original)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java Sun Nov  4 21:03:36 2012
@@ -25,11 +25,13 @@ import static org.apache.qpid.test.utils
 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 QpidBrokerT
     @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 QpidBrokerT
             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 QpidBrokerT
 
     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 QpidBrokerT
         }        
     }
     
-    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 QpidBrokerT
             }
             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 QpidBrokerT
     
     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 QpidBrokerT
 
     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 QpidBrokerT
             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);
+    }
 }

Added: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java?rev=1405636&view=auto
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java (added)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java Sun Nov  4 21:03:36 2012
@@ -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");
+    }
+}

Modified: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java (original)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java Sun Nov  4 21:03:36 2012
@@ -129,6 +129,7 @@ public class QpidBrokerTestCase extends 
     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 
         _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 
         _messageSize = byteSize;
     }
 
-    public ConnectionURL getConnectionURL() throws NamingException
-    {
-        return getConnectionFactory().getConnectionURL();
-    }
-
     public BrokerDetails getBroker()
     {
         try

Modified: qpid/trunk/qpid/java/test-profiles/CPPExcludes
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/test-profiles/CPPExcludes?rev=1405636&r1=1405635&r2=1405636&view=diff
==============================================================================
--- qpid/trunk/qpid/java/test-profiles/CPPExcludes (original)
+++ qpid/trunk/qpid/java/test-profiles/CPPExcludes Sun Nov  4 21:03:36 2012
@@ -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



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org