cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [cxf] 01/02: CXF-7744 - CXF clients do not fall back to use the javax.net.ssl.trustStore System property
Date Fri, 25 May 2018 16:08:38 GMT
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit fe709de68e80e42edae1a6cea27d6ec0c05ff9d7
Author: Colm O hEigeartaigh <coheigea@apache.org>
AuthorDate: Fri May 25 15:47:48 2018 +0100

    CXF-7744 - CXF clients do not fall back to use the javax.net.ssl.trustStore System property
---
 .../apache/cxf/configuration/jsse/SSLUtils.java    | 93 +++++++++++++++++++++-
 .../configuration/jsse/TLSParameterJaxBUtils.java  | 13 ++-
 .../org/apache/cxf/transport/https/SSLUtils.java   |  9 ++-
 .../cxf/systest/https/trust/TrustManagerTest.java  | 66 +++++++++++++++
 .../systest/https/trust/client-trust-config.xml    | 32 ++++++++
 .../https/trust/client-trust-empty-config.xml      | 36 +++++++++
 6 files changed, 242 insertions(+), 7 deletions(-)

diff --git a/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java b/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java
index 49eb6ed..f889541 100644
--- a/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java
+++ b/core/src/main/java/org/apache/cxf/configuration/jsse/SSLUtils.java
@@ -43,9 +43,13 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.SystemPropertyAction;
 import org.apache.cxf.configuration.security.FiltersType;
+import org.apache.cxf.resource.ResourceManager;
 
 
 /**
@@ -96,16 +100,24 @@ public final class SSLUtils {
         String location = getKeystore(null, log);
         String keyStorePassword = getKeystorePassword(null, log);
         String keyPassword = getKeyPassword(null, log);
+        String keyStoreType = getKeystoreType(null, log);
         InputStream is = null;
 
         try {
-            File file = new File(location);
-            if (file.exists()) {
+            if (location != null) {
+                File file = new File(location);
+                if (file.exists()) {
+                    is = Files.newInputStream(file.toPath());
+                } else {
+                    is = getResourceAsStream(location);
+                }
+            }
+
+            if (is != null) {
                 KeyManagerFactory kmf =
                     KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-                KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+                KeyStore ks = KeyStore.getInstance(keyStoreType != null ? keyStoreType :
KeyStore.getDefaultType());
 
-                is = Files.newInputStream(file.toPath());
                 ks.load(is, (keyStorePassword != null) ? keyStorePassword.toCharArray() :
null);
                 kmf.init(ks, (keyPassword != null) ? keyPassword.toCharArray() : null);
                 defaultManagers = kmf.getKeyManagers();
@@ -127,6 +139,63 @@ public final class SSLUtils {
         }
     }
 
+    // We don't cache the default TrustStore managers here (see above) for backwards compatibility
reasons
+    // We also return null rather than an empty array in case this changes using the default
trust managers when
+    // initing the SSLContext
+    public static TrustManager[] getDefaultTrustStoreManagers(Logger log) {
+        String location = getTruststore(null, log);
+        String trustStorePassword = getTruststorePassword(null, log);
+        String trustStoreType = getTrustStoreType(null, log, DEFAULT_TRUST_STORE_TYPE);
+        InputStream is = null;
+
+        try {
+            if (location != null) {
+                File file = new File(location);
+                if (file.exists()) {
+                    is = Files.newInputStream(file.toPath());
+                } else {
+                    is = getResourceAsStream(location);
+                }
+            }
+            
+            if (is != null) {
+                TrustManagerFactory tmf =
+                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                KeyStore ks = KeyStore.getInstance(trustStoreType);
+
+                ks.load(is, (trustStorePassword != null) ? trustStorePassword.toCharArray()
: null);
+                tmf.init(ks);
+                return tmf.getTrustManagers();
+            } else {
+                log.log(Level.FINER, "No default trust keystore {0}", location);
+            }
+        } catch (Exception e) {
+            log.log(Level.WARNING, "Default trust managers cannot be initialized: " + e.getMessage(),
e);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    log.warning("Keystore stream cannot be closed: " + e.getMessage());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private static InputStream getResourceAsStream(String resource) {
+        InputStream is = ClassLoaderUtils.getResourceAsStream(resource, SSLUtils.class);
+        if (is == null) {
+            Bus bus = BusFactory.getThreadDefaultBus(true);
+            ResourceManager rm = bus.getExtension(ResourceManager.class);
+            if (rm != null) {
+                is = rm.getResourceAsStream(resource);
+            }
+        }
+        return is;
+    }
+
     public static KeyManager[] loadKeyStore(KeyManagerFactory kmf,
                                                KeyStore ks,
                                                ByteArrayInputStream bin,
@@ -431,6 +500,22 @@ public final class SSLUtils {
         return cipherSuites;
     }
 
+    public static String getTruststore(String trustStoreLocation, Logger log) {
+        String logMsg = null;
+        if (trustStoreLocation != null) {
+            logMsg = "TRUST_STORE_SET";
+        } else {
+            trustStoreLocation = SystemPropertyAction.getProperty("javax.net.ssl.trustStore");
+            if (trustStoreLocation != null) {
+                logMsg = "TRUST_STORE_SYSTEM_PROPERTY_SET";
+            } else {
+                logMsg = "TRUST_STORE_NOT_SET";
+            }
+        }
+        LogUtils.log(log, Level.FINE, logMsg, trustStoreLocation);
+        return trustStoreLocation;
+    }
+
     public static String getTrustStoreType(String trustStoreType, Logger log) {
         return getTrustStoreType(trustStoreType, log, DEFAULT_TRUST_STORE_TYPE);
     }
diff --git a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
index 58fc21b..cba8742 100644
--- a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
+++ b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Paths;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
@@ -163,10 +164,20 @@ public final class TLSParameterJaxBUtils {
         } else if (kst.isSetUrl()) {
             keyStore.load(new URL(kst.getUrl()).openStream(), password);
         } else {
-            String loc = SSLUtils.getKeystore(null, LOG);
+            String loc = null;
+            if (trustStore) {
+                loc = SSLUtils.getTruststore(null, LOG);
+            } else {
+                loc = SSLUtils.getKeystore(null, LOG);
+            }
             if (loc != null) {
                 try (InputStream ins = Files.newInputStream(Paths.get(loc))) {
                     keyStore.load(ins, password);
+                } catch (NoSuchFileException ex) {
+                    // Fall back to load the location as a stream
+                    try (InputStream ins = getResourceAsStream(loc)) {
+                        keyStore.load(ins, password);
+                    }
                 }
             }
         }
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
index 48a4b7c..8db57de 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
@@ -26,6 +26,7 @@ import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509KeyManager;
 
 import org.apache.cxf.common.logging.LogUtils;
@@ -78,8 +79,12 @@ public final class SSLUtils {
         }
         configureKeyManagersWithCertAlias(parameters, keyManagers);
 
-        ctx.init(keyManagers, parameters.getTrustManagers(),
-                 parameters.getSecureRandom());
+        TrustManager[] trustManagers = parameters.getTrustManagers();
+        if (trustManagers == null && parameters instanceof TLSClientParameters) {
+            trustManagers = org.apache.cxf.configuration.jsse.SSLUtils.getDefaultTrustStoreManagers(LOG);
+        }
+
+        ctx.init(keyManagers, trustManagers, parameters.getSecureRandom());
 
         return ctx;
     }
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/https/trust/TrustManagerTest.java
b/systests/transports/src/test/java/org/apache/cxf/systest/https/trust/TrustManagerTest.java
index 4cc75fd..f9edba0 100644
--- a/systests/transports/src/test/java/org/apache/cxf/systest/https/trust/TrustManagerTest.java
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/https/trust/TrustManagerTest.java
@@ -150,6 +150,72 @@ public class TrustManagerTest extends AbstractBusClientServerTestBase
{
         bus.shutdown(true);
     }
 
+    // Here we're using spring config but getting the truststore from the standard system
properties
+    @org.junit.Test
+    public void testSystemPropertiesWithEmptyTLSClientParametersConfig() throws Exception
{
+        try {
+            System.setProperty("javax.net.ssl.trustStore", "keys/Bethal.jks");
+            System.setProperty("javax.net.ssl.trustStorePassword", "password");
+            System.setProperty("javax.net.ssl.trustStoreType", "JKS");
+            SpringBusFactory bf = new SpringBusFactory();
+            URL busFile = TrustManagerTest.class.getResource("client-trust-config.xml");
+
+            Bus bus = bf.createBus(busFile.toString());
+            BusFactory.setDefaultBus(bus);
+            BusFactory.setThreadDefaultBus(bus);
+
+            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);
+
+            assertEquals(port.greetMe("Kitty"), "Hello Kitty");
+
+            ((java.io.Closeable)port).close();
+            bus.shutdown(true);
+        } finally {
+            System.clearProperty("javax.net.ssl.trustStore");
+            System.clearProperty("javax.net.ssl.trustStorePassword");
+            System.clearProperty("javax.net.ssl.trustStoreType");
+        }
+    }
+
+    // Here we're using spring config but getting the truststore from the standard system
properties
+    @org.junit.Test
+    public void testSystemPropertiesWithEmptyKeystoreConfig() throws Exception {
+        try {
+            System.setProperty("javax.net.ssl.trustStore", "keys/Bethal.jks");
+            System.setProperty("javax.net.ssl.trustStorePassword", "password");
+            System.setProperty("javax.net.ssl.trustStoreType", "JKS");
+            SpringBusFactory bf = new SpringBusFactory();
+            URL busFile = TrustManagerTest.class.getResource("client-trust-empty-config.xml");
+
+            Bus bus = bf.createBus(busFile.toString());
+            BusFactory.setDefaultBus(bus);
+            BusFactory.setThreadDefaultBus(bus);
+
+            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);
+
+            assertEquals(port.greetMe("Kitty"), "Hello Kitty");
+
+            ((java.io.Closeable)port).close();
+            bus.shutdown(true);
+        } finally {
+            System.clearProperty("javax.net.ssl.trustStore");
+            System.clearProperty("javax.net.ssl.trustStorePassword");
+            System.clearProperty("javax.net.ssl.trustStoreType");
+        }
+    }
+
     // Here the Trust Manager checks the server cert. this time we are invoking on the
     // service that is configured in code (not by spring)
     @org.junit.Test
diff --git a/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-config.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-config.xml
new file mode 100644
index 0000000..5feb0c2
--- /dev/null
+++ b/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="           http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-b
[...]
+    
+    <cxf:bus>
+        <cxf:features>
+            <cxf:logging/>
+        </cxf:features>
+    </cxf:bus>
+    
+    <http:conduit name="https://localhost:.*">
+        <http:tlsClientParameters disableCNCheck="true" />
+    </http:conduit>
+    
+</beans>
diff --git a/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-empty-config.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-empty-config.xml
new file mode 100644
index 0000000..1f6eb1f
--- /dev/null
+++ b/systests/transports/src/test/resources/org/apache/cxf/systest/https/trust/client-trust-empty-config.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="           http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-b
[...]
+    
+    <cxf:bus>
+        <cxf:features>
+            <cxf:logging/>
+        </cxf:features>
+    </cxf:bus>
+    
+    <http:conduit name="https://localhost:.*">
+        <http:tlsClientParameters disableCNCheck="true">
+            <sec:trustManagers>
+                <sec:keyStore/>
+            </sec:trustManagers>
+        </http:tlsClientParameters>
+    </http:conduit>
+    
+</beans>

-- 
To stop receiving notification emails like this one, please contact
coheigea@apache.org.

Mime
View raw message