Skip to content

Commit 19d8be8

Browse files
author
Stephane Landelle
committed
Have a way to configure SslEngine enabled Protocols and CipherSuites, close AsyncHttpClient#740
1 parent e5be625 commit 19d8be8

File tree

4 files changed

+78
-21
lines changed

4 files changed

+78
-21
lines changed

api/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ public class AsyncHttpClientConfig {
104104
protected boolean disableUrlEncodingForBoundRequests;
105105
protected int ioThreadMultiplier;
106106
protected TimeConverter timeConverter;
107+
protected String[] enabledProtocols;
108+
protected String[] enabledCipherSuites;
107109
protected AsyncHttpProviderConfig<?, ?> providerConfig;
108110

109111
// AHC 2 specific
@@ -144,6 +146,8 @@ private AsyncHttpClientConfig(int connectTimeout,//
144146
boolean disableUrlEncodingForBoundRequests, //
145147
int ioThreadMultiplier, //
146148
TimeConverter timeConverter,//
149+
String[] enabledProtocols,//
150+
String[] enabledCipherSuites,//
147151
AsyncHttpProviderConfig<?, ?> providerConfig,//
148152
boolean spdyEnabled, //
149153
int spdyInitialWindowSize, //
@@ -179,6 +183,8 @@ private AsyncHttpClientConfig(int connectTimeout,//
179183
this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests;
180184
this.ioThreadMultiplier = ioThreadMultiplier;
181185
this.timeConverter = timeConverter;
186+
this.enabledProtocols = enabledProtocols;
187+
this.enabledCipherSuites = enabledCipherSuites;
182188
this.providerConfig = providerConfig;
183189
this.spdyEnabled = spdyEnabled;
184190
this.spdyInitialWindowSize = spdyInitialWindowSize;
@@ -514,7 +520,7 @@ public int getConnectionTTL() {
514520
/**
515521
* @return the TimeConverter used for converting RFC2616Dates into time
516522
*
517-
* @since 2.0.0
523+
* since 1.9.0
518524
*/
519525
public TimeConverter getTimeConverter() {
520526
return timeConverter;
@@ -524,6 +530,20 @@ public boolean isAcceptAnyCertificate() {
524530
return acceptAnyCertificate;
525531
}
526532

533+
/**
534+
* since 1.9.0
535+
*/
536+
public String[] getEnabledProtocols() {
537+
return enabledProtocols;
538+
}
539+
540+
/**
541+
* since 1.9.0
542+
*/
543+
public String[] getEnabledCipherSuites() {
544+
return enabledCipherSuites;
545+
}
546+
527547
/**
528548
* Builder for an {@link AsyncHttpClient}
529549
*/
@@ -560,6 +580,8 @@ public static class Builder {
560580
private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests();
561581
private int ioThreadMultiplier = defaultIoThreadMultiplier();
562582
private TimeConverter timeConverter;
583+
private String[] enabledProtocols;
584+
private String[] enabledCipherSuites;
563585
private AsyncHttpProviderConfig<?, ?> providerConfig;
564586

565587
// AHC 2
@@ -1028,7 +1050,17 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) {
10281050
this.acceptAnyCertificate = acceptAnyCertificate;
10291051
return this;
10301052
}
1031-
1053+
1054+
public Builder setEnabledProtocols(String[] enabledProtocols) {
1055+
this.enabledProtocols = enabledProtocols;
1056+
return this;
1057+
}
1058+
1059+
public Builder setEnabledCipherSuites(String[] enabledCipherSuites) {
1060+
this.enabledCipherSuites = enabledCipherSuites;
1061+
return this;
1062+
}
1063+
10321064
/**
10331065
* Create a config builder with values taken from the given prototype configuration.
10341066
*
@@ -1070,7 +1102,9 @@ public Builder(AsyncHttpClientConfig prototype) {
10701102
strict302Handling = prototype.isStrict302Handling();
10711103
timeConverter = prototype.timeConverter;
10721104
acceptAnyCertificate = prototype.acceptAnyCertificate;
1073-
1105+
enabledProtocols = prototype.enabledProtocols;
1106+
enabledCipherSuites = prototype.enabledCipherSuites;
1107+
10741108
spdyEnabled = prototype.isSpdyEnabled();
10751109
spdyInitialWindowSize = prototype.getSpdyInitialWindowSize();
10761110
spdyMaxConcurrentStreams = prototype.getSpdyMaxConcurrentStreams();
@@ -1127,6 +1161,8 @@ else if (hostnameVerifier == null)
11271161
disableUrlEncodingForBoundRequests, //
11281162
ioThreadMultiplier, //
11291163
timeConverter,//
1164+
enabledProtocols, //
1165+
enabledCipherSuites, //
11301166
providerConfig, //
11311167
spdyEnabled, //
11321168
spdyInitialWindowSize, //

api/src/main/java/org/asynchttpclient/SSLEngineFactory.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,51 @@
1313
*/
1414
package org.asynchttpclient;
1515

16+
import java.security.GeneralSecurityException;
17+
18+
import javax.net.ssl.SSLContext;
1619
import javax.net.ssl.SSLEngine;
1720

18-
import java.security.GeneralSecurityException;
21+
import org.asynchttpclient.util.SslUtils;
1922

2023
/**
2124
* Factory that creates an {@link SSLEngine} to be used for a single SSL connection.
2225
*/
2326
public interface SSLEngineFactory {
27+
2428
/**
2529
* Creates new {@link SSLEngine}.
2630
*
2731
* @return new engine
2832
* @throws GeneralSecurityException if the SSLEngine cannot be created
2933
*/
30-
SSLEngine newSSLEngine() throws GeneralSecurityException;
34+
SSLEngine newSSLEngine(String peerHost, int peerPort) throws GeneralSecurityException;
35+
36+
public static class DefaultSSLEngineFactory implements SSLEngineFactory {
37+
38+
private final AsyncHttpClientConfig config;
39+
40+
public DefaultSSLEngineFactory(AsyncHttpClientConfig config) {
41+
this.config = config;
42+
}
43+
44+
@Override
45+
public SSLEngine newSSLEngine(String peerHost, int peerPort) throws GeneralSecurityException {
46+
SSLContext sslContext = config.getSSLContext();
47+
48+
if (sslContext == null)
49+
sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate());
50+
51+
SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort);
52+
sslEngine.setUseClientMode(true);
53+
54+
if (config.getEnabledProtocols() != null)
55+
sslEngine.setEnabledProtocols(config.getEnabledProtocols());
56+
57+
if (config.getEnabledCipherSuites() != null)
58+
sslEngine.setEnabledCipherSuites(config.getEnabledCipherSuites());
59+
60+
return sslEngine;
61+
}
62+
}
3163
}

api/src/main/java/org/asynchttpclient/util/SslUtils.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import javax.net.ssl.TrustManager;
2020
import javax.net.ssl.X509TrustManager;
2121

22-
import java.io.IOException;
2322
import java.security.GeneralSecurityException;
2423
import java.security.KeyManagementException;
2524
import java.security.NoSuchAlgorithmException;
@@ -65,7 +64,7 @@ public static SslUtils getInstance() {
6564
return SingletonHolder.instance;
6665
}
6766

68-
public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException {
67+
public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException {
6968
return acceptAnyCertificate? looseTrustManagerSSLContext: SSLContext.getDefault();
7069
}
7170
}

providers/netty/src/main/java/org/asynchttpclient/providers/netty/channel/ChannelManager.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@
4141
import java.util.concurrent.Semaphore;
4242
import java.util.concurrent.atomic.AtomicBoolean;
4343

44-
import javax.net.ssl.SSLContext;
4544
import javax.net.ssl.SSLEngine;
4645

4746
import org.asynchttpclient.AsyncHttpClientConfig;
4847
import org.asynchttpclient.ConnectionPoolPartitioning;
4948
import org.asynchttpclient.ProxyServer;
49+
import org.asynchttpclient.SSLEngineFactory;
5050
import org.asynchttpclient.providers.netty.Callback;
5151
import org.asynchttpclient.providers.netty.NettyAsyncHttpProviderConfig;
5252
import org.asynchttpclient.providers.netty.channel.pool.ChannelPool;
@@ -59,7 +59,6 @@
5959
import org.asynchttpclient.providers.netty.handler.WebSocketProtocol;
6060
import org.asynchttpclient.providers.netty.request.NettyRequestSender;
6161
import org.asynchttpclient.uri.Uri;
62-
import org.asynchttpclient.util.SslUtils;
6362
import org.slf4j.Logger;
6463
import org.slf4j.LoggerFactory;
6564

@@ -79,6 +78,7 @@ public class ChannelManager {
7978

8079
private final AsyncHttpClientConfig config;
8180
private final NettyAsyncHttpProviderConfig nettyConfig;
81+
private final SSLEngineFactory sslEngineFactory;
8282

8383
private final EventLoopGroup eventLoopGroup;
8484
private final boolean allowReleaseEventLoopGroup;
@@ -104,6 +104,7 @@ public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig
104104

105105
this.config = config;
106106
this.nettyConfig = nettyConfig;
107+
this.sslEngineFactory = nettyConfig.getSslEngineFactory() != null? nettyConfig.getSslEngineFactory() : new SSLEngineFactory.DefaultSSLEngineFactory(config);
107108

108109
ChannelPool channelPool = nettyConfig.getChannelPool();
109110
if (channelPool == null && config.isAllowPoolingConnections()) {
@@ -343,18 +344,7 @@ private HttpClientCodec newHttpClientCodec() {
343344

344345
public SslHandler createSslHandler(String peerHost, int peerPort) throws IOException, GeneralSecurityException {
345346

346-
SSLEngine sslEngine = null;
347-
if (nettyConfig.getSslEngineFactory() != null) {
348-
sslEngine = nettyConfig.getSslEngineFactory().newSSLEngine();
349-
350-
} else {
351-
SSLContext sslContext = config.getSSLContext();
352-
if (sslContext == null)
353-
sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate());
354-
355-
sslEngine = sslContext.createSSLEngine(peerHost, peerPort);
356-
sslEngine.setUseClientMode(true);
357-
}
347+
SSLEngine sslEngine = sslEngineFactory.newSSLEngine(peerHost, peerPort);
358348

359349
SslHandler sslHandler = new SslHandler(sslEngine);
360350
if (handshakeTimeout > 0)

0 commit comments

Comments
 (0)