316382: support a more strict SSL option with certificates 

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/sandbox/trunk@2776 7e9141cc-0065-0410-87d8-b60c137991c4
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java
index 5bf5fc9..207f6f6 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java
@@ -716,7 +716,7 @@
     /* ------------------------------------------------------------ */
     public void setKeyStorePassword(String keyStorePassword)
     {
-        _sslContextFactory.setKeyStorePassword(keyStorePassword);
+        _sslContextFactory.setKeystorePassword(keyStorePassword);
     }
 
     /* ------------------------------------------------------------ */
@@ -728,7 +728,7 @@
     /* ------------------------------------------------------------ */
     public void setTrustStorePassword(String trustStorePassword)
     {
-        _sslContextFactory.setTrustStorePassword(trustStorePassword);
+        _sslContextFactory.setTruststorePassword(trustStorePassword);
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
index 1508157..7b9af6b 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
@@ -173,7 +173,7 @@
      */
     public void setPassword(String password)
     {
-        _sslContextFactory.setKeyStorePassword(password);
+        _sslContextFactory.setKeystorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -182,7 +182,7 @@
      */
     public void setTrustPassword(String password)
     {
-        _sslContextFactory.setTrustStorePassword(password);
+        _sslContextFactory.setTruststorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -488,7 +488,17 @@
         SSLEngine engine = null;
         try
         {
+            engine = _sslContextFactory.getSslContext().createSSLEngine();
+            engine.setUseClientMode(false);
 
+            if (_sslContextFactory.getWantClientAuth())
+                engine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
+            if (_sslContextFactory.getWantClientAuth())
+                engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
+
+            engine.setEnabledCipherSuites(
+                    _sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(),
+                                                          engine.getSupportedCipherSuites()));
         }
         catch (Exception e)
         {
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
index b826344..a27929e 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
@@ -286,8 +286,10 @@
                         factory.createServerSocket(port,backlog):
                         factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
 
-        socket.setWantClientAuth(_sslContextFactory.getWantClientAuth());
-        socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
+        if (_sslContextFactory.getWantClientAuth())
+            socket.setWantClientAuth(_sslContextFactory.getWantClientAuth());
+        if (_sslContextFactory.getNeedClientAuth())
+            socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
 
         socket.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
                                             socket.getEnabledCipherSuites(),
@@ -345,13 +347,13 @@
     /* ------------------------------------------------------------ */
     public void setPassword(String password)
     {
-        _sslContextFactory.setKeyStorePassword(password);
+        _sslContextFactory.setKeystorePassword(password);
     }
     
     /* ------------------------------------------------------------ */
     public void setTrustPassword(String password)
     {
-        _sslContextFactory.setTrustStorePassword(password);
+        _sslContextFactory.setTruststorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java b/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
index 6c1bcb5..4092637 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
@@ -19,7 +19,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.SecureRandom;
@@ -469,7 +468,7 @@
      * @param password
      *            The password for the key store
      */
-    public SslContextFactory setKeyStorePassword(String password)
+    public SslContextFactory setKeystorePassword(String password)
     {
         _keystorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
         
@@ -493,7 +492,7 @@
      * @param password
      *            The password for the trust store
      */
-    public SslContextFactory setTrustStorePassword(String password)
+    public SslContextFactory setTruststorePassword(String password)
     {
         _truststorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
         
@@ -749,6 +748,8 @@
     /* ------------------------------------------------------------ */
     public SSLContext createSSLContext() throws Exception
     {
+        // verify that keystore and truststore 
+        // parameters are set up correctly  
         checkConfig();
         
         KeyStore keyStore = getKeyStore(_keystoreInputStream, _keystorePath, _keystoreType, 
@@ -757,20 +758,20 @@
                 _truststoreProvider, _truststorePassword==null? null: _truststorePassword.toString());
         Collection<? extends CRL> crls = loadCRL(_crlPath);
 
-        if (_certAlias == null)
+        if (_validateCerts && keyStore != null)
         {
-            List<String> aliases = Collections.list(keyStore.aliases());
-            _certAlias = aliases.size() == 1?aliases.get(0):null;
-        }
+            if (_certAlias == null)
+            {
+                List<String> aliases = Collections.list(keyStore.aliases());
+                _certAlias = aliases.size() == 1 ? aliases.get(0) : null;
+            }
+    
+            Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
+            if (cert == null)
+            {
+                throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
+            }
 
-        Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
-        if (cert == null)
-        {
-            throw new Exception("No certificate found in the keystore" + (_certAlias == null?"":" for alias " + _certAlias));
-        }
-
-        if (_validateCerts)
-        {
             CertificateValidator validator = new CertificateValidator(trustStore,crls);
             validator.validate(keyStore, cert);
         }
@@ -917,7 +918,8 @@
     protected void checkConfig()
     {
         /*
-         * if the keystore exists but the trust store doesn't use the keystore as the trust store
+         * if the keystore exists but the trust store 
+         * does not, use the keystore as the trust store
          */
         if (_keystoreInputStream != null || _keystorePath != null)
         {
@@ -932,7 +934,7 @@
             }
         }
         
-        // It's the same stream and we cannot read it twice, so we read it once in memory
+        // It's the same stream we cannot read it twice, so read it once in memory
         if (_keystoreInputStream != null && _keystoreInputStream == _truststoreInputStream)
         {
             try
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java
index 3267530..b1321af 100644
--- a/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java
@@ -213,12 +213,20 @@
         throws Exception
     {
         _client = new HttpClient();
-        _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+        configureClient(_client);
+        
         if (realm != null)
             _client.setRealmResolver(new SimpleRealmResolver(realm));
+        
         _client.start();
     }
     
+    protected void configureClient(HttpClient client)
+        throws Exception
+    {
+        client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+    }
+
     protected void stopClient()
         throws Exception
     {
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java
deleted file mode 100644
index c823bd3..0000000
--- a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.eclipse.jetty.exssl;
-
-import java.io.File;
-import java.lang.reflect.Constructor;
-import java.security.cert.CertificateException;
-
-import org.eclipse.jetty.io.SslContextFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ssl.SslConnector;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.junit.After;
-import org.junit.Test;
-
-public abstract class CertificateValidationTestBase
-{
-    protected Server _server;
-    protected Class<? extends SslConnector> _klass;
-
-    @After
-    public void tearDown()
-    {
-        try
-        {
-            _server.stop();
-            _server = null;
-        }
-        catch (Exception ex) {}
-    }
-
-    protected void doTest(String keystore) throws Exception
-    {
-        String keypath = MavenTestingUtils.getTestResourceFile(keystore).getAbsolutePath();
-        String trustpath = new File(System.getProperty("java.home"),"./lib/security/cacerts").getAbsolutePath();
-        String crlpath = MavenTestingUtils.getTestResourceFile("crlfile.pem").getAbsolutePath();
-
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setValidateCerts(true);
-        sslContextFactory.setKeystore(keypath);
-        sslContextFactory.setKeyStorePassword("webtide");
-        sslContextFactory.setKeyManagerPassword("webtide");
-        sslContextFactory.setTruststore(trustpath);
-        sslContextFactory.setTrustStorePassword("changeit");
-        sslContextFactory.setCrlPath(crlpath);
-        
-        Constructor<? extends SslConnector> constructor = _klass.getConstructor(SslContextFactory.class);
-        SslConnector connector = constructor.newInstance(sslContextFactory);
-        connector.setPort(0);
-
-        _server = new Server();
-        _server.addConnector(connector);
-        _server.start();
-        
-        Thread.sleep(1000);
-    }
-    
-    @Test
-    public void validCertificateTest() throws Exception
-    {
-        doTest("jetty-valid.keystore"); // certificate is valid until Jan 1, 2050
-    }
-    
-    @Test(expected = CertificateException.class)
-    public void revokedCertificateTest() throws Exception
-    {
-        doTest("jetty-revoked.keystore"); // certificate is valid until Jan 1, 2050
-    }
-
-    @Test(expected = CertificateException.class)
-    public void notvalidCertificateTest() throws Exception
-    {
-        doTest("jetty-notvalid.keystore"); // certificate is valid from Jan 1, 2049
-    }
-
-    @Test(expected = CertificateException.class)
-    public void expiredCertificateTest() throws Exception
-    {
-        doTest("jetty-expired.keystore"); // certificate is valid until Dec 31, 2000
-    }
-}
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidatorTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidatorTest.java
new file mode 100644
index 0000000..aa64a15
--- /dev/null
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidatorTest.java
@@ -0,0 +1,53 @@
+package org.eclipse.jetty.exssl;
+
+import java.io.File;
+import java.security.cert.CertificateException;
+
+import org.eclipse.jetty.io.SslContextFactory;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Test;
+
+public class CertificateValidatorTest
+{
+    protected void doTest(String keystore) throws Exception
+    {
+        String keypath = MavenTestingUtils.getTestResourceFile(keystore).getAbsolutePath();
+        String trustpath = new File(System.getProperty("java.home"),"./lib/security/cacerts").getAbsolutePath();
+        String crlpath = MavenTestingUtils.getTestResourceFile("crlfile.pem").getAbsolutePath();
+
+        SslContextFactory factory = new SslContextFactory();
+        factory.setValidateCerts(true);
+        factory.setKeystore(keypath);
+        factory.setKeystorePassword("webtide");
+        factory.setKeyManagerPassword("webtide");
+        factory.setTruststore(trustpath);
+        factory.setTruststorePassword("changeit");
+        factory.setCrlPath(crlpath);
+        
+        factory.createSSLContext();
+    }
+    
+    @Test
+    public void validCertificateTest() throws Exception
+    {
+        doTest("jetty-valid.keystore"); // certificate is valid until Jan 1, 2050
+    }
+    
+    @Test(expected = CertificateException.class)
+    public void revokedCertificateTest() throws Exception
+    {
+        doTest("jetty-revoked.keystore"); // certificate is valid until Jan 1, 2050
+    }
+
+    @Test(expected = CertificateException.class)
+    public void notvalidCertificateTest() throws Exception
+    {
+        doTest("jetty-notvalid.keystore"); // certificate is valid from Jan 1, 2049
+    }
+
+    @Test(expected = CertificateException.class)
+    public void expiredCertificateTest() throws Exception
+    {
+        doTest("jetty-expired.keystore"); // certificate is valid until Dec 31, 2000
+    }
+}
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSelectChannelValidationTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSelectChannelValidationTest.java
index 56fadd6..955ce72 100644
--- a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSelectChannelValidationTest.java
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSelectChannelValidationTest.java
@@ -1,12 +1,12 @@
 package org.eclipse.jetty.exssl;
 
-import org.junit.Before;
+import org.eclipse.jetty.client.HttpClient;
 
-public class SslSelectChannelValidationTest extends CertificateValidationTestBase
+public class SslSelectChannelValidationTest extends SslValidationTestBase
 {
-    @Before
-    public void setUp()
+    static
     {
-        _klass = SslSelectChannelConnector.class;
+        __klass = SslSelectChannelConnector.class;
+        __konnector = HttpClient.CONNECTOR_SELECT_CHANNEL;
     }
 }
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSocketValidationTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSocketValidationTest.java
index 5337d27..8f52403 100644
--- a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSocketValidationTest.java
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslSocketValidationTest.java
@@ -1,12 +1,12 @@
 package org.eclipse.jetty.exssl;
 
-import org.junit.Before;
+import org.eclipse.jetty.client.HttpClient;
 
-public class SslSocketValidationTest extends CertificateValidationTestBase
+public class SslSocketValidationTest extends SslValidationTestBase
 {
-    @Before
-    public void setUp()
+    static
     {
-        _klass = SslSocketConnector.class;
+        __klass = SslSocketConnector.class;
+        __konnector = HttpClient.CONNECTOR_SOCKET;
     }
 }
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslValidationTestBase.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslValidationTestBase.java
new file mode 100644
index 0000000..f835623
--- /dev/null
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/SslValidationTestBase.java
@@ -0,0 +1,71 @@
+package org.eclipse.jetty.exssl;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.SslContentExchangeTest;
+import org.eclipse.jetty.io.SslContextFactory;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.ssl.SslConnector;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Ignore;
+
+public abstract class SslValidationTestBase extends SslContentExchangeTest
+{
+    protected static Class<? extends SslConnector> __klass;
+    protected static int __konnector;
+
+    @Override
+    protected void configureServer(Server server)
+        throws Exception
+    {
+        setProtocol("https");
+        
+        // certificate is valid until Jan 1, 2050
+        String keypath = MavenTestingUtils.getTestResourceFile("jetty-valid.keystore").getAbsolutePath();
+        String trustpath = new File(System.getProperty("java.home"),"./lib/security/cacerts").getAbsolutePath();
+        String crlpath = MavenTestingUtils.getTestResourceFile("crlfile.pem").getAbsolutePath();
+
+        SslContextFactory srvFactory = new SslContextFactory();
+        srvFactory.setValidateCerts(true);
+        srvFactory.setKeystore(keypath);
+        srvFactory.setKeystorePassword("webtide");
+        srvFactory.setKeyManagerPassword("webtide");
+        srvFactory.setTruststore(trustpath);
+        srvFactory.setTruststorePassword("changeit");
+        srvFactory.setCrlPath(crlpath);
+        
+        Constructor<? extends SslConnector> constructor = __klass.getConstructor(SslContextFactory.class);
+        SslConnector connector = constructor.newInstance(srvFactory);
+        server.addConnector(connector);
+
+        Handler handler = new TestHandler(getBasePath());
+    
+        ServletContextHandler root = new ServletContextHandler();
+        root.setContextPath("/");
+        root.setResourceBase(getBasePath());
+        ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
+        servletHolder.setInitParameter( "gzip", "true" );
+        root.addServlet( servletHolder, "/*" );    
+    
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(new Handler[]{handler, root});
+        server.setHandler( handlers ); 
+    }
+    
+//    @Override
+//    protected void configureClient(HttpClient client)
+//        throws Exception
+//    {
+//        String trustpath = new File(System.getProperty("java.home"),"./lib/security/cacerts").getAbsolutePath();
+//        client.setTrustStoreLocation(trustpath);
+//        client.setTrustStorePassword("changeit");
+//        client.setConnectorType(__konnector);
+//    }
+}