You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2013/06/20 16:34:37 UTC
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/
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