diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index babb8cbd9e..444ceda349 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -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; @@ -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 requestFilters; @@ -114,6 +112,7 @@ public class AsyncHttpClientConfig { protected int spdyInitialWindowSize; protected int spdyMaxConcurrentStreams; protected TimeConverter timeConverter; + protected boolean acceptAnyCertificate; protected AsyncHttpClientConfig() { } @@ -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; @@ -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; @@ -190,6 +189,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, // this.spdyInitialWindowSize = spdyInitialWindowSize; this.spdyMaxConcurrentStreams = spdyMaxConcurrentStreams; this.timeConverter = timeConverter; + this.acceptAnyCertificate = acceptAnyCertificate; } @@ -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} * @@ -558,6 +536,10 @@ public TimeConverter getTimeConverter() { return timeConverter; } + public boolean isAcceptAnyCertificate() { + return acceptAnyCertificate; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -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; @@ -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. * @@ -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(); @@ -1212,7 +1199,8 @@ public Thread newThread(Runnable r) { spdyEnabled, // spdyInitialWindowSize, // spdyMaxConcurrentStreams, // - timeConverter); + timeConverter, // + acceptAnyCertificate); } } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java index 98ab988ebb..463d0c2c37 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigBean.java @@ -70,6 +70,7 @@ void configureDefaults() { spdyEnabled = defaultSpdyEnabled(); spdyInitialWindowSize = defaultSpdyInitialWindowSize(); spdyMaxConcurrentStreams = defaultSpdyMaxConcurrentStreams(); + acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } else if (defaultUseProxyProperties()) { @@ -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; @@ -239,4 +235,9 @@ public AsyncHttpClientConfigBean setIoThreadMultiplier(int ioThreadMultiplier) { this.ioThreadMultiplier = ioThreadMultiplier; return this; } + + public AsyncHttpClientConfigBean setAcceptAnyCertificate(boolean acceptAnyCertificate) { + this.acceptAnyCertificate = acceptAnyCertificate; + return this; + } } diff --git a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java index edd51169a1..3cb9ebddc7 100644 --- a/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java +++ b/api/src/main/java/org/asynchttpclient/AsyncHttpClientConfigDefaults.java @@ -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); + } } diff --git a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java index 4147e3e8d0..b96d69a91f 100644 --- a/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java +++ b/api/src/main/java/org/asynchttpclient/SimpleAsyncHttpClient.java @@ -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) { diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java index 7a80e00268..3cad6cfd37 100644 --- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java +++ b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java @@ -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 withDefault(T value, T defaults) { + return value != null? value : value; + } } diff --git a/api/src/main/java/org/asynchttpclient/util/SslUtils.java b/api/src/main/java/org/asynchttpclient/util/SslUtils.java index 29c7b70011..becb9ed943 100644 --- a/api/src/main/java/org/asynchttpclient/util/SslUtils.java +++ b/api/src/main/java/org/asynchttpclient/util/SslUtils.java @@ -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]; } @@ -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(); + } } diff --git a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java index f754ac83a5..132c87f453 100644 --- a/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java +++ b/api/src/test/java/org/asynchttpclient/async/HttpToHttpsRedirectTest.java @@ -96,7 +96,11 @@ public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { public void httpToHttpsRedirect() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); @@ -112,7 +116,11 @@ public void httpToHttpsRedirect() throws Exception { public void httpToHttpsProperConfig() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); @@ -134,7 +142,11 @@ public void httpToHttpsProperConfig() throws Exception { public void relativeLocationUrl() throws Exception { redirectDone.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaxRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaxRedirects(5)// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); diff --git a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java index 4f223f40ce..01d85ac608 100644 --- a/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/async/ProxyTunnellingTest.java @@ -74,12 +74,14 @@ public void tearDownGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void testRequestProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { - AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirects(true); ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - AsyncHttpClientConfig config = b.build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// + .setFollowRedirects(true)// + .setAcceptAnyCertificate(true)// + .build(); + AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); @@ -108,6 +110,7 @@ public void testConfigProxy() throws IOException, InterruptedException, Executio AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// .setFollowRedirects(true)// .setProxyServer(new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1))// + .setAcceptAnyCertificate(true)// .build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { @@ -136,7 +139,12 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()// .setProviderClass(getProviderClass())// - .setProxyProtocol(ProxyServer.Protocol.HTTPS).setProxyHost("127.0.0.1").setProxyPort(port1).setFollowRedirects(true).setUrl(getTargetUrl2())// + .setProxyProtocol(ProxyServer.Protocol.HTTPS)// + .setProxyHost("127.0.0.1")// + .setProxyPort(port1)// + .setFollowRedirects(true)// + .setUrl(getTargetUrl2())// + .setAcceptAnyCertificate(true)// .setHeader("Content-Type", "text/html")// .build(); try { diff --git a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java index 4df55e2537..cdb6e38cad 100644 --- a/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java +++ b/api/src/test/java/org/asynchttpclient/websocket/ProxyTunnellingTest.java @@ -78,7 +78,7 @@ protected String getTargetUrl() { public void echoText() throws Exception { ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { final CountDownLatch latch = new CountDownLatch(1); diff --git a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java index 6949ca9be3..2e1d77ee37 100644 --- a/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -253,7 +253,7 @@ public void onTimeout(Connection connection) { SSLContext context = clientConfig.getSSLContext(); if (context == null) { try { - context = SslUtils.getSSLContext(); + context = SslUtils.getInstance().getSSLContext(clientConfig.isAcceptAnyCertificate()); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 620eb6ea66..9e6a500c63 100644 --- a/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/providers/grizzly/src/test/java/org/asynchttpclient/providers/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -138,6 +138,7 @@ private void doSimpleFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) .setMaxConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); @@ -240,6 +241,7 @@ private void doNonBlockingFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaxConnectionsPerHost(60) .setMaxConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new DefaultAsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); diff --git a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java index f4a0022bad..ac75499993 100644 --- a/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/providers/netty/src/main/java/org/asynchttpclient/providers/netty/NettyAsyncHttpProviderConfig.java @@ -17,6 +17,7 @@ package org.asynchttpclient.providers.netty; import org.asynchttpclient.AsyncHttpProviderConfig; +import org.asynchttpclient.SSLEngineFactory; import org.asynchttpclient.providers.netty.channel.ChannelPool; import org.asynchttpclient.providers.netty.response.EagerResponseBodyPart; import org.asynchttpclient.providers.netty.response.LazyResponseBodyPart; @@ -93,6 +94,8 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig