Skip to content

Enable SSL validation #572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 13, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 16 additions & 28 deletions api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -94,7 +93,6 @@ public class AsyncHttpClientConfig {
protected ExecutorService applicationThreadPool;
protected ProxyServerSelector proxyServerSelector;
protected SSLContext sslContext;
protected SSLEngineFactory sslEngineFactory;
protected AsyncHttpProviderConfig<?, ?> providerConfig;
protected Realm realm;
protected List<RequestFilter> requestFilters;
Expand All @@ -114,6 +112,7 @@ public class AsyncHttpClientConfig {
protected int spdyInitialWindowSize;
protected int spdyMaxConcurrentStreams;
protected TimeConverter timeConverter;
protected boolean acceptAnyCertificate;

protected AsyncHttpClientConfig() {
}
Expand Down Expand Up @@ -153,7 +152,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, //
boolean spdyEnabled, //
int spdyInitialWindowSize, //
int spdyMaxConcurrentStreams, //
TimeConverter timeConverter) {
TimeConverter timeConverter, //
boolean acceptAnyCertificate) {

this.maxTotalConnections = maxTotalConnections;
this.maxConnectionPerHost = maxConnectionPerHost;
Expand All @@ -169,7 +169,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, //
this.userAgent = userAgent;
this.allowPoolingConnection = keepAlive;
this.sslContext = sslContext;
this.sslEngineFactory = sslEngineFactory;
this.providerConfig = providerConfig;
this.realm = realm;
this.requestFilters = requestFilters;
Expand All @@ -190,6 +189,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, //
this.spdyInitialWindowSize = spdyInitialWindowSize;
this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams;
this.timeConverter = timeConverter;
this.acceptAnyCertificate = acceptAnyCertificate;

}

Expand Down Expand Up @@ -332,28 +332,6 @@ public SSLContext getSSLContext() {
return sslContext;
}

/**
* Return an instance of {@link SSLEngineFactory} used for SSL connection.
*
* @return an instance of {@link SSLEngineFactory} used for SSL connection.
*/
public SSLEngineFactory getSSLEngineFactory() {
if (sslEngineFactory == null) {
return new SSLEngineFactory() {
public SSLEngine newSSLEngine() {
if (sslContext != null) {
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(true);
return sslEngine;
} else {
return null;
}
}
};
}
return sslEngineFactory;
}

/**
* Return the {@link AsyncHttpProviderConfig}
*
Expand Down Expand Up @@ -558,6 +536,10 @@ public TimeConverter getTimeConverter() {
return timeConverter;
}

public boolean isAcceptAnyCertificate() {
return acceptAnyCertificate;
}

/**
* Builder for an {@link AsyncHttpClient}
*/
Expand Down Expand Up @@ -589,6 +571,7 @@ public static class Builder {
private boolean spdyEnabled = defaultSpdyEnabled();
private int spdyInitialWindowSize = defaultSpdyInitialWindowSize();
private int spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams();
private boolean acceptAnyCertificate = defaultAcceptAnyCertificate();

private ScheduledExecutorService reaper;
private ExecutorService applicationThreadPool;
Expand Down Expand Up @@ -1103,6 +1086,11 @@ public Builder setTimeConverter(TimeConverter timeConverter) {
return this;
}

public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) {
this.acceptAnyCertificate = acceptAnyCertificate;
return this;
}

/**
* Create a config builder with values taken from the given prototype configuration.
*
Expand All @@ -1122,7 +1110,6 @@ public Builder(AsyncHttpClientConfig prototype) {
realm = prototype.getRealm();
requestTimeoutInMs = prototype.getRequestTimeoutInMs();
sslContext = prototype.getSSLContext();
sslEngineFactory = prototype.getSSLEngineFactory();
userAgent = prototype.getUserAgent();
redirectEnabled = prototype.isRedirectEnabled();
compressionEnabled = prototype.isCompressionEnabled();
Expand Down Expand Up @@ -1212,7 +1199,8 @@ public Thread newThread(Runnable r) {
spdyEnabled, //
spdyInitialWindowSize, //
spdyMaxConcurrentStreams, //
timeConverter);
timeConverter, //
acceptAnyCertificate);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ void configureDefaults() {
spdyEnabled = defaultSpdyEnabled();
spdyInitialWindowSize = defaultSpdyInitialWindowSize();
spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams();
acceptAnyCertificate = defaultAcceptAnyCertificate();
if (defaultUseProxySelector()) {
proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector();
} else if (defaultUseProxyProperties()) {
Expand Down Expand Up @@ -175,11 +176,6 @@ public AsyncHttpClientConfigBean setSslContext(SSLContext sslContext) {
return this;
}

public AsyncHttpClientConfigBean setSslEngineFactory(SSLEngineFactory sslEngineFactory) {
this.sslEngineFactory = sslEngineFactory;
return this;
}

public AsyncHttpClientConfigBean setProviderConfig(AsyncHttpProviderConfig<?, ?> providerConfig) {
this.providerConfig = providerConfig;
return this;
Expand Down Expand Up @@ -239,4 +235,9 @@ public AsyncHttpClientConfigBean setIoThreadMultiplier(int ioThreadMultiplier) {
this.ioThreadMultiplier = ioThreadMultiplier;
return this;
}

public AsyncHttpClientConfigBean setAcceptAnyCertificate(boolean acceptAnyCertificate) {
this.acceptAnyCertificate = acceptAnyCertificate;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,8 @@ public static int defaultSpdyInitialWindowSize() {
public static int defaultSpdyMaxConcurrentStreams() {
return Integer.getInteger(ASYNC_CLIENT + "spdyMaxConcurrentStreams", 100);
}

public static boolean defaultAcceptAnyCertificate() {
return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,11 @@ public Builder setProviderClass(String providerClass) {
return this;
}

public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) {
configBuilder.setAcceptAnyCertificate(acceptAnyCertificate);
return this;
}

public SimpleAsyncHttpClient build() {

if (realmBuilder != null) {
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/org/asynchttpclient/util/MiscUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) {
String systemPropValue = System.getProperty(systemPropName);
return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue;
}

public static <T> T withDefault(T value, T defaults) {
return value != null? value : value;
}
}
145 changes: 25 additions & 120 deletions api/src/main/java/org/asynchttpclient/util/SslUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,94 +15,23 @@
*/
package org.asynchttpclient.util;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;

/**
* This class is a copy of http://github.com/sonatype/wagon-ning/raw/master/src/main/java/org/apache/maven/wagon/providers/http/SslUtils.java
*/
public class SslUtils {

private static SSLContext context = null;

public static SSLEngine getSSLEngine() throws GeneralSecurityException, IOException {
SSLEngine engine = null;

SSLContext context = getSSLContext();
if (context != null) {
engine = context.createSSLEngine();
engine.setUseClientMode(true);
}

return engine;
}

public static SSLContext getSSLContext() throws GeneralSecurityException, IOException {
if (context == null) {
SSLConfig config = new SSLConfig();
if (config.keyStoreLocation == null || config.trustStoreLocation == null) {
context = getLooseSSLContext();
} else {
context = getStrictSSLContext(config);
}
}
return context;
}

static SSLContext getStrictSSLContext(SSLConfig config) throws GeneralSecurityException, IOException {
KeyStore keyStore = KeyStore.getInstance(config.keyStoreType);
InputStream keystoreInputStream = new FileInputStream(config.keyStoreLocation);
try {
keyStore.load(keystoreInputStream, (config.keyStorePassword == null) ? null : config.keyStorePassword.toCharArray());
} finally {
keystoreInputStream.close();
}

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(config.keyManagerAlgorithm);
keyManagerFactory.init(keyStore, (config.keyManagerPassword == null) ? null : config.keyManagerPassword.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

KeyStore trustStore = KeyStore.getInstance(config.trustStoreType);
InputStream truststoreInputStream = new FileInputStream(config.trustStoreLocation);
try {
trustStore.load(truststoreInputStream, (config.trustStorePassword == null) ? null : config.trustStorePassword.toCharArray());
} finally {
truststoreInputStream.close();
}

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(config.trustManagerAlgorithm);
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagers, trustManagers, null);

return context;
}

static SSLContext getLooseSSLContext() throws GeneralSecurityException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { LooseTrustManager.INSTANCE }, new SecureRandom());
return sslContext;
}


static class LooseTrustManager implements X509TrustManager {

public static final LooseTrustManager INSTANCE = new LooseTrustManager();

public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
Expand All @@ -114,53 +43,29 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin
}
}

private final static class SSLConfig {

public String keyStoreLocation;

public String keyStoreType = "JKS";

public String keyStorePassword = "changeit";

public String keyManagerAlgorithm = "SunX509";

public String keyManagerPassword = "changeit";

public String trustStoreLocation;

public String trustStoreType = "JKS";

public String trustStorePassword = "changeit";

public String trustManagerAlgorithm = "SunX509";

public SSLConfig() {
keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword", "changeit");
keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
keyManagerAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");

if (keyManagerAlgorithm == null) {
keyManagerAlgorithm = "SunX509";
}

keyManagerPassword = System.getProperty("javax.net.ssl.keyStorePassword", "changeit");

trustStoreLocation = System.getProperty("javax.net.ssl.trustStore");
if (trustStoreLocation == null) {
trustStoreLocation = keyStoreLocation;
trustStorePassword = keyStorePassword;
trustStoreType = keyStoreType;
} else {
trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword", "changeit");
trustStoreType = System.getProperty("javax.net.ssl.trustStoreType", KeyStore.getDefaultType());
}
trustManagerAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm");

if (trustManagerAlgorithm == null) {
trustManagerAlgorithm = "SunX509";
}
private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext();

private SSLContext looseTrustManagerSSLContext() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { new LooseTrustManager() }, new SecureRandom());
return sslContext;
} catch (NoSuchAlgorithmException e) {
throw new ExceptionInInitializerError(e);
} catch (KeyManagementException e) {
throw new ExceptionInInitializerError(e);
}
}

private static class SingletonHolder {
public static final SslUtils instance = new SslUtils();
}

public static SslUtils getInstance() {
return SingletonHolder.instance;
}

public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException {
return acceptAnyCertificate? looseTrustManagerSSLContext: SSLContext.getDefault();
}
}
Loading