|
18 | 18 | **/ |
19 | 19 | package lucee.commons.net.http.httpclient; |
20 | 20 |
|
21 | | -import java.io.File; |
22 | | -import java.io.FileInputStream; |
23 | 21 | import java.io.IOException; |
24 | 22 | import java.io.InputStream; |
25 | 23 | import java.lang.reflect.Field; |
26 | 24 | import java.net.URL; |
| 25 | +import java.nio.file.Path; |
| 26 | +import java.nio.file.Paths; |
27 | 27 | import java.security.GeneralSecurityException; |
28 | | -import java.security.KeyManagementException; |
29 | | -import java.security.KeyStore; |
30 | | -import java.security.KeyStoreException; |
31 | | -import java.security.NoSuchAlgorithmException; |
32 | | -import java.security.UnrecoverableKeyException; |
33 | | -import java.security.cert.CertificateException; |
34 | 28 | import java.util.ArrayList; |
35 | 29 | import java.util.Collection; |
36 | 30 | import java.util.Iterator; |
|
41 | 35 | import java.util.concurrent.TimeUnit; |
42 | 36 | import java.util.concurrent.atomic.AtomicBoolean; |
43 | 37 |
|
44 | | -import javax.net.ssl.KeyManagerFactory; |
| 38 | +import javax.net.ssl.HostnameVerifier; |
45 | 39 | import javax.net.ssl.SSLContext; |
46 | 40 |
|
47 | 41 | import org.apache.http.Header; |
|
73 | 67 | import org.apache.http.conn.HttpClientConnectionManager; |
74 | 68 | import org.apache.http.conn.socket.ConnectionSocketFactory; |
75 | 69 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; |
| 70 | +import org.apache.http.conn.ssl.NoopHostnameVerifier; |
76 | 71 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
77 | 72 | import org.apache.http.entity.ByteArrayEntity; |
78 | 73 | import org.apache.http.entity.ContentType; |
|
110 | 105 | import lucee.runtime.PageContextImpl; |
111 | 106 | import lucee.runtime.engine.ThreadLocalPageContext; |
112 | 107 | import lucee.runtime.net.http.ReqRspUtil; |
| 108 | +import lucee.runtime.net.http.SSLUtil; |
113 | 109 | import lucee.runtime.net.http.sni.DefaultHostnameVerifierImpl; |
114 | 110 | import lucee.runtime.net.http.sni.DefaultHttpClientConnectionOperatorImpl; |
115 | 111 | import lucee.runtime.net.http.sni.SSLConnectionSocketFactoryImpl; |
@@ -272,10 +268,9 @@ private static Header toHeader(lucee.commons.net.http.Header header) { |
272 | 268 | return new HeaderImpl(header.getName(), header.getValue()); |
273 | 269 | } |
274 | 270 |
|
275 | | - public static HttpClientBuilder getHttpClientBuilder(boolean pooling, String clientCert, String clientCertPassword, String redirect) |
276 | | - throws GeneralSecurityException, IOException { |
277 | | - String key = clientCert + ":" + clientCertPassword; |
278 | | - Registry<ConnectionSocketFactory> reg = StringUtil.isEmpty(clientCert, true) ? createRegistry() : createRegistry(clientCert, clientCertPassword); |
| 271 | + public static HttpClientBuilder getHttpClientBuilder(boolean pooling, String clientCert, String clientCertPassword, String trustStore, String trustStorePassword, boolean sslVerify, String redirect) throws GeneralSecurityException { |
| 272 | + String key = clientCert + ":" + clientCertPassword + ":" + trustStore + ":" + trustStorePassword + ":" + sslVerify; |
| 273 | + Registry<ConnectionSocketFactory> reg = createRegistry( clientCert, clientCertPassword, trustStore, trustStorePassword, sslVerify ); |
279 | 274 |
|
280 | 275 | if (!pooling) { |
281 | 276 | HttpClientBuilder builder = HttpClients.custom(); |
@@ -331,31 +326,43 @@ public static void setTimeout(HttpClientBuilder builder, TimeSpan timeout) { |
331 | 326 | builder.setDefaultRequestConfig(rcBuilder.build()); |
332 | 327 | } |
333 | 328 |
|
334 | | - private static Registry<ConnectionSocketFactory> createRegistry() throws GeneralSecurityException { |
335 | | - SSLContext sslcontext = SSLContext.getInstance("TLS"); |
336 | | - sslcontext.init(null, null, new java.security.SecureRandom()); |
337 | | - SSLConnectionSocketFactory defaultsslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl()); |
338 | | - /* Register connection handlers */ |
339 | | - return RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", defaultsslsf).build(); |
| 329 | + private static Registry<ConnectionSocketFactory> createRegistry( String clientCert, String clientCertPassword, String trustStore, String trustStorePassword, boolean sslVerify ) throws GeneralSecurityException { |
| 330 | + SSLContext sslContext; |
| 331 | + HostnameVerifier hostnameVerifier; |
340 | 332 |
|
341 | | - } |
| 333 | + try { |
| 334 | + Path clientCertPath = StringUtil.isEmpty( clientCert, true ) ? null : Paths.get( clientCert ); |
| 335 | + char[] clientPassword = clientCertPassword != null ? clientCertPassword.toCharArray() : null; |
| 336 | + |
| 337 | + if ( !sslVerify ) { |
| 338 | + // Disable all SSL verification (like curl -k) |
| 339 | + sslContext = SSLUtil.createUnsafeSSLContext( clientCertPath, clientPassword ); |
| 340 | + hostnameVerifier = NoopHostnameVerifier.INSTANCE; |
| 341 | + } |
| 342 | + else if ( !StringUtil.isEmpty( trustStore, true ) ) { |
| 343 | + // Use custom trust store |
| 344 | + Path trustStorePath = Paths.get( trustStore ); |
| 345 | + char[] trustPassword = trustStorePassword != null ? trustStorePassword.toCharArray() : "changeit".toCharArray(); |
| 346 | + List<SSLUtil.TrustStoreConfig> additionalTrustStores = new ArrayList<>(); |
| 347 | + additionalTrustStores.add( new SSLUtil.TrustStoreConfig( trustStorePath, trustPassword ) ); |
| 348 | + sslContext = SSLUtil.createSSLContext( clientCertPath, clientPassword, additionalTrustStores ); |
| 349 | + hostnameVerifier = new DefaultHostnameVerifierImpl(); |
| 350 | + } |
| 351 | + else { |
| 352 | + // Standard mode with JVM + custom-cacerts |
| 353 | + sslContext = SSLUtil.createSSLContext( clientCertPath, clientPassword ); |
| 354 | + hostnameVerifier = new DefaultHostnameVerifierImpl(); |
| 355 | + } |
| 356 | + } |
| 357 | + catch ( IOException e ) { |
| 358 | + throw new GeneralSecurityException( "Failed to create SSL context", e ); |
| 359 | + } |
342 | 360 |
|
343 | | - private static Registry<ConnectionSocketFactory> createRegistry(String clientCert, String clientCertPassword) |
344 | | - throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { |
345 | | - // Currently, clientCert force usePool to being ignored |
346 | | - if (clientCertPassword == null) clientCertPassword = ""; |
347 | | - // Load the client cert |
348 | | - File ksFile = new File(clientCert); |
349 | | - KeyStore clientStore = KeyStore.getInstance("PKCS12"); |
350 | | - clientStore.load(new FileInputStream(ksFile), clientCertPassword.toCharArray()); |
351 | | - // Prepare the keys |
352 | | - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
353 | | - kmf.init(clientStore, clientCertPassword.toCharArray()); |
354 | | - SSLContext sslcontext = SSLContext.getInstance("TLS"); |
355 | | - // Configure the socket factory |
356 | | - sslcontext.init(kmf.getKeyManagers(), null, new java.security.SecureRandom()); |
357 | | - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl()); |
358 | | - return RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build(); |
| 361 | + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl( sslContext, hostnameVerifier ); |
| 362 | + return RegistryBuilder.<ConnectionSocketFactory>create() |
| 363 | + .register( "http", PlainConnectionSocketFactory.getSocketFactory() ) |
| 364 | + .register( "https", sslsf ) |
| 365 | + .build(); |
359 | 366 | } |
360 | 367 |
|
361 | 368 | public static void releaseConnectionManager() { |
@@ -399,7 +406,7 @@ private static HTTPResponse invoke(URL url, HttpUriRequest request, String usern |
399 | 406 | CloseableHttpClient client; |
400 | 407 | proxy = ProxyDataImpl.validate(proxy, url.getHost()); |
401 | 408 |
|
402 | | - HttpClientBuilder builder = getHttpClientBuilder(pooling, null, null, String.valueOf(redirect)); |
| 409 | + HttpClientBuilder builder = getHttpClientBuilder(pooling, null, null, null, null, true, String.valueOf(redirect)); |
403 | 410 |
|
404 | 411 | HttpHost hh = new HttpHost(url.getHost(), url.getPort()); |
405 | 412 | setHeader(request, headers); |
|
0 commit comments