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.hc.core5.testing.nio;
29
30 import java.net.InetSocketAddress;
31 import java.net.URI;
32 import java.net.URISyntaxException;
33 import java.net.URL;
34 import java.security.Provider;
35 import java.security.SecureRandom;
36 import java.security.Security;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.concurrent.Future;
40
41 import javax.net.ssl.SSLEngine;
42
43 import org.apache.hc.core5.function.Supplier;
44 import org.apache.hc.core5.http.HttpHeaders;
45 import org.apache.hc.core5.http.HttpResponse;
46 import org.apache.hc.core5.http.Message;
47 import org.apache.hc.core5.http.Method;
48 import org.apache.hc.core5.http.config.Http1Config;
49 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
50 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
51 import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder;
52 import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
53 import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
54 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
55 import org.apache.hc.core5.http.protocol.HttpProcessor;
56 import org.apache.hc.core5.http.protocol.RequestValidateHost;
57 import org.apache.hc.core5.net.NamedEndpoint;
58 import org.apache.hc.core5.reactor.IOReactorConfig;
59 import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
60 import org.apache.hc.core5.ssl.SSLContextBuilder;
61 import org.apache.hc.core5.util.ReflectionUtils;
62 import org.apache.hc.core5.util.TimeValue;
63 import org.apache.hc.core5.util.Timeout;
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 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 @RunWith(Parameterized.class)
79 public class JSSEProviderIntegrationTest {
80
81 private final Logger log = LoggerFactory.getLogger(getClass());
82
83 @Parameterized.Parameters(name = "{0} {1}")
84 public static Collection<Object[]> protocols() {
85 return Arrays.asList(new Object[][]{
86 {"Oracle", null},
87 {"Conscrypt", "TLSv1.2"},
88 {"Conscrypt", "TLSv1.3"},
89 });
90 }
91
92 private final String securityProviderName;
93 private final String protocolVersion;
94
95 public JSSEProviderIntegrationTest(final String securityProviderName, final String protocolVersion) {
96 super();
97 this.securityProviderName = securityProviderName;
98 this.protocolVersion = protocolVersion;
99 }
100
101 private static final Timeout TIMEOUT = Timeout.ofMinutes(1);
102 private static final int REQ_NUM = 25;
103
104 private Provider securityProvider;
105 private Http1TestServer server;
106 private Http1TestClient client;
107
108 @BeforeClass
109 public static void determineJavaVersion() {
110 Assume.assumeTrue("Java version must be 8 or greater", ReflectionUtils.determineJRELevel() >= 8);
111 }
112
113 @Rule
114 public TestRule resourceRules = RuleChain.outerRule(new ExternalResource() {
115
116 @Override
117 protected void before() throws Throwable {
118 if ("Conscrypt".equalsIgnoreCase(securityProviderName)) {
119 try {
120 securityProvider = Conscrypt.newProviderBuilder().provideTrustManager(true).build();
121 } catch (final UnsatisfiedLinkError e) {
122 Assume.assumeFalse("Conscrypt provider failed to be loaded: " + e.getMessage(), true);
123 }
124 } else {
125 securityProvider = null;
126 }
127 if (securityProvider != null) {
128 Security.insertProviderAt(securityProvider, 1);
129 }
130 }
131
132 @Override
133 protected void after() {
134 if (securityProvider != null) {
135 Security.removeProvider(securityProvider.getName());
136 securityProvider = null;
137 }
138 }
139
140 }).around(new ExternalResource() {
141
142 @Override
143 protected void before() throws Throwable {
144 log.debug("Starting up test server");
145
146 final URL keyStoreURL = getClass().getResource("/test-server.p12");
147 final String storePassword = "nopassword";
148
149 server = new Http1TestServer(
150 IOReactorConfig.custom()
151 .setSoTimeout(TIMEOUT)
152 .build(),
153 SSLContextBuilder.create()
154 .setProvider(securityProvider)
155 .setKeyStoreType("pkcs12")
156 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
157 .loadKeyMaterial(keyStoreURL, storePassword.toCharArray(), storePassword.toCharArray())
158 .setSecureRandom(new SecureRandom())
159 .build(),
160 new SSLSessionInitializer() {
161
162 @Override
163 public void initialize(final NamedEndpoint endpoint, final SSLEngine sslEngine) {
164 if (protocolVersion != null) {
165 sslEngine.setEnabledProtocols(new String[]{protocolVersion});
166 }
167 }
168
169 },
170 null);
171 }
172
173 @Override
174 protected void after() {
175 log.debug("Shutting down test server");
176 if (server != null) {
177 server.shutdown(TimeValue.ofSeconds(5));
178 }
179 }
180
181 }).around(new ExternalResource() {
182
183 @Override
184 protected void before() throws Throwable {
185 log.debug("Starting up test client");
186
187 final URL keyStoreURL = getClass().getResource("/test-client.p12");
188 final String storePassword = "nopassword";
189
190 client = new Http1TestClient(
191 IOReactorConfig.custom()
192 .setSoTimeout(TIMEOUT)
193 .build(),
194 SSLContextBuilder.create()
195 .setProvider(securityProvider)
196 .setKeyStoreType("pkcs12")
197 .loadTrustMaterial(keyStoreURL, storePassword.toCharArray())
198 .setSecureRandom(new SecureRandom())
199 .build(),
200 new SSLSessionInitializer() {
201
202 @Override
203 public void initialize(final NamedEndpoint endpoint, final SSLEngine sslEngine) {
204 if (protocolVersion != null) {
205 sslEngine.setEnabledProtocols(new String[]{protocolVersion});
206 }
207 }
208
209 },
210 null);
211 }
212
213 @Override
214 protected void after() {
215 log.debug("Shutting down test client");
216 if (client != null) {
217 client.shutdown(TimeValue.ofSeconds(5));
218 }
219 }
220
221 });
222
223 private URI createRequestURI(final InetSocketAddress serverEndpoint, final String path) {
224 try {
225 return new URI("https", null, "localhost", serverEndpoint.getPort(), path, null, null);
226 } catch (final URISyntaxException e) {
227 throw new IllegalStateException();
228 }
229 }
230
231 @Test
232 public void testSimpleGet() throws Exception {
233 server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
234
235 @Override
236 public AsyncServerExchangeHandler get() {
237 return new SingleLineResponseHandler("Hi there");
238 }
239
240 });
241 final InetSocketAddress serverEndpoint = server.start();
242
243 client.start();
244 final Future<ClientSessionEndpoint> connectFuture = client.connect(
245 "localhost", serverEndpoint.getPort(), TIMEOUT);
246 final ClientSessionEndpoint streamEndpoint = connectFuture.get();
247
248 for (int i = 0; i < REQ_NUM; i++) {
249 final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
250 new BasicRequestProducer(Method.GET, createRequestURI(serverEndpoint, "/hello")),
251 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
252 final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
253 Assert.assertNotNull(result);
254 final HttpResponse response1 = result.getHead();
255 final String entity1 = result.getBody();
256 Assert.assertNotNull(response1);
257 Assert.assertEquals(200, response1.getCode());
258 Assert.assertEquals("Hi there", entity1);
259 }
260 }
261
262 @Test
263 public void testSimpleGetConnectionClose() throws Exception {
264 server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
265
266 @Override
267 public AsyncServerExchangeHandler get() {
268 return new SingleLineResponseHandler("Hi there");
269 }
270
271 });
272 final InetSocketAddress serverEndpoint = server.start();
273
274 client.start();
275 final URI requestURI = createRequestURI(serverEndpoint, "/hello");
276 for (int i = 0; i < REQ_NUM; i++) {
277 final Future<ClientSessionEndpoint> connectFuture = client.connect(
278 "localhost", serverEndpoint.getPort(), TIMEOUT);
279 try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) {
280 final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
281 AsyncRequestBuilder.get(requestURI)
282 .addHeader(HttpHeaders.CONNECTION, "close")
283 .build(),
284 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
285 final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
286 Assert.assertNotNull(result);
287 final HttpResponse response1 = result.getHead();
288 final String entity1 = result.getBody();
289 Assert.assertNotNull(response1);
290 Assert.assertEquals(200, response1.getCode());
291 Assert.assertEquals("Hi there", entity1);
292 }
293 }
294 }
295
296 @Test
297 public void testSimpleGetIdentityTransfer() throws Exception {
298 server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
299
300 @Override
301 public AsyncServerExchangeHandler get() {
302 return new SingleLineResponseHandler("Hi there");
303 }
304
305 });
306 final HttpProcessor httpProcessor = new DefaultHttpProcessor(new RequestValidateHost());
307 final InetSocketAddress serverEndpoint = server.start(httpProcessor, Http1Config.DEFAULT);
308
309 client.start();
310
311 for (int i = 0; i < REQ_NUM; i++) {
312 final Future<ClientSessionEndpoint> connectFuture = client.connect(
313 "localhost", serverEndpoint.getPort(), TIMEOUT);
314 try (final ClientSessionEndpoint streamEndpoint = connectFuture.get()) {
315 final Future<Message<HttpResponse, String>> future = streamEndpoint.execute(
316 new BasicRequestProducer(Method.GET, createRequestURI(serverEndpoint, "/hello")),
317 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
318 final Message<HttpResponse, String> result = future.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
319 Assert.assertNotNull(result);
320 final HttpResponse response = result.getHead();
321 final String entity = result.getBody();
322 Assert.assertNotNull(response);
323 Assert.assertEquals(200, response.getCode());
324 Assert.assertEquals("Hi there", entity);
325 }
326 }
327 }
328
329 }