hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1495022 - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/conn/ssl/ test/java/org/apache/http/conn/ssl/ test/java/org/apache/http/impl/client/integration/ test/java/org/apache/http/localserver/ test/resources/
Date Thu, 20 Jun 2013 14:34:37 GMT
Author: olegk
Date: Thu Jun 20 14:34:37 2013
New Revision: 1495022

URL: http://svn.apache.org/r1495022
Log:
Enhanced SSLContextBuilder; added PrivateKeyStrategy interface to enable customization of
private key selection; more SSL test cases

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java
      - copied, changed from r1494902, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
  (contents, props changed)
      - copied, changed from r1494902, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java
    httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-1.truststore
    httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-2.truststore
    httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test.keystore
Removed:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java
    httpcomponents/httpclient/trunk/httpclient/src/test/resources/test.keystore
Modified:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java
(from r1494902, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java&r1=1494902&r2=1495022&rev=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyDetails.java
Thu Jun 20 14:34:37 2013
@@ -26,39 +26,40 @@
  */
 package org.apache.http.conn.ssl;
 
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import org.apache.http.util.Args;
 
-import javax.net.ssl.X509TrustManager;
+import java.net.Socket;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Map;
 
 /**
- * @since 4.1
+ * Private key details.
+ *
+ * @since 4.3
  */
-class TrustManagerDecorator implements X509TrustManager {
+public final class PrivateKeyDetails {
 
-    private final X509TrustManager trustManager;
-    private final TrustStrategy trustStrategy;
+    private final String type;
+    private final X509Certificate[] certChain;
 
-    TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy)
{
+    public PrivateKeyDetails(final String type, final X509Certificate[] certChain) {
         super();
-        this.trustManager = trustManager;
-        this.trustStrategy = trustStrategy;
+        this.type = Args.notNull(type, "Private key type");
+        this.certChain = certChain;
     }
 
-    public void checkClientTrusted(
-            final X509Certificate[] chain, final String authType) throws CertificateException
{
-        this.trustManager.checkClientTrusted(chain, authType);
+    public String getType() {
+        return type;
     }
 
-    public void checkServerTrusted(
-            final X509Certificate[] chain, final String authType) throws CertificateException
{
-        if (!this.trustStrategy.isTrusted(chain, authType)) {
-            this.trustManager.checkServerTrusted(chain, authType);
-        }
+    public X509Certificate[] getCertChain() {
+        return certChain;
     }
 
-    public X509Certificate[] getAcceptedIssuers() {
-        return this.trustManager.getAcceptedIssuers();
+    @Override
+    public String toString() {
+        return type + ':' + Arrays.toString(certChain);
     }
 
 }

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
(from r1494902, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java&r1=1494902&r2=1495022&rev=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/TrustManagerDecorator.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
Thu Jun 20 14:34:37 2013
@@ -26,39 +26,22 @@
  */
 package org.apache.http.conn.ssl;
 
+import java.net.Socket;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
-
-import javax.net.ssl.X509TrustManager;
+import java.util.Map;
+import java.util.Set;
 
 /**
- * @since 4.1
+ * A strategy allowing for a choice of an alias during SSL authentication.
+ *
+ * @since 4.3
  */
-class TrustManagerDecorator implements X509TrustManager {
-
-    private final X509TrustManager trustManager;
-    private final TrustStrategy trustStrategy;
-
-    TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy)
{
-        super();
-        this.trustManager = trustManager;
-        this.trustStrategy = trustStrategy;
-    }
-
-    public void checkClientTrusted(
-            final X509Certificate[] chain, final String authType) throws CertificateException
{
-        this.trustManager.checkClientTrusted(chain, authType);
-    }
-
-    public void checkServerTrusted(
-            final X509Certificate[] chain, final String authType) throws CertificateException
{
-        if (!this.trustStrategy.isTrusted(chain, authType)) {
-            this.trustManager.checkServerTrusted(chain, authType);
-        }
-    }
+public interface PrivateKeyStrategy {
 
-    public X509Certificate[] getAcceptedIssuers() {
-        return this.trustManager.getAcceptedIssuers();
-    }
+    /**
+     * Determines what key material to use for SSL authentication.
+     */
+    String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket);
 
 }

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/PrivateKeyStrategy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
Thu Jun 20 14:34:37 2013
@@ -27,18 +27,28 @@
 
 package org.apache.http.conn.ssl;
 
+import java.net.Socket;
 import java.security.KeyManagementException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
 import javax.net.ssl.X509TrustManager;
 
 import org.apache.http.annotation.NotThreadSafe;
@@ -55,10 +65,16 @@ public class SSLContextBuilder {
     static final String SSL   = "SSL";
 
     private String protocol;
-    private KeyManager[] keymanagers;
-    private TrustManager[] trustmanagers;
+    private Set<KeyManager> keymanagers;
+    private Set<TrustManager> trustmanagers;
     private SecureRandom secureRandom;
 
+    public SSLContextBuilder() {
+        super();
+        this.keymanagers = new HashSet<KeyManager>();
+        this.trustmanagers = new HashSet<TrustManager>();
+    }
+
     public SSLContextBuilder useTLS() {
         this.protocol = TLS;
         return this;
@@ -81,52 +97,163 @@ public class SSLContextBuilder {
 
     public SSLContextBuilder loadTrustMaterial(
             final KeyStore truststore,
-            final char[] truststorePassword,
             final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException
{
         final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
                 TrustManagerFactory.getDefaultAlgorithm());
         tmfactory.init(truststore);
-        final TrustManager[] trustmanagers = tmfactory.getTrustManagers();
-        if (trustmanagers != null && trustStrategy != null) {
-            for (int i = 0; i < trustmanagers.length; i++) {
-                final TrustManager tm = trustmanagers[i];
-                if (tm instanceof X509TrustManager) {
-                    trustmanagers[i] = new TrustManagerDecorator(
-                            (X509TrustManager) tm, trustStrategy);
+        final TrustManager[] tms = tmfactory.getTrustManagers();
+        if (tms != null) {
+            if (trustStrategy != null) {
+                for (int i = 0; i < tms.length; i++) {
+                    final TrustManager tm = tms[i];
+                    if (tm instanceof X509TrustManager) {
+                        tms[i] = new TrustManagerDelegate(
+                                (X509TrustManager) tm, trustStrategy);
+                    }
                 }
             }
+            for (int i = 0; i < tms.length; i++) {
+                this.trustmanagers.add(tms[i]);
+            }
         }
-        this.trustmanagers = trustmanagers;
         return this;
     }
 
     public SSLContextBuilder loadTrustMaterial(
-            final KeyStore truststore,
-            final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException
{
-        return loadTrustMaterial(truststore, null, trustStrategy);
-    }
-
-    public SSLContextBuilder loadTrustMaterial(
             final KeyStore truststore) throws NoSuchAlgorithmException, KeyStoreException
{
-        return loadTrustMaterial(truststore, null, null);
+        return loadTrustMaterial(truststore, null);
     }
 
     public SSLContextBuilder loadKeyMaterial(
             final KeyStore keystore,
             final char[] keyPassword)
                 throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException
{
+        loadKeyMaterial(keystore, keyPassword, null);
+        return this;
+    }
+
+    public SSLContextBuilder loadKeyMaterial(
+            final KeyStore keystore,
+            final char[] keyPassword,
+            final PrivateKeyStrategy aliasStrategy)
+            throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException
{
         final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
                 KeyManagerFactory.getDefaultAlgorithm());
         kmfactory.init(keystore, keyPassword);
-        this.keymanagers =  kmfactory.getKeyManagers();
+        final KeyManager[] kms =  kmfactory.getKeyManagers();
+        if (kms != null) {
+            if (aliasStrategy != null) {
+                for (int i = 0; i < kms.length; i++) {
+                    final KeyManager km = kms[i];
+                    if (km instanceof X509KeyManager) {
+                        kms[i] = new KeyManagerDelegate(
+                                (X509KeyManager) km, aliasStrategy);
+                    }
+                }
+            }
+            for (int i = 0; i < kms.length; i++) {
+                keymanagers.add(kms[i]);
+            }
+        }
         return this;
     }
 
     public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
         final SSLContext sslcontext = SSLContext.getInstance(
                 this.protocol != null ? this.protocol : TLS);
-        sslcontext.init(keymanagers, trustmanagers, secureRandom);
+        sslcontext.init(
+                !keymanagers.isEmpty() ? keymanagers.toArray(new KeyManager[keymanagers.size()])
: null,
+                !trustmanagers.isEmpty() ? trustmanagers.toArray(new TrustManager[trustmanagers.size()])
: null,
+                secureRandom);
         return sslcontext;
     }
 
+    static class TrustManagerDelegate implements X509TrustManager {
+
+        private final X509TrustManager trustManager;
+        private final TrustStrategy trustStrategy;
+
+        TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy)
{
+            super();
+            this.trustManager = trustManager;
+            this.trustStrategy = trustStrategy;
+        }
+
+        public void checkClientTrusted(
+                final X509Certificate[] chain, final String authType) throws CertificateException
{
+            this.trustManager.checkClientTrusted(chain, authType);
+        }
+
+        public void checkServerTrusted(
+                final X509Certificate[] chain, final String authType) throws CertificateException
{
+            if (!this.trustStrategy.isTrusted(chain, authType)) {
+                this.trustManager.checkServerTrusted(chain, authType);
+            }
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            return this.trustManager.getAcceptedIssuers();
+        }
+
+    }
+
+    static class KeyManagerDelegate implements X509KeyManager {
+
+        private final X509KeyManager keyManager;
+        private final PrivateKeyStrategy aliasStrategy;
+
+        KeyManagerDelegate(final X509KeyManager keyManager, final PrivateKeyStrategy aliasStrategy)
{
+            super();
+            this.keyManager = keyManager;
+            this.aliasStrategy = aliasStrategy;
+        }
+
+        public String[] getClientAliases(
+                final String keyType, final Principal[] issuers) {
+            return this.keyManager.getClientAliases(keyType, issuers);
+        }
+
+        public String chooseClientAlias(
+                final String[] keyTypes, final Principal[] issuers, final Socket socket)
{
+            final Map<String, PrivateKeyDetails> validAliases = new HashMap<String,
PrivateKeyDetails>();
+            for (String keyType: keyTypes) {
+                String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
+                if (aliases != null) {
+                    for (String alias: aliases) {
+                        validAliases.put(alias,
+                                new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+                    }
+                }
+            }
+            return this.aliasStrategy.chooseAlias(validAliases, socket);
+        }
+
+        public String[] getServerAliases(
+                final String keyType, final Principal[] issuers) {
+            return this.keyManager.getServerAliases(keyType, issuers);
+        }
+
+        public String chooseServerAlias(
+                final String keyType, final Principal[] issuers, final Socket socket) {
+            final Map<String, PrivateKeyDetails> validAliases = new HashMap<String,
PrivateKeyDetails>();
+            String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
+            if (aliases != null) {
+                for (String alias: aliases) {
+                    validAliases.put(alias,
+                            new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+                }
+            }
+            return this.aliasStrategy.chooseAlias(validAliases, socket);
+        }
+
+        public X509Certificate[] getCertificateChain(final String alias) {
+            return this.keyManager.getCertificateChain(alias);
+        }
+
+        public PrivateKey getPrivateKey(final String alias) {
+            return this.keyManager.getPrivateKey(alias);
+        }
+
+    }
+
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java
Thu Jun 20 14:34:37 2013
@@ -85,6 +85,49 @@ import org.apache.http.util.TextUtils;
  * requested to do so by the server.
  * The target HTTPS server will in its turn verify the certificate presented
  * by the client in order to establish client's authenticity.
+ * <p>
+ * Use the following sequence of actions to generate a key-store file
+ * </p>
+ *   <ul>
+ *     <li>
+ *      <p>
+ *      Use JDK keytool utility to generate a new key
+ *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ *      For simplicity use the same password for the key as that of the key-store
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Issue a certificate signing request (CSR)
+ *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore
my.keystore</pre>
+ *     </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Send the certificate request to the trusted Certificate Authority for signature.
+ *      One may choose to act as her own CA and sign the certificate request using a PKI
+ *      tool, such as OpenSSL.
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the trusted CA root certificate
+ *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the PKCS#7 file containg the complete certificate chain
+ *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Verify the content the resultant keystore file
+ *       <pre>keytool -list -v -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *   </ul>
  *
  * @since 4.0
  */
@@ -275,7 +318,7 @@ public class SSLSocketFactory implements
             final X509HostnameVerifier hostnameVerifier)
                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException,
UnrecoverableKeyException {
         this(SSLContexts.custom()
-                .loadTrustMaterial(null, null, trustStrategy)
+                .loadTrustMaterial(null, trustStrategy)
                 .build(),
                 hostnameVerifier);
     }
@@ -290,7 +333,7 @@ public class SSLSocketFactory implements
             final TrustStrategy trustStrategy)
                 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException,
UnrecoverableKeyException {
         this(SSLContexts.custom()
-                .loadTrustMaterial(null, null, trustStrategy)
+                .loadTrustMaterial(null, trustStrategy)
                 .build(),
                 BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
     }

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLContextBuilder.java
Thu Jun 20 14:34:37 2013
@@ -27,28 +27,60 @@
 
 package org.apache.http.conn.ssl;
 
+import java.io.InputStream;
 import java.net.URL;
 import java.security.KeyStore;
 import java.security.UnrecoverableKeyException;
 
-import org.apache.http.localserver.LocalServerTestBase;
 import org.junit.Test;
 
 /**
  * Unit tests for {@link org.apache.http.conn.ssl.SSLContextBuilder}.
  */
-public class TestSSLContextBuilder extends LocalServerTestBase {
+public class TestSSLContextBuilder {
+
+    private static KeyStore load(final String res, final char[] passwd) throws Exception
{
+        final KeyStore keystore  = KeyStore.getInstance("jks");
+        final ClassLoader cl = TestSSLContextBuilder.class.getClassLoader();
+        final URL url = cl.getResource(res);
+        final InputStream instream = url.openStream();
+        try {
+            keystore.load(instream, passwd);
+        } finally {
+            instream.close();
+        }
+        return keystore;
+    }
 
     @Test
-    public void testKeyWithAlternatePassword() throws Exception {
-        final String keystorePassword = "nopassword";
-        final String keyPassword = "password";
+    public void testBuildDefault() throws Exception {
+        new SSLContextBuilder().build();
+    }
 
-        final ClassLoader cl = getClass().getClassLoader();
-        final URL url = cl.getResource("test-keypasswd.keystore");
-        final KeyStore keystore  = KeyStore.getInstance("jks");
-        keystore.load(url.openStream(), keystorePassword.toCharArray());
+    @Test
+    public void testBuildAllNull() throws Exception {
+        new SSLContextBuilder()
+                .useProtocol(null)
+                .setSecureRandom(null)
+                .loadTrustMaterial(null)
+                .loadKeyMaterial(null, null)
+                .build();
+    }
 
+    @Test
+    public void testLoadTrustMultipleMaterial() throws Exception {
+        final KeyStore truststore1 = load("hc-test-1.truststore", "nopassword".toCharArray());
+        final KeyStore truststore2 = load("hc-test-2.truststore", "nopassword".toCharArray());
+        new SSLContextBuilder()
+                .loadTrustMaterial(truststore1)
+                .loadTrustMaterial(truststore2)
+                .build();
+    }
+
+    @Test
+    public void testKeyWithAlternatePassword() throws Exception {
+        final KeyStore keystore = load("test-keypasswd.keystore", "nopassword".toCharArray());
+        final String keyPassword = "password";
         new SSLContextBuilder()
                 .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray()
: null)
                 .loadTrustMaterial(keystore)
@@ -57,14 +89,8 @@ public class TestSSLContextBuilder exten
 
     @Test(expected=UnrecoverableKeyException.class)
     public void testKeyWithAlternatePasswordInvalid() throws Exception {
-        final String keystorePassword = "nopassword";
+        final KeyStore keystore = load("test-keypasswd.keystore", "nopassword".toCharArray());
         final String keyPassword = "!password";
-
-        final ClassLoader cl = getClass().getClassLoader();
-        final URL url = cl.getResource("test-keypasswd.keystore");
-        final KeyStore keystore  = KeyStore.getInstance("jks");
-        keystore.load(url.openStream(), keystorePassword.toCharArray());
-
         new SSLContextBuilder()
                 .loadKeyMaterial(keystore, keyPassword != null ? keyPassword.toCharArray()
: null)
                 .loadTrustMaterial(keystore)

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestSSLSocketFactory.java
Thu Jun 20 14:34:37 2013
@@ -28,22 +28,20 @@
 package org.apache.http.conn.ssl;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.net.URL;
 import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
 
 import org.apache.http.HttpHost;
 import org.apache.http.localserver.LocalServerTestBase;
@@ -59,53 +57,19 @@ import org.junit.Test;
  */
 public class TestSSLSocketFactory extends LocalServerTestBase {
 
-    private KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException {
-        final String algo = KeyManagerFactory.getDefaultAlgorithm();
-        try {
-            return KeyManagerFactory.getInstance(algo);
-        } catch (final NoSuchAlgorithmException ex) {
-            return KeyManagerFactory.getInstance("SunX509");
-        }
-    }
-
-    private TrustManagerFactory createTrustManagerFactory() throws NoSuchAlgorithmException
{
-        final String algo = TrustManagerFactory.getDefaultAlgorithm();
-        try {
-            return TrustManagerFactory.getInstance(algo);
-        } catch (final NoSuchAlgorithmException ex) {
-            return TrustManagerFactory.getInstance("SunX509");
-        }
-    }
-
-    private SSLContext serverSSLContext;
-    private SSLContext clientSSLContext;
+    private KeyStore keystore;
 
     @Before
     public void setUp() throws Exception {
+        keystore  = KeyStore.getInstance("jks");
         final ClassLoader cl = getClass().getClassLoader();
-        final URL url = cl.getResource("test.keystore");
-        final KeyStore keystore  = KeyStore.getInstance("jks");
-        final char[] pwd = "nopassword".toCharArray();
-        keystore.load(url.openStream(), pwd);
-
-        final TrustManagerFactory tmf = createTrustManagerFactory();
-        tmf.init(keystore);
-        final TrustManager[] tm = tmf.getTrustManagers();
-
-        final KeyManagerFactory kmfactory = createKeyManagerFactory();
-        kmfactory.init(keystore, pwd);
-        final KeyManager[] km = kmfactory.getKeyManagers();
-
-        this.serverSSLContext = SSLContext.getInstance("TLS");
-        this.serverSSLContext.init(km, tm, null);
-
-        this.clientSSLContext = SSLContext.getInstance("TLS");
-        this.clientSSLContext.init(null, tm, null);
-
-        this.localServer = new LocalTestServer(this.serverSSLContext);
-        this.localServer.registerDefaultHandlers();
-
-        this.localServer.start();
+        final URL url = cl.getResource("hc-test.keystore");
+        final InputStream instream = url.openStream();
+        try {
+            keystore.load(instream, "nopassword".toCharArray());
+        } finally {
+            instream.close();
+        }
     }
 
     @Override
@@ -143,10 +107,125 @@ public class TestSSLSocketFactory extend
 
     @Test
     public void testBasicSSL() throws Exception {
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+        final SSLContext clientSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
+        final HttpHost host = new HttpHost("localhost", 443, "https");
+        final HttpContext context = new BasicHttpContext();
+        final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
+        final SSLSocketFactory socketFactory = new SSLSocketFactory(clientSSLContext, hostVerifier);
+        SSLSocket socket = (SSLSocket) socketFactory.createSocket(context);
+        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
+        socket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress,
null, context);
+        final SSLSession sslsession = socket.getSession();
+
+        Assert.assertNotNull(sslsession);
+        Assert.assertTrue(hostVerifier.isFired());
+    }
+
+    @Test
+    public void testClientAuthSSL() throws Exception {
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+        final SSLContext clientSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext, true);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
+        final HttpHost host = new HttpHost("localhost", 443, "https");
+        final HttpContext context = new BasicHttpContext();
+        final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
+        final SSLSocketFactory socketFactory = new SSLSocketFactory(clientSSLContext, hostVerifier);
+        SSLSocket socket = (SSLSocket) socketFactory.createSocket(context);
+        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
+        socket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress,
null, context);
+        final SSLSession sslsession = socket.getSession();
+
+        Assert.assertNotNull(sslsession);
+        Assert.assertTrue(hostVerifier.isFired());
+    }
+
+    @Test(expected=IOException.class)
+    public void testClientAuthSSLFailure() throws Exception {
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+        final SSLContext clientSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext, true);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
+        final HttpHost host = new HttpHost("localhost", 443, "https");
+        final HttpContext context = new BasicHttpContext();
+        final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
+        final SSLSocketFactory socketFactory = new SSLSocketFactory(clientSSLContext, hostVerifier);
+        SSLSocket socket = (SSLSocket) socketFactory.createSocket(context);
+        final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
+        socket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress,
null, context);
+        final SSLSession sslsession = socket.getSession();
+
+        Assert.assertNotNull(sslsession);
+        Assert.assertTrue(hostVerifier.isFired());
+    }
+
+    @Test
+    public void testClientAuthSSLAliasChoice() throws Exception {
+        final PrivateKeyStrategy aliasStrategy = new PrivateKeyStrategy() {
+
+            public String chooseAlias(
+                    final Map<String, PrivateKeyDetails> aliases, final Socket socket)
{
+                Assert.assertEquals(2, aliases.size());
+                Assert.assertTrue(aliases.containsKey("hc-test-key-1"));
+                Assert.assertTrue(aliases.containsKey("hc-test-key-2"));
+                return "hc-test-key-2";
+            }
+
+        };
+
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+        final SSLContext clientSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray(), aliasStrategy)
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext, true);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
         final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
         final TestX509HostnameVerifier hostVerifier = new TestX509HostnameVerifier();
-        final SSLSocketFactory socketFactory = new SSLSocketFactory(this.clientSSLContext,
hostVerifier);
+        final SSLSocketFactory socketFactory = new SSLSocketFactory(clientSSLContext, hostVerifier);
         SSLSocket socket = (SSLSocket) socketFactory.createSocket(context);
         final InetSocketAddress remoteAddress = this.localServer.getServiceAddress();
         socket = (SSLSocket) socketFactory.connectSocket(0, socket, host, remoteAddress,
null, context);
@@ -158,11 +237,24 @@ public class TestSSLSocketFactory extend
 
     @Test(expected=SSLHandshakeException.class)
     public void testSSLTrustVerification() throws Exception {
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+        final SSLContext clientSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
         final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
         // Use default SSL context
-        final SSLContext defaultsslcontext = SSLContext.getInstance("TLS");
-        defaultsslcontext.init(null, null, null);
+        final SSLContext defaultsslcontext = SSLContexts.createDefault();
 
         final SSLSocketFactory socketFactory = new SSLSocketFactory(defaultsslcontext,
                 SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
@@ -174,11 +266,18 @@ public class TestSSLSocketFactory extend
 
     @Test
     public void testSSLTrustVerificationOverride() throws Exception {
+        final SSLContext serverSSLContext = SSLContexts.custom()
+                .useProtocol("TLS")
+                .loadTrustMaterial(keystore)
+                .loadKeyMaterial(keystore, "nopassword".toCharArray())
+                .build();
+
+        this.localServer = new LocalTestServer(serverSSLContext);
+        this.localServer.registerDefaultHandlers();
+        this.localServer.start();
+
         final HttpHost host = new HttpHost("localhost", 443, "https");
         final HttpContext context = new BasicHttpContext();
-        // Use default SSL context
-        final SSLContext defaultsslcontext = SSLContext.getInstance("TLS");
-        defaultsslcontext.init(null, null, null);
 
         final TrustStrategy trustStrategy = new TrustStrategy() {
 
@@ -189,7 +288,7 @@ public class TestSSLSocketFactory extend
 
         };
         final SSLContext sslcontext = SSLContexts.custom()
-            .loadTrustMaterial(null, null, trustStrategy)
+            .loadTrustMaterial(null, trustStrategy)
             .build();
         final SSLSocketFactory socketFactory = new SSLSocketFactory(
                 sslcontext,

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java
Thu Jun 20 14:34:37 2013
@@ -235,7 +235,7 @@ public class TestClientAuthentication ex
             .add(new RequestBasicAuth())
             .add(new ResponseBasicUnauthorized()).build();
         this.localServer = new LocalTestServer(
-                httpproc, null, null, new AuthExpectationVerifier(), null);
+                httpproc, null, null, new AuthExpectationVerifier(), null, false);
         this.localServer.register("*", new AuthHandler());
         this.localServer.start();
 

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java?rev=1495022&r1=1495021&r2=1495022&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/localserver/LocalTestServer.java
Thu Jun 20 14:34:37 2013
@@ -37,6 +37,7 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
 import javax.net.ssl.SSLServerSocketFactory;
 
 import org.apache.http.ConnectionReuseStrategy;
@@ -85,6 +86,9 @@ public class LocalTestServer {
     /** Optional SSL context */
     private final SSLContext sslcontext;
 
+    /** Optional flag whether to force SSL context */
+    private final boolean forceSSLAuth;
+
     /** The server socket, while being served. */
     private volatile ServerSocket servicedSocket;
 
@@ -116,13 +120,15 @@ public class LocalTestServer {
      *                  <code>null</code>.
      * @param sslcontext optional SSL context if the server is to leverage
      *                   SSL/TLS transport security
+     * @param forceSSLAuth whether or not the server needs to enforce client auth
      */
     public LocalTestServer(
             final HttpProcessor proc,
             final ConnectionReuseStrategy reuseStrat,
             final HttpResponseFactory responseFactory,
             final HttpExpectationVerifier expectationVerifier,
-            final SSLContext sslcontext) {
+            final SSLContext sslcontext,
+            final boolean forceSSLAuth) {
         super();
         this.handlerRegistry = new UriHttpRequestHandlerMapper();
         this.workers = Collections.synchronizedSet(new HashSet<Worker>());
@@ -133,12 +139,23 @@ public class LocalTestServer {
             handlerRegistry,
             expectationVerifier);
         this.sslcontext = sslcontext;
+        this.forceSSLAuth = forceSSLAuth;
     }
 
     public LocalTestServer(
             final HttpProcessor proc,
             final ConnectionReuseStrategy reuseStrat) {
-        this(proc, reuseStrat, null, null, null);
+        this(proc, reuseStrat, null, null, null, false);
+    }
+
+    /**
+     * Creates a new test server with SSL/TLS encryption.
+     *
+     * @param sslcontext SSL context
+     * @param forceSSLAuth whether or not the server needs to enforce client auth
+     */
+    public LocalTestServer(final SSLContext sslcontext, final boolean forceSSLAuth) {
+        this(null, null, null, null, sslcontext, forceSSLAuth);
     }
 
     /**
@@ -147,7 +164,7 @@ public class LocalTestServer {
      * @param sslcontext SSL context
      */
     public LocalTestServer(final SSLContext sslcontext) {
-        this(null, null, null, null, sslcontext);
+        this(null, null, null, null, sslcontext, false);
     }
 
     /**
@@ -226,10 +243,16 @@ public class LocalTestServer {
      */
     public void start() throws Exception {
         Asserts.check(servicedSocket == null, "Already running");
-        ServerSocket ssock;
+        final ServerSocket ssock;
         if (sslcontext != null) {
             final SSLServerSocketFactory sf = sslcontext.getServerSocketFactory();
-            ssock = sf.createServerSocket();
+            final SSLServerSocket sslsock = (SSLServerSocket) sf.createServerSocket();
+            if (forceSSLAuth) {
+                sslsock.setNeedClientAuth(true);
+            } else {
+                sslsock.setWantClientAuth(true);
+            }
+            ssock = sslsock;
         } else {
             ssock = new ServerSocket();
         }

Added: httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-1.truststore
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-1.truststore?rev=1495022&view=auto
==============================================================================
Files httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-1.truststore (added)
and httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-1.truststore Thu
Jun 20 14:34:37 2013 differ

Added: httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-2.truststore
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-2.truststore?rev=1495022&view=auto
==============================================================================
Files httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-2.truststore (added)
and httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test-2.truststore Thu
Jun 20 14:34:37 2013 differ

Added: httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test.keystore
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test.keystore?rev=1495022&view=auto
==============================================================================
Files httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test.keystore (added)
and httpcomponents/httpclient/trunk/httpclient/src/test/resources/hc-test.keystore Thu Jun
20 14:34:37 2013 differ



Mime
View raw message