|
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; |
|
109 | 104 | import lucee.runtime.PageContextImpl; |
110 | 105 | import lucee.runtime.engine.ThreadLocalPageContext; |
111 | 106 | import lucee.runtime.net.http.ReqRspUtil; |
| 107 | +import lucee.runtime.net.http.SSLUtil; |
112 | 108 | import lucee.runtime.net.http.sni.DefaultHostnameVerifierImpl; |
113 | 109 | import lucee.runtime.net.http.sni.DefaultHttpClientConnectionOperatorImpl; |
114 | 110 | import lucee.runtime.net.http.sni.SSLConnectionSocketFactoryImpl; |
@@ -271,9 +267,9 @@ private static Header toHeader(lucee.commons.net.http.Header header) { |
271 | 267 | return new HeaderImpl(header.getName(), header.getValue()); |
272 | 268 | } |
273 | 269 |
|
274 | | - public static HttpClientBuilder getHttpClientBuilder(boolean pooling, String clientCert, String clientCertPassword, String redirect) throws GeneralSecurityException, IOException { |
275 | | - String key = clientCert + ":" + clientCertPassword; |
276 | | - Registry<ConnectionSocketFactory> reg = StringUtil.isEmpty(clientCert, true) ? createRegistry() : createRegistry(clientCert, clientCertPassword); |
| 270 | + public static HttpClientBuilder getHttpClientBuilder(boolean pooling, String clientCert, String clientCertPassword, String trustStore, String trustStorePassword, boolean sslVerify, String redirect) throws GeneralSecurityException { |
| 271 | + String key = clientCert + ":" + clientCertPassword + ":" + trustStore + ":" + trustStorePassword + ":" + sslVerify; |
| 272 | + Registry<ConnectionSocketFactory> reg = createRegistry( clientCert, clientCertPassword, trustStore, trustStorePassword, sslVerify ); |
277 | 273 |
|
278 | 274 | if (!pooling) { |
279 | 275 | HttpClientBuilder builder = HttpClients.custom(); |
@@ -328,31 +324,43 @@ public static void setTimeout(HttpClientBuilder builder, TimeSpan timeout) { |
328 | 324 | builder.setDefaultRequestConfig(rcBuilder.build()); |
329 | 325 | } |
330 | 326 |
|
331 | | - private static Registry<ConnectionSocketFactory> createRegistry() throws GeneralSecurityException { |
332 | | - SSLContext sslcontext = SSLContext.getInstance("TLS"); |
333 | | - sslcontext.init(null, null, new java.security.SecureRandom()); |
334 | | - SSLConnectionSocketFactory defaultsslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl()); |
335 | | - /* Register connection handlers */ |
336 | | - return RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", defaultsslsf).build(); |
| 327 | + private static Registry<ConnectionSocketFactory> createRegistry( String clientCert, String clientCertPassword, String trustStore, String trustStorePassword, boolean sslVerify ) throws GeneralSecurityException { |
| 328 | + SSLContext sslContext; |
| 329 | + HostnameVerifier hostnameVerifier; |
337 | 330 |
|
338 | | - } |
| 331 | + try { |
| 332 | + Path clientCertPath = StringUtil.isEmpty( clientCert, true ) ? null : Paths.get( clientCert ); |
| 333 | + char[] clientPassword = clientCertPassword != null ? clientCertPassword.toCharArray() : null; |
| 334 | + |
| 335 | + if ( !sslVerify ) { |
| 336 | + // Disable all SSL verification (like curl -k) |
| 337 | + sslContext = SSLUtil.createUnsafeSSLContext( clientCertPath, clientPassword ); |
| 338 | + hostnameVerifier = NoopHostnameVerifier.INSTANCE; |
| 339 | + } |
| 340 | + else if ( !StringUtil.isEmpty( trustStore, true ) ) { |
| 341 | + // Use custom trust store |
| 342 | + Path trustStorePath = Paths.get( trustStore ); |
| 343 | + char[] trustPassword = trustStorePassword != null ? trustStorePassword.toCharArray() : "changeit".toCharArray(); |
| 344 | + List<SSLUtil.TrustStoreConfig> additionalTrustStores = new ArrayList<>(); |
| 345 | + additionalTrustStores.add( new SSLUtil.TrustStoreConfig( trustStorePath, trustPassword ) ); |
| 346 | + sslContext = SSLUtil.createSSLContext( clientCertPath, clientPassword, additionalTrustStores ); |
| 347 | + hostnameVerifier = new DefaultHostnameVerifierImpl(); |
| 348 | + } |
| 349 | + else { |
| 350 | + // Standard mode with JVM + custom-cacerts |
| 351 | + sslContext = SSLUtil.createSSLContext( clientCertPath, clientPassword ); |
| 352 | + hostnameVerifier = new DefaultHostnameVerifierImpl(); |
| 353 | + } |
| 354 | + } |
| 355 | + catch ( IOException e ) { |
| 356 | + throw new GeneralSecurityException( "Failed to create SSL context", e ); |
| 357 | + } |
339 | 358 |
|
340 | | - private static Registry<ConnectionSocketFactory> createRegistry(String clientCert, String clientCertPassword) |
341 | | - throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { |
342 | | - // Currently, clientCert force usePool to being ignored |
343 | | - if (clientCertPassword == null) clientCertPassword = ""; |
344 | | - // Load the client cert |
345 | | - File ksFile = new File(clientCert); |
346 | | - KeyStore clientStore = KeyStore.getInstance("PKCS12"); |
347 | | - clientStore.load(new FileInputStream(ksFile), clientCertPassword.toCharArray()); |
348 | | - // Prepare the keys |
349 | | - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
350 | | - kmf.init(clientStore, clientCertPassword.toCharArray()); |
351 | | - SSLContext sslcontext = SSLContext.getInstance("TLS"); |
352 | | - // Configure the socket factory |
353 | | - sslcontext.init(kmf.getKeyManagers(), null, new java.security.SecureRandom()); |
354 | | - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl(sslcontext, new DefaultHostnameVerifierImpl()); |
355 | | - return RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build(); |
| 359 | + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactoryImpl( sslContext, hostnameVerifier ); |
| 360 | + return RegistryBuilder.<ConnectionSocketFactory>create() |
| 361 | + .register( "http", PlainConnectionSocketFactory.getSocketFactory() ) |
| 362 | + .register( "https", sslsf ) |
| 363 | + .build(); |
356 | 364 | } |
357 | 365 |
|
358 | 366 | public static void releaseConnectionManager() { |
@@ -392,7 +400,7 @@ private static HTTPResponse invoke(URL url, HttpUriRequest request, String usern |
392 | 400 | CloseableHttpClient client; |
393 | 401 | proxy = ProxyDataImpl.validate(proxy, url.getHost()); |
394 | 402 |
|
395 | | - HttpClientBuilder builder = getHttpClientBuilder(pooling, null, null, String.valueOf(redirect)); |
| 403 | + HttpClientBuilder builder = getHttpClientBuilder(pooling, null, null, null, null, true, String.valueOf(redirect)); |
396 | 404 |
|
397 | 405 | HttpHost hh = new HttpHost(url.getHost(), url.getPort()); |
398 | 406 | setHeader(request, headers); |
|
0 commit comments