1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.nio.integration;
29
30 import java.io.IOException;
31 import java.net.InetSocketAddress;
32 import java.net.URL;
33 import java.security.Provider;
34 import java.security.SecureRandom;
35 import java.security.Security;
36 import java.util.Arrays;
37 import java.util.Collection;
38 import java.util.concurrent.Future;
39 import java.util.concurrent.TimeUnit;
40
41 import javax.net.ssl.SSLContext;
42 import javax.net.ssl.SSLEngine;
43 import javax.net.ssl.SSLException;
44 import javax.net.ssl.SSLSession;
45
46 import org.apache.http.HttpHeaders;
47 import org.apache.http.HttpHost;
48 import org.apache.http.HttpResponse;
49 import org.apache.http.config.ConnectionConfig;
50 import org.apache.http.impl.nio.pool.BasicNIOConnFactory;
51 import org.apache.http.message.BasicHttpRequest;
52 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
53 import org.apache.http.nio.reactor.IOSession;
54 import org.apache.http.nio.reactor.ListenerEndpoint;
55 import org.apache.http.nio.reactor.ssl.SSLSetupHandler;
56 import org.apache.http.nio.testserver.HttpClientNio;
57 import org.apache.http.nio.testserver.HttpServerNio;
58 import org.apache.http.nio.testserver.ServerConnectionFactory;
59 import org.apache.http.nio.util.TestingSupport;
60 import org.apache.http.protocol.ImmutableHttpProcessor;
61 import org.apache.http.protocol.ResponseServer;
62 import org.apache.http.ssl.SSLContextBuilder;
63 import org.apache.http.util.EntityUtils;
64 import org.conscrypt.Conscrypt;
65 import org.junit.Assert;
66 import org.junit.Assume;
67 import org.junit.BeforeClass;
68 import org.junit.Rule;
69 import org.junit.Test;
70 import org.junit.rules.ExternalResource;
71 import org.junit.rules.RuleChain;
72 import org.junit.rules.TestRule;
73 import org.junit.runner.RunWith;
74 import org.junit.runners.Parameterized;
75
76 @RunWith(Parameterized.class)
77 public class TestJSSEProviderIntegration {
78
79 private final static long RESULT_TIMEOUT_SEC = 30;
80 private final static int REQ_NUM = 25;
81
82 @Parameterized.Parameters(name = "{0} {1}")
83 public static Collection<Object[]> protocols() {
84 return Arrays.asList(new Object[][]{
85 {"Oracle", null},
86 {"Conscrypt", "TLSv1.2"},
87 {"Conscrypt", "TLSv1.3"}
88 });
89 }
90
91 private final String securityProviderName;
92 private final String protocolVersion;
93
94 private Provider securityProvider;
95 private HttpServerNio server;
96 private HttpClientNio client;
97
98 public TestJSSEProviderIntegration(final String securityProviderName, final String protocolVersion) {
99 super();
100 this.securityProviderName = securityProviderName;
101 this.protocolVersion = protocolVersion;
102 }
103
104 @BeforeClass
105 public static void determineJavaVersion() {
106 Assume.assumeTrue("Java version must be 8 or greater", TestingSupport.determineJRELevel() >= 8);
107 }
108
109 @Rule
110 public TestRule resourceRules = RuleChain.outerRule(new ExternalResource() {
111
112 @Override
113 protected void before() throws Throwable {
114 if ("Conscrypt".equalsIgnoreCase(securityProviderName)) {
115 try {
116 securityProvider = Conscrypt.newProviderBuilder().provideTrustManager(true).build();
117 } catch (final UnsatisfiedLinkError e) {
118 Assume.assumeFalse("Conscrypt provider failed to be loaded: " + e.getMessage(), true);
119 }
120 } else {
121 securityProvider = null;
122 }
123 if (securityProvider != null) {
124 Security.insertProviderAt(securityProvider, 1);
125 }
126 }
127
128 @Override
129 protected void after() {
130 if (securityProvider != null) {
131 Security.removeProvider(securityProvider.getName());
132 securityProvider = null;
133 }
134 }
135
136 }).around(new ExternalResource() {
137
138 @Override
139 protected void before() throws Throwable {
140 final URL keyStoreURL = TestJSSEProviderIntegration.class.getResource("/test-server.p12");
141 final String storePassword = "nopassword";
142 final SSLContext sslContext = SSLContextBuilder.create()
143 .setKeyStoreType("pkcs12")
144 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
145 .loadKeyMaterial(keyStoreURL, storePassword.toCharArray(), storePassword.toCharArray())
146 .setSecureRandom(new SecureRandom())
147 .build();
148
149 server = new HttpServerNio();
150 server.setConnectionFactory(new ServerConnectionFactory(sslContext, new SSLSetupHandler() {
151
152 @Override
153 public void initalize(final SSLEngine sslEngine) throws SSLException {
154 if (protocolVersion != null) {
155 sslEngine.setEnabledProtocols(new String[]{protocolVersion});
156 }
157 }
158
159 @Override
160 public void verify(final IOSession ioSession, final SSLSession sslSession) throws SSLException {
161 }
162
163 }));
164 server.setTimeout(5000);
165 }
166
167 @Override
168 protected void after() {
169 if (server != null) {
170 try {
171 server.shutdown();
172 } catch (final Exception ignore) {
173 }
174 }
175 }
176
177 }).around(new ExternalResource() {
178
179 @Override
180 protected void before() throws Throwable {
181 final URL keyStoreURL = TestJSSEProviderIntegration.class.getResource("/test-client.p12");
182 final String storePassword = "nopassword";
183 final SSLContext sslContext = SSLContextBuilder.create()
184 .setKeyStoreType("pkcs12")
185 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
186 .setSecureRandom(new SecureRandom())
187 .build();
188
189 client = new HttpClientNio(new BasicNIOConnFactory(sslContext, new SSLSetupHandler() {
190
191 @Override
192 public void initalize(final SSLEngine sslEngine) throws SSLException {
193 if (protocolVersion != null) {
194 sslEngine.setEnabledProtocols(new String[]{protocolVersion});
195 }
196 }
197
198 @Override
199 public void verify(final IOSession ioSession, final SSLSession sslSession) throws SSLException {
200 }
201
202 }, ConnectionConfig.DEFAULT));
203 client.setTimeout(5000);
204 }
205
206 @Override
207 protected void after() {
208 if (client != null) {
209 try {
210 client.shutdown();
211 } catch (final Exception ignore) {
212 }
213 }
214 }
215
216 });
217
218 private HttpHost start() throws IOException, InterruptedException {
219 this.server.start();
220 this.client.start();
221
222 final ListenerEndpoint endpoint = this.server.getListenerEndpoint();
223 endpoint.waitFor();
224
225 final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
226 return new HttpHost("localhost", address.getPort(), "https");
227 }
228
229 @Test
230 public void testHttpGets() throws Exception {
231 this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
232 final HttpHost target = start();
233
234 this.client.setMaxPerRoute(3);
235 this.client.setMaxTotal(3);
236
237 final String pattern = RndTestPatternGenerator.generateText();
238
239 for (int i = 0; i < REQ_NUM; i++) {
240 final BasicHttpRequest request = new BasicHttpRequest("GET", pattern + "x1");
241 final Future<HttpResponse> future = this.client.execute(target, request);
242 final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
243 Assert.assertNotNull(response);
244 Assert.assertEquals(pattern, EntityUtils.toString(response.getEntity()));
245 }
246 }
247
248 @Test
249 public void testHttpGetsCloseConnection() throws Exception {
250 this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
251 final HttpHost target = start();
252
253 this.client.setMaxPerRoute(3);
254 this.client.setMaxTotal(3);
255
256 final String pattern = RndTestPatternGenerator.generateText();
257
258 for (int i = 0; i < REQ_NUM; i++) {
259 final BasicHttpRequest request = new BasicHttpRequest("GET", pattern + "x1");
260 request.addHeader(HttpHeaders.CONNECTION, "Close");
261 final Future<HttpResponse> future = this.client.execute(target, request);
262 final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
263 Assert.assertNotNull(response);
264 Assert.assertEquals(pattern, EntityUtils.toString(response.getEntity()));
265 }
266 }
267
268 @Test
269 public void testHttpGetIdentityTransfer() throws Exception {
270 this.server.setHttpProcessor(new ImmutableHttpProcessor(new ResponseServer("TEST-SERVER/1.1")));
271 this.server.registerHandler("*", new BasicAsyncRequestHandler(new SimpleRequestHandler()));
272 final HttpHost target = start();
273
274 this.client.setMaxPerRoute(3);
275 this.client.setMaxTotal(3);
276
277 final String pattern = RndTestPatternGenerator.generateText();
278
279 for (int i = 0; i < REQ_NUM; i++) {
280 final BasicHttpRequest request = new BasicHttpRequest("GET", pattern + "x1");
281 final Future<HttpResponse> future = this.client.execute(target, request);
282 final HttpResponse response = future.get(RESULT_TIMEOUT_SEC, TimeUnit.SECONDS);
283 Assert.assertNotNull(response);
284 Assert.assertEquals(pattern, EntityUtils.toString(response.getEntity()));
285 }
286 }
287
288 }