This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch 3.2.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/3.2.x-fixes by this push: new 00fa31e CXF-5077 - Provide a way to define a specific SSLContext to be used by HTTPConduit implementations 00fa31e is described below commit 00fa31ef54423cb1d05650e16d6b813f1b968bc0 Author: Colm O hEigeartaigh <cohei...@apache.org> AuthorDate: Tue Sep 11 11:34:15 2018 +0100 CXF-5077 - Provide a way to define a specific SSLContext to be used by HTTPConduit implementations (cherry picked from commit 6db38f9984b9c0bf6309a3d7e26d5a9ab8055d1f) --- .../configuration/jsse/TLSClientParameters.java | 20 +++++ .../http/asyncclient/AsyncHTTPConduit.java | 38 +++++---- .../transport/https/HttpsURLConnectionFactory.java | 18 ++-- .../systest/https/clientauth/ClientAuthTest.java | 98 ++++++++++++++++++++++ 4 files changed, 151 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java index 51b85b6..6f4b0f4 100644 --- a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java +++ b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java @@ -21,6 +21,7 @@ package org.apache.cxf.configuration.jsse; import java.util.List; import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; /** @@ -35,6 +36,7 @@ public class TLSClientParameters extends TLSParameterBase { private boolean useHttpsURLConnectionDefaultSslSocketFactory; private boolean useHttpsURLConnectionDefaultHostnameVerifier; private HostnameVerifier hostnameVerifier; + private SSLContext sslContext; /** * Set custom HostnameVerifier @@ -147,6 +149,9 @@ public class TLSClientParameters extends TLSParameterBase { if (sslSocketFactory != null) { hash = hash * 41 + System.identityHashCode(sslSocketFactory); } + if (sslContext != null) { + hash = hash * 41 + System.identityHashCode(sslContext); + } hash = hash(hash, useHttpsURLConnectionDefaultSslSocketFactory); hash = hash(hash, useHttpsURLConnectionDefaultHostnameVerifier); hash = hash(hash, sslCacheTimeout); @@ -193,6 +198,7 @@ public class TLSClientParameters extends TLSParameterBase { TLSClientParameters that = (TLSClientParameters)o; boolean eq = disableCNCheck == that.disableCNCheck; eq &= sslSocketFactory == that.sslSocketFactory; + eq &= sslContext == that.sslContext; eq &= useHttpsURLConnectionDefaultSslSocketFactory == that.useHttpsURLConnectionDefaultSslSocketFactory; eq &= useHttpsURLConnectionDefaultHostnameVerifier == that.useHttpsURLConnectionDefaultHostnameVerifier; eq &= sslCacheTimeout == that.sslCacheTimeout; @@ -258,4 +264,18 @@ public class TLSClientParameters extends TLSParameterBase { } return false; } + + /** + * Get the SSLContext parameter to use (if it has been set) + */ + public SSLContext getSslContext() { + return sslContext; + } + + /** + * Set an SSLContext parameter to use to create https connections + */ + public void setSslContext(SSLContext sslContext) { + this.sslContext = sslContext; + } } diff --git a/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java b/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java index 9c55b60..7df19ce 100755 --- a/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java +++ b/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java @@ -880,25 +880,31 @@ public class AsyncHTTPConduit extends URLConnectionHTTPConduit { return sslContext; } - String provider = tlsClientParameters.getJsseProvider(); + SSLContext ctx = null; + if (tlsClientParameters.getSslContext() != null) { + ctx = tlsClientParameters.getSslContext(); + } else { + String provider = tlsClientParameters.getJsseProvider(); - String protocol = tlsClientParameters.getSecureSocketProtocol() != null ? tlsClientParameters - .getSecureSocketProtocol() : "TLS"; + String protocol = tlsClientParameters.getSecureSocketProtocol() != null ? tlsClientParameters + .getSecureSocketProtocol() : "TLS"; - SSLContext ctx = provider == null ? SSLContext.getInstance(protocol) : SSLContext - .getInstance(protocol, provider); - ctx.getClientSessionContext().setSessionTimeout(tlsClientParameters.getSslCacheTimeout()); + ctx = provider == null ? SSLContext.getInstance(protocol) : SSLContext + .getInstance(protocol, provider); + ctx.getClientSessionContext().setSessionTimeout(tlsClientParameters.getSslCacheTimeout()); - KeyManager[] keyManagers = tlsClientParameters.getKeyManagers(); - KeyManager[] configuredKeyManagers = org.apache.cxf.transport.https.SSLUtils.configureKeyManagersWithCertAlias( - tlsClientParameters, keyManagers); + KeyManager[] keyManagers = tlsClientParameters.getKeyManagers(); + KeyManager[] configuredKeyManagers = + org.apache.cxf.transport.https.SSLUtils.configureKeyManagersWithCertAlias( + tlsClientParameters, keyManagers); - TrustManager[] trustManagers = tlsClientParameters.getTrustManagers(); - if (trustManagers == null) { - trustManagers = org.apache.cxf.configuration.jsse.SSLUtils.getDefaultTrustStoreManagers(LOG); - } + TrustManager[] trustManagers = tlsClientParameters.getTrustManagers(); + if (trustManagers == null) { + trustManagers = org.apache.cxf.configuration.jsse.SSLUtils.getDefaultTrustStoreManagers(LOG); + } - ctx.init(configuredKeyManagers, trustManagers, tlsClientParameters.getSecureRandom()); + ctx.init(configuredKeyManagers, trustManagers, tlsClientParameters.getSecureRandom()); + } sslContext = ctx; lastTlsHash = hash; @@ -923,9 +929,9 @@ public class AsyncHTTPConduit extends URLConnectionHTTPConduit { sslengine.setEnabledCipherSuites(cipherSuites); String protocol = tlsClientParameters.getSecureSocketProtocol() != null ? tlsClientParameters - .getSecureSocketProtocol() : "TLS"; + .getSecureSocketProtocol() : sslcontext.getProtocol(); - String p[] = findProtocols(protocol, sslengine.getSupportedProtocols()); + String[] p = findProtocols(protocol, sslengine.getSupportedProtocols()); if (p != null) { sslengine.setEnabledProtocols(p); } diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/HttpsURLConnectionFactory.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/HttpsURLConnectionFactory.java index cced865..5b51b30 100644 --- a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/HttpsURLConnectionFactory.java +++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/HttpsURLConnectionFactory.java @@ -138,11 +138,15 @@ public class HttpsURLConnectionFactory { socketFactory = tlsClientParameters.getSSLSocketFactory(); } else if (socketFactory == null) { - // ssl socket factory not yet instantiated, create a new one with tlsClientParameters's Trust - // Managers, Key Managers, etc - SSLContext ctx = - org.apache.cxf.transport.https.SSLUtils.getSSLContext(tlsClientParameters); + SSLContext ctx = null; + if (tlsClientParameters.getSslContext() != null) { + // Use the SSLContext which was set + ctx = tlsClientParameters.getSslContext(); + } else { + // Create socketfactory with tlsClientParameters's Trust Managers, Key Managers, etc + ctx = org.apache.cxf.transport.https.SSLUtils.getSSLContext(tlsClientParameters); + } String[] cipherSuites = SSLUtils.getCiphersuitesToInclude(tlsClientParameters.getCipherSuites(), @@ -150,10 +154,10 @@ public class HttpsURLConnectionFactory { ctx.getSocketFactory().getDefaultCipherSuites(), SSLUtils.getSupportedCipherSuites(ctx), LOG); - // The SSLSocketFactoryWrapper enables certain cipher suites - // from the policy. + + // The SSLSocketFactoryWrapper enables certain cipher suites from the policy. String protocol = tlsClientParameters.getSecureSocketProtocol() != null ? tlsClientParameters - .getSecureSocketProtocol() : "TLS"; + .getSecureSocketProtocol() : ctx.getProtocol(); socketFactory = new SSLSocketFactoryWrapper(ctx.getSocketFactory(), cipherSuites, protocol); //recalc the hashcode since some of the above MAY have changed the tlsClientParameters diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/https/clientauth/ClientAuthTest.java b/systests/transports/src/test/java/org/apache/cxf/systest/https/clientauth/ClientAuthTest.java index 0160a69..11a7d23 100644 --- a/systests/transports/src/test/java/org/apache/cxf/systest/https/clientauth/ClientAuthTest.java +++ b/systests/transports/src/test/java/org/apache/cxf/systest/https/clientauth/ClientAuthTest.java @@ -35,6 +35,7 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; +import javax.xml.ws.BindingProvider; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; @@ -412,6 +413,103 @@ public class ClientAuthTest extends AbstractBusClientServerTestBase { } } + // Server directly trusts the client cert + @org.junit.Test + public void testDirectTrustUsingKeyManagers() throws Exception { + + URL url = SOAPService.WSDL_LOCATION; + SOAPService service = new SOAPService(url, SOAPService.SERVICE); + assertNotNull("Service is null", service); + final Greeter port = service.getHttpsPort(); + assertNotNull("Port is null", port); + + updateAddressPort(port, PORT); + + // Set up KeyManagers/TrustManagers + KeyStore ts = KeyStore.getInstance("JKS"); + try (InputStream trustStore = + ClassLoaderUtils.getResourceAsStream("keys/Truststore.jks", ClientAuthTest.class)) { + ts.load(trustStore, "password".toCharArray()); + } + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ts); + + KeyStore ks = KeyStore.getInstance("JKS"); + try (InputStream keyStore = + ClassLoaderUtils.getResourceAsStream("keys/Morpit.jks", ClientAuthTest.class)) { + ks.load(keyStore, "password".toCharArray()); + } + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(ks, "password".toCharArray()); + + TLSClientParameters tlsParams = new TLSClientParameters(); + tlsParams.setKeyManagers(kmf.getKeyManagers()); + tlsParams.setTrustManagers(tmf.getTrustManagers()); + tlsParams.setDisableCNCheck(true); + + Client client = ClientProxy.getClient(port); + HTTPConduit http = (HTTPConduit) client.getConduit(); + http.setTlsClientParameters(tlsParams); + + assertEquals(port.greetMe("Kitty"), "Hello Kitty"); + + ((java.io.Closeable)port).close(); + } + + // Server directly trusts the client cert + @org.junit.Test + public void testDirectTrustUsingSSLContext() throws Exception { + + URL url = SOAPService.WSDL_LOCATION; + SOAPService service = new SOAPService(url, SOAPService.SERVICE); + assertNotNull("Service is null", service); + final Greeter port = service.getHttpsPort(); + assertNotNull("Port is null", port); + + updateAddressPort(port, PORT); + + // Set up KeyManagers/TrustManagers + KeyStore ts = KeyStore.getInstance("JKS"); + try (InputStream trustStore = + ClassLoaderUtils.getResourceAsStream("keys/Truststore.jks", ClientAuthTest.class)) { + ts.load(trustStore, "password".toCharArray()); + } + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ts); + + KeyStore ks = KeyStore.getInstance("JKS"); + try (InputStream keyStore = + ClassLoaderUtils.getResourceAsStream("keys/Morpit.jks", ClientAuthTest.class)) { + ks.load(keyStore, "password".toCharArray()); + } + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); + kmf.init(ks, "password".toCharArray()); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new java.security.SecureRandom()); + + TLSClientParameters tlsParams = new TLSClientParameters(); + tlsParams.setSslContext(sslContext); + tlsParams.setDisableCNCheck(true); + + Client client = ClientProxy.getClient(port); + HTTPConduit http = (HTTPConduit) client.getConduit(); + http.setTlsClientParameters(tlsParams); + + assertEquals(port.greetMe("Kitty"), "Hello Kitty"); + + // Enable Async + ((BindingProvider)port).getRequestContext().put("use.async.http.conduit", true); + + assertEquals(port.greetMe("Kitty"), "Hello Kitty"); + + ((java.io.Closeable)port).close(); + } + private static final class DisableCNCheckVerifier implements HostnameVerifier { @Override