changeset 838:38c11c570144

Move SSL related classes from web-client to common-core. This patch moves SSL related classes from the thermostat-web-client bundle to common-core and refactors a few things in preparation for SSL-enabling the cmd-channel. A new KeyStoreProvider class has been introduced in order to load a thermostat keystore file (as configured in ssl.properties). Tests have been added as well. What was formerly client.properties has been renamed to ssl.properties since it more acurately reflects what this config file is used for. Reviewed-by: rkennke Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-December/004557.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Tue, 11 Dec 2012 12:04:58 +0100
parents 15bdfbd07f48
children b99988e68839
files common/core/pom.xml common/core/src/main/java/com/redhat/thermostat/common/internal/CustomX509TrustManager.java common/core/src/main/java/com/redhat/thermostat/common/internal/KeyStoreProvider.java common/core/src/main/java/com/redhat/thermostat/common/internal/SSLKeystoreConfiguration.java common/core/src/main/java/com/redhat/thermostat/common/internal/TrustManagerFactory.java common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLContextFactory.java common/core/src/main/java/com/redhat/thermostat/common/ssl/SslInitException.java common/core/src/test/java/com/redhat/thermostat/common/internal/CustomX509TrustManagerTest.java common/core/src/test/java/com/redhat/thermostat/common/internal/KeyStoreProviderTest.java common/core/src/test/java/com/redhat/thermostat/common/internal/SSLKeystoreConfigurationTest.java common/core/src/test/resources/ca.crt common/core/src/test/resources/client.properties common/core/src/test/resources/empty.keystore common/core/src/test/resources/test_ca.keystore distribution/config/client.properties distribution/config/ssl.properties distribution/pom.xml web/client/src/main/java/com/redhat/thermostat/web/client/internal/CustomX509TrustManager.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/SSLKeystoreConfiguration.java web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/CustomX509TrustManagerTest.java web/client/src/test/java/com/redhat/thermostat/web/client/internal/SSLKeystoreConfigurationTest.java web/client/src/test/resources/ca.crt web/client/src/test/resources/client.properties web/client/src/test/resources/empty.keystore web/client/src/test/resources/test_ca.keystore
diffstat 26 files changed, 933 insertions(+), 626 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/pom.xml	Mon Dec 10 16:52:51 2012 -0500
+++ b/common/core/pom.xml	Tue Dec 11 12:04:58 2012 +0100
@@ -87,7 +87,8 @@
               com.redhat.thermostat.common.dao,
               com.redhat.thermostat.common.utils,
               com.redhat.thermostat.common.heap,
-              com.redhat.thermostat.common.locale
+              com.redhat.thermostat.common.locale,
+              com.redhat.thermostat.common.ssl,
             </Export-Package>
             <Private-Package>
               com.redhat.thermostat.test,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/CustomX509TrustManager.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+/**
+ * Custom X509TrustManager which first attempts to verify peer certificates
+ * using Java's default trust manager. If that fails it uses thermostat's
+ * keystore file (if any) and uses it for another attempt to validate the
+ * server certificate. If that fails as well, the connection is not allowed.
+ * 
+ */
+class CustomX509TrustManager implements X509TrustManager {
+    
+    Logger logger = LoggingUtils.getLogger(CustomX509TrustManager.class);
+
+    /*
+     * The default X509TrustManager returned by SunX509. We'll delegate
+     * decisions to it, and fall back to the logic in this class if the default
+     * X509TrustManager doesn't trust it.
+     */
+    private X509TrustManager defaultX509TrustManager;
+    private X509TrustManager ourX509TrustManager;
+
+    // For testing
+    CustomX509TrustManager(X509TrustManager defaultTrustManager,
+            X509TrustManager ourTrustManager) {
+        this.defaultX509TrustManager = defaultTrustManager;
+        this.ourX509TrustManager = ourTrustManager;
+    }
+    
+    // For testing
+    CustomX509TrustManager(X509TrustManager defaultTrustManager,
+            File keyStoreFile, String keyStorePassword) {
+        this.defaultX509TrustManager = defaultTrustManager;
+        this.ourX509TrustManager = getOurTrustManager(keyStoreFile, keyStorePassword);
+    }
+
+    // For testing
+    CustomX509TrustManager(File keyStoreFile, String keyStorePassword) {
+        this.defaultX509TrustManager = getDefaultTrustManager();
+        this.ourX509TrustManager = getOurTrustManager(keyStoreFile, keyStorePassword);
+    }
+
+    /*
+     * Main constructor, which uses ssl.properties as config if present.
+     */
+    CustomX509TrustManager() {
+        this(SSLKeystoreConfiguration.getKeystoreFile(), SSLKeystoreConfiguration.getKeyStorePassword());
+    }
+ 
+    private X509TrustManager getDefaultTrustManager() {
+        try {
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                    "SunX509", "SunJSSE");
+            // Passing a null-KeyStore in order to get default Java behaviour.
+            // See:
+            // http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
+            tmf.init((KeyStore) null);
+
+            TrustManager tms[] = tmf.getTrustManagers();
+
+            /*
+             * Iterate over the returned trustmanagers, look for an instance of
+             * X509TrustManager. If found, use that as our "default" trust
+             * manager.
+             */
+            for (int i = 0; i < tms.length; i++) {
+                if (tms[i] instanceof X509TrustManager) {
+                    logger.log(Level.FINE, "Using system trust manager.");
+                    return (X509TrustManager) tms[i];
+                }
+            }
+        } catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException e) {
+            logger.log(Level.WARNING, "Could not retrieve system trust manager", e);
+        }
+        return null;
+    }
+    
+    /*
+     * If thermostat trust store file exists and a X509TrustManager can be
+     * retrieved from said trust store it returns this X509TrustManager. Returns
+     * null if an exception is thrown along the way, the keystore file does not
+     * exist or no X509TrustManager was found in the backing trust store.
+     */
+    private X509TrustManager getOurTrustManager(File trustStoreFile,
+            String keyStorePassword) {
+        KeyStore trustStore  = KeyStoreProvider.getKeyStore(trustStoreFile, keyStorePassword);
+        if (trustStore != null) {
+            // backing keystore file existed and initialization was successful.
+            try {
+                TrustManagerFactory tmf = null;
+                tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
+                tmf.init(trustStore);
+
+                for (TrustManager tm : tmf.getTrustManagers()) {
+                    if (tm instanceof X509TrustManager) {
+                        logger.log(Level.FINE,
+                                "Using Thermostat trust manager.");
+                        return (X509TrustManager) tm;
+                    }
+                }
+            } catch (NoSuchAlgorithmException | NoSuchProviderException
+                    | KeyStoreException e) {
+                logger.log(Level.WARNING,
+                        "Could not load Thermostat trust manager");
+                return null;
+            }
+        }
+        logger.log(Level.FINE, "No Thermostat trust manager found");
+        return null;
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        // no-op: we don't support client authentication
+        logger.log(Level.INFO, "Checking client authentication: Allowing all client certificates!");
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        logger.log(Level.FINE, "Checking server certificate");
+        if (defaultX509TrustManager != null) {
+            try {
+                defaultX509TrustManager.checkServerTrusted(chain, authType);
+                logger.log(Level.FINE, "Server certificate check passed using system trust manager");
+                return;
+            } catch (CertificateException e) {
+                if (ourX509TrustManager != null) {
+                    // try our trust manager instead
+                    ourX509TrustManager.checkServerTrusted(chain, authType);
+                    logger.log(Level.FINE, "Server certificate check passed using Thermostat trust manager");
+                    return;
+                } else {
+                    // just rethrow
+                    logger.log(Level.WARNING, "Server certificate check FAILED!", e);
+                    throw e;
+                }
+            }
+        } else if (ourX509TrustManager != null) {
+            ourX509TrustManager.checkServerTrusted(chain, authType);
+            logger.log(Level.FINE, "Server certificate check passed using Thermostat trust manager");
+            return;
+        }
+        logger.log(Level.SEVERE, "Server certificate could not be checked. No trust managers found. Stopping now.");
+        // Default to not trusting this cert
+        throw new CertificateException("Certificate verification failed!");
+    }
+
+    /*
+     * Union of CA's trusted by default trust manager and the thermostat trust
+     * manager (if any).
+     * 
+     * (non-Javadoc)
+     * 
+     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
+     */
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        Set<X509Certificate> trustedSet = new HashSet<>();
+        if (defaultX509TrustManager != null) {
+            trustedSet.addAll(Arrays.asList(defaultX509TrustManager
+                    .getAcceptedIssuers()));
+        }
+        if (ourX509TrustManager != null) {
+            trustedSet.addAll(Arrays.asList(ourX509TrustManager
+                    .getAcceptedIssuers()));
+        }
+        X509Certificate[] certs = trustedSet.toArray(new X509Certificate[0]);
+        return certs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/KeyStoreProvider.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+public class KeyStoreProvider {
+
+    private static final Logger logger = LoggingUtils
+            .getLogger(KeyStoreProvider.class);
+
+    public static KeyStore getKeyStore(File trustStoreFile, String keyStorePassword) {
+        if (trustStoreFile != null && trustStoreFile.exists()) {
+            try (InputStream is = new FileInputStream(trustStoreFile)) {
+                KeyStore trustStore = KeyStore.getInstance(KeyStore
+                        .getDefaultType());
+                trustStore.load(is, keyStorePassword.toCharArray());
+                return trustStore;
+            } catch (IOException | CertificateException
+                    | NoSuchAlgorithmException | KeyStoreException e) {
+                logger.log(Level.WARNING,
+                        "Could not load Thermostat trust manager", e);
+                return null;
+            }
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/SSLKeystoreConfiguration.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+
+public class SSLKeystoreConfiguration {
+
+    private static Properties clientProps = null;
+    private static final String KEYSTORE_FILE_KEY = "KEYSTORE_FILE";
+    private static final String KEYSTORE_FILE_PWD_KEY = "KEYSTORE_PASSWORD";
+
+    /**
+     * 
+     * @return The keystore file as specified in
+     *         $THERMOSTAT_HOME/ssl.properties if any. null otherwise.
+     */
+    public static File getKeystoreFile() {
+        try {
+            loadClientProperties();
+        } catch (InvalidConfigurationException e) {
+            // Thermostat home not set? Should have failed earlier. Do something
+            // reasonable.
+            return null;
+        }
+        String path = clientProps.getProperty(KEYSTORE_FILE_KEY);
+        if (path != null) {
+            File file = new File(path);
+            return file;
+        }
+        return null;
+    }
+
+    /**
+     * 
+     * @return The keystore file as specified in
+     *         $THERMOSTAT_HOME/ssl.properties if any. The empty string
+     *         otherwise.
+     * @throws InvalidConfigurationException
+     */
+    public static String getKeyStorePassword() {
+        try {
+            loadClientProperties();
+        } catch (InvalidConfigurationException e) {
+            // Thermostat home not set? Do something reasonable
+            return "";
+        }
+        String pwd = clientProps.getProperty(KEYSTORE_FILE_PWD_KEY);
+        if (pwd == null) {
+            return "";
+        } else {
+            return pwd;
+        }
+    }
+
+    // testing hook
+    static void initClientProperties(File clientPropertiesFile) {
+        clientProps = new Properties();
+        try {
+            clientProps.load(new FileInputStream(clientPropertiesFile));
+        } catch (IOException | IllegalArgumentException e) {
+            // Could not load ssl properties file. This is fine as it's
+            // an optional config.
+        }
+    }
+
+    private static void loadClientProperties()
+            throws InvalidConfigurationException {
+        if (clientProps == null) {
+            File thermostatEtcDir = new File(ConfigUtils.getThermostatHome(),
+                    "etc");
+            File clientPropertiesFile = new File(thermostatEtcDir,
+                    "ssl.properties");
+            initClientProperties(clientPropertiesFile);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/TrustManagerFactory.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import javax.net.ssl.X509TrustManager;
+
+
+/**
+ * Factory class in order to be able to get at the thermostat X509TrustManager.
+ * 
+ */
+public class TrustManagerFactory {
+
+    /**
+     * @return the thermostat X509TrustManager.
+     */
+    public static X509TrustManager getTrustManager() {
+        return new CustomX509TrustManager();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLContextFactory.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.ssl;
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+import com.redhat.thermostat.common.internal.TrustManagerFactory;
+
+public class SSLContextFactory {
+
+    private static final String PROTOCOL = "TLS";
+    private static SSLContext clientContext;
+
+    /**
+     * 
+     * @return An initialized SSLContext with Thermostat's own X509TrustManager
+     *         registered.
+     * @throws SslInitException if SSL initialization failed.
+     */
+    public static SSLContext getClientContext() throws SslInitException {
+        if (clientContext != null) {
+            return clientContext;
+        }
+        initClientContext();
+        return clientContext;
+    }
+
+    private static void initClientContext() throws SslInitException {
+        SSLContext clientCtxt = null;
+        try {
+            clientCtxt = SSLContext.getInstance(PROTOCOL);
+            TrustManager[] tms = new TrustManager[] { TrustManagerFactory
+                    .getTrustManager() };
+            clientCtxt.init(null, tms, new SecureRandom());
+        } catch (NoSuchAlgorithmException | KeyManagementException e) {
+            e.printStackTrace();
+        }
+        clientContext = clientCtxt;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/ssl/SslInitException.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.ssl;
+
+@SuppressWarnings("serial")
+public class SslInitException extends Exception {
+    public SslInitException(Throwable cause) {
+        super(cause);
+    }
+
+    public SslInitException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/internal/CustomX509TrustManagerTest.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.internal.CustomX509TrustManager;
+
+/**
+ * This trust manager test uses files in src/test/resources. Files are as
+ * follows:
+ * 
+ * empty.keystore => emtpy file (not a real keystore file)
+ * 
+ * ca.crt => a openssl generated X509 certificate (representing a custom CA)
+ * 
+ * test_ca.keystore => a Java keystore file with ca.crt imported. Uses keystore
+ * password "testpassword". Used command sequence to generate this file:
+ * 
+ * $ keytool -genkey -alias com.redhat -keyalg RSA -keystore test_ca.keystore -keysize 2048
+ * $ keytool -import -trustcacerts -alias root -file ca.crt -keystore test_ca.keystore
+ * 
+ * 
+ */
+public class CustomX509TrustManagerTest {
+
+    @Test
+    public void testEmptyDefaultOur() {
+        X509TrustManager tm = new CustomX509TrustManager(
+                (X509TrustManager) null, (X509TrustManager) null);
+        assertEquals(0, tm.getAcceptedIssuers().length);
+        try {
+            tm.checkClientTrusted(null, null);
+        } catch (Exception e) {
+            fail("Should not have thrown exception");
+        }
+        try {
+            tm.checkServerTrusted(null, null);
+            fail("Expected exception since there aren't any trust managers available");
+        } catch (CertificateException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void testLoadEmptyTrustStoreForOur() {
+        File emptyKeyStore = new File(this.getClass()
+                .getResource("/empty.keystore").getFile());
+        X509TrustManager tm = new CustomX509TrustManager(null, emptyKeyStore,
+                "");
+        assertEquals(0, tm.getAcceptedIssuers().length);
+        try {
+            tm.checkClientTrusted(null, null);
+        } catch (Exception e) {
+            fail("Should not have thrown exception");
+        }
+        try {
+            X509Certificate dummyCert = mock(X509Certificate.class);
+            tm.checkServerTrusted(new X509Certificate[] { dummyCert }, "RSA");
+            fail("Expected exception since there aren't any trust managers available");
+        } catch (CertificateException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void testLoadEmptyTrustStoreForOurDefaultAsUsual() throws Exception {
+        File emptyKeyStore = new File(this.getClass()
+                .getResource("/empty.keystore").getFile());
+        X509TrustManager tm = new CustomX509TrustManager(emptyKeyStore, "");
+        // Default list should not be empty
+        assertTrue(tm.getAcceptedIssuers().length > 0);
+        try {
+            tm.checkClientTrusted(null, null);
+        } catch (Exception e) {
+            fail("Should not have thrown exception");
+        }
+    }
+    
+    @Test
+    public void canGetCustomCaCertFromOurTrustManager() {
+        File ourKeyStore = new File(this.getClass()
+                .getResource("/test_ca.keystore").getFile());
+        X509TrustManager tm = new CustomX509TrustManager((X509TrustManager)null, ourKeyStore, "testpassword");
+        // keystore contains private key of itself + imported CA cert
+        assertEquals(2, tm.getAcceptedIssuers().length);
+        String issuerNameCustomCA = "1.2.840.113549.1.9.1=#16126a6572626f6161407265646861742e636f6d,CN=test.example.com,O=Red Hat Inc.,L=Saalfelden,ST=Salzburg,C=AT";
+        String issuerNameKeystoreCA = "CN=Unknown,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown";
+        assertEquals(issuerNameCustomCA, tm.getAcceptedIssuers()[0]
+                .getIssuerX500Principal().getName());
+        assertEquals(issuerNameKeystoreCA, tm.getAcceptedIssuers()[1]
+                .getIssuerX500Principal().getName());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/internal/KeyStoreProviderTest.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+
+import org.junit.Test;
+
+public class KeyStoreProviderTest {
+
+    @Test
+    public void nonExistentFileReturnsNull() {
+        File notThere = new File("/some/path/that/doesnt/exists");
+        assertNull(KeyStoreProvider.getKeyStore(notThere, "ignored"));
+    }
+    
+    @Test
+    public void nullFileReturnsNull() {
+        assertNull(KeyStoreProvider.getKeyStore(null, "ignored"));
+    }
+    
+    @Test
+    public void existingFileWithWrongPwdReturnsNull() {
+        File keystore = new File(this.getClass()
+                .getResource("/test_ca.keystore").getFile());
+        assertNull(KeyStoreProvider.getKeyStore(keystore, "wrong password"));
+    }
+    
+    @Test
+    public void existingFileWithCorrectPasswordWorks() {
+        File keystore = new File(this.getClass()
+                .getResource("/test_ca.keystore").getFile());
+        assertNotNull("Should have been able to retrieve and load keystore", KeyStoreProvider.getKeyStore(keystore, "testpassword"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/internal/SSLKeystoreConfigurationTest.java	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.common.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.internal.SSLKeystoreConfiguration;
+
+public class SSLKeystoreConfigurationTest {
+
+    @Test
+    public void canGetKeystoreFileFromProps() throws Exception {
+        File clientProps = new File(this.getClass().getResource("/client.properties").getFile());
+        SSLKeystoreConfiguration.initClientProperties(clientProps);
+        String keystorePath = "/path/to/thermostat.keystore";
+        String keystorePwd = "some password";
+        assertEquals(keystorePath, SSLKeystoreConfiguration.getKeystoreFile().getAbsolutePath());
+        assertEquals(keystorePwd, SSLKeystoreConfiguration.getKeyStorePassword());
+    }
+    
+    @Test
+    public void notExistingPropertiesFileReturnsNull() throws Exception {
+        File clientProps = new File("i/am/not/there/file.txt");
+        SSLKeystoreConfiguration.initClientProperties(clientProps);
+        assertTrue(SSLKeystoreConfiguration.getKeystoreFile() == null);
+        assertEquals("", SSLKeystoreConfiguration.getKeyStorePassword());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/resources/ca.crt	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF6TCCA9GgAwIBAgIJAMqGn7zFkpycMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD
+VQQGEwJBVDERMA8GA1UECAwIU2FsemJ1cmcxEzARBgNVBAcMClNhYWxmZWxkZW4x
+FTATBgNVBAoMDFJlZCBIYXQgSW5jLjEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLmNv
+bTEhMB8GCSqGSIb3DQEJARYSamVyYm9hYUByZWRoYXQuY29tMB4XDTEyMTIwMzEz
+MTc1M1oXDTE3MTIwMzEzMTc1M1owgYoxCzAJBgNVBAYTAkFUMREwDwYDVQQIDAhT
+YWx6YnVyZzETMBEGA1UEBwwKU2FhbGZlbGRlbjEVMBMGA1UECgwMUmVkIEhhdCBJ
+bmMuMRkwFwYDVQQDDBB0ZXN0LmV4YW1wbGUuY29tMSEwHwYJKoZIhvcNAQkBFhJq
+ZXJib2FhQHJlZGhhdC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQDKdOtT5HmVdFWj05aTqWQPX9L2NA44/69hwsrIwQFHi09DD+BwobaTmRpWg3Tg
+6qr+128AFlj2N8gYHyKELSxt1rsBV1yleTcpywfsmP7XkcZfu9ZKgmB4xyXuK4IQ
+EYxGqeWIdGYFNncjFm7Na3i9aTJZqtGxGf+kkQX2OdzqMbiXg17AYxH21kqMbNPk
+R2mhWUE4sT9Nfj+qO+iUqHCUMPusJY4xi/tGjLA9phih85ShYyqRBXXHiplzDCm+
+0W/puPodPVDo1FdfAwXExYaj8QoKmqCnGT9U++gMQ0b1xkRyuyImdqF9o63HoCMm
+8/R7ye0QTU8yUXwRoujvowSiip6/FAfADe7QyhHmScP9uS2/tNR0daCKUBnkWnJf
++PvbzNCT3V4MTwvg3LvphhU1JKXLSdQiZkSsLLKjnfUFE6BuT2RNFlWsbnuF2NcK
+H8ZDySDFL2LSeROPmi1lV2k+MScG2XOwKQXVQiU5GPgqNhhYvSClIk/kOagBoI74
+Ixq9hDW1viOHwKHZ315M3rNTg3Y4dq4eohUPP9iLmCFEBOW14MGDOMRKhzdFSUnG
+UBVdUiesqi3zwOSZ0EeqU2SgvmQKwvN1imWqsZlvkKV8p9mnFNmF/idbbkq2EWN0
+q/Hg7ekq/6mdN2f3XTGf0F85pTUtWWKpoyUM2qmZ72H+hQIDAQABo1AwTjAdBgNV
+HQ4EFgQUpknaZuFsL+AYna6uu5gSlKVUdbkwHwYDVR0jBBgwFoAUpknaZuFsL+AY
+na6uu5gSlKVUdbkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAyAlS
+DJ+h4SO0mfZLU88JuRF8LoADD2u2eO890aIC1PtxIm9Osrfrc104LukCGpeLJvSZ
+hee/yZklen6K7lEURCgYmHreDtWx6zkf+qGdhqq0+97cfzvnSH8pDwVJxzY8dr+Q
+K2XSFOszkmVVNOnvu/GgHjcpOvXBNItnalrAqGgFi4cOGRzFl9x4iWUEMiUWERnP
+ntsisNsG4yY8D50Vl/k9qrU02IAsNQ+pnjDI+8bPni4aDE6nGH1+aNmS0J1YBM0s
+pPpK/W9GIxltARUfHI/mnvRNMCPeaG7ohJKBaIJkvibTa5Ux6zx1lNhJmDTHH4t+
+jMdoF5+90/AxYTnOQFb9oTPTX4+HgOhib9YtaxA7mXH5lVGFB19UrT7eFFNZeUFu
+Du+HOCPSrtTgLUdrkix+znl7ai4SORYFGL/v7QDw9U3FCGgRWuKzyQasvm3xELea
+3GXOuttDMWyfsAAsBWGpcJVN+YN23B75j1xN2b8JMvNNQChifWiFcztp7DsA1qxo
+M4g88l6WlRFm7OKqi9ZMbPH9/LlmvAhak5fS4l6UI08v/bX9qUEWNo1RzBZlHA4U
+3Xs9P3VF7h2pp0O3ucWm6nWAcp0CfvmaTnjof+cW8LDRHqEK0tWLEdBLg1TnUnnk
+EUsxCO6b/aOvribtT0aDLRB6sF8MTAtOBkczmp4=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/resources/client.properties	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,2 @@
+KEYSTORE_FILE=/path/to/thermostat.keystore
+KEYSTORE_PASSWORD=some password
\ No newline at end of file
Binary file common/core/src/test/resources/empty.keystore has changed
Binary file common/core/src/test/resources/test_ca.keystore has changed
--- a/distribution/config/client.properties	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-# This file is only used in a Web storage setup and is entirely optional.
-# It allows for a user to specify a thermostat specific keystore to be used
-# for TLS certificate validation in addition to the default as described in:
-# http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager
-
-# If you'd like to use a keystore file in addition to defaults uncomment the
-# following line:
-#KEYSTORE_FILE=/path/to/thermostat.keystore
-
-# The password for the keystore file. If none is provided the empty password
-# is assumed. Only used if KEYSTORE_FILE was specified.
-#KEYSTORE_PASSWORD=nopassword
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/config/ssl.properties	Tue Dec 11 12:04:58 2012 +0100
@@ -0,0 +1,12 @@
+# This file is only used in a Web storage setup and is entirely optional.
+# It allows for a user to specify a thermostat specific keystore to be used
+# for TLS certificate validation in addition to the default as described in:
+# http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager
+
+# If you'd like to use a keystore file in addition to defaults uncomment the
+# following line:
+#KEYSTORE_FILE=/path/to/thermostat.keystore
+
+# The password for the keystore file. If none is provided the empty password
+# is assumed. Only used if KEYSTORE_FILE was specified.
+#KEYSTORE_PASSWORD=nopassword
\ No newline at end of file
--- a/distribution/pom.xml	Mon Dec 10 16:52:51 2012 -0500
+++ b/distribution/pom.xml	Tue Dec 11 12:04:58 2012 +0100
@@ -131,7 +131,7 @@
                   <targetPath>etc</targetPath>
                   <filtering>true</filtering>
                   <includes>
-                    <include>client.properties</include>
+                    <include>ssl.properties</include>
                   </includes>
                 </resource>
                 <resource>
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/CustomX509TrustManager.java	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.client.internal;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-/**
- * Custom X509TrustManager which first attempts to verify peer certificates
- * using Java's default trust manager. If that fails it uses thermostat's
- * keystore file (if any) and uses it for another attempt to validate the
- * server certificate. If that fails as well, the connection is not allowed.
- * 
- */
-class CustomX509TrustManager implements X509TrustManager {
-    
-    Logger logger = LoggingUtils.getLogger(CustomX509TrustManager.class);
-
-    /*
-     * The default X509TrustManager returned by SunX509. We'll delegate
-     * decisions to it, and fall back to the logic in this class if the default
-     * X509TrustManager doesn't trust it.
-     */
-    private X509TrustManager defaultX509TrustManager;
-    private X509TrustManager ourX509TrustManager;
-
-    // For testing
-    CustomX509TrustManager(X509TrustManager defaultTrustManager,
-            X509TrustManager ourTrustManager) {
-        this.defaultX509TrustManager = defaultTrustManager;
-        this.ourX509TrustManager = ourTrustManager;
-    }
-    
-    // For testing
-    CustomX509TrustManager(X509TrustManager defaultTrustManager,
-            File keyStoreFile, String keyStorePassword) {
-        this.defaultX509TrustManager = defaultTrustManager;
-        this.ourX509TrustManager = getOurTrustManager(keyStoreFile, keyStorePassword);
-    }
-
-    // For testing
-    CustomX509TrustManager(File keyStoreFile, String keyStorePassword) {
-        this.defaultX509TrustManager = getDefaultTrustManager();
-        this.ourX509TrustManager = getOurTrustManager(keyStoreFile, keyStorePassword);
-    }
-
-    /*
-     * Main constructor. Others are used for testing.
-     */
-    CustomX509TrustManager() {
-        this(SSLKeystoreConfiguration.getKeystoreFile(), SSLKeystoreConfiguration.getKeyStorePassword());
-    }
- 
-    private X509TrustManager getDefaultTrustManager() {
-        try {
-            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
-                    "SunX509", "SunJSSE");
-            // Passing a null-KeyStore in order to get default Java behaviour.
-            // See:
-            // http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
-            tmf.init((KeyStore) null);
-
-            TrustManager tms[] = tmf.getTrustManagers();
-
-            /*
-             * Iterate over the returned trustmanagers, look for an instance of
-             * X509TrustManager. If found, use that as our "default" trust
-             * manager.
-             */
-            for (int i = 0; i < tms.length; i++) {
-                if (tms[i] instanceof X509TrustManager) {
-                    logger.log(Level.FINE, "Using system trust manager.");
-                    return (X509TrustManager) tms[i];
-                }
-            }
-        } catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException e) {
-            logger.log(Level.WARNING, "Could not retrieve system trust manager", e);
-        }
-        return null;
-    }
-    
-    /*
-     * If thermostat trust store file exists and a X509TrustManager can be
-     * retrieved from said trust store it returns this X509TrustManager. Returns
-     * null if an exception is thrown along the way, the keystore file does not
-     * exist or no X509TrustManager was found in the backing trust store.
-     */
-    private X509TrustManager getOurTrustManager(File trustStoreFile,
-            String keyStorePassword) {
-        KeyStore trustStore = null;
-        if (trustStoreFile != null && trustStoreFile.exists()) {
-            try {
-                trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
-                try (InputStream is = new FileInputStream(trustStoreFile)) {
-                    trustStore.load(is, keyStorePassword.toCharArray());
-                } catch (IOException | CertificateException
-                        | NoSuchAlgorithmException e) {
-                    logger.log(Level.WARNING,
-                            "Could not load Thermostat trust manager");
-                    return null;
-                }
-                TrustManagerFactory tmf = null;
-                tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
-                tmf.init(trustStore);
-
-                for (TrustManager tm : tmf.getTrustManagers()) {
-                    if (tm instanceof X509TrustManager) {
-                        logger.log(Level.FINE,
-                                "Using Thermostat trust manager.");
-                        return (X509TrustManager) tm;
-                    }
-                }
-            } catch (NoSuchAlgorithmException | NoSuchProviderException
-                    | KeyStoreException e) {
-                logger.log(Level.WARNING,
-                        "Could not load Thermostat trust manager");
-                return null;
-            }
-        }
-        logger.log(Level.FINE, "No Thermostat trust manager found");
-        return null;
-    }
-
-    @Override
-    public void checkClientTrusted(X509Certificate[] chain, String authType)
-            throws CertificateException {
-        // no-op: we don't support client authentication
-        logger.log(Level.INFO, "Checking client authentication: Allowing all client certificates!");
-    }
-
-    @Override
-    public void checkServerTrusted(X509Certificate[] chain, String authType)
-            throws CertificateException {
-        logger.log(Level.FINE, "Checking server certificate");
-        if (defaultX509TrustManager != null) {
-            try {
-                defaultX509TrustManager.checkServerTrusted(chain, authType);
-                logger.log(Level.FINE, "Server certificate check passed using system trust manager");
-                return;
-            } catch (CertificateException e) {
-                if (ourX509TrustManager != null) {
-                    // try our trust manager instead
-                    ourX509TrustManager.checkServerTrusted(chain, authType);
-                    logger.log(Level.FINE, "Server certificate check passed using Thermostat trust manager");
-                    return;
-                } else {
-                    // just rethrow
-                    logger.log(Level.WARNING, "Server certificate check FAILED!", e);
-                    throw e;
-                }
-            }
-        } else if (ourX509TrustManager != null) {
-            ourX509TrustManager.checkServerTrusted(chain, authType);
-            logger.log(Level.FINE, "Server certificate check passed using Thermostat trust manager");
-            return;
-        }
-        logger.log(Level.SEVERE, "Server certificate could not be checked. No trust managers found. Stopping now.");
-        // Default to not trusting this cert
-        throw new CertificateException("Certificate verification failed!");
-    }
-
-    /*
-     * Union of CA's trusted by default trust manager and the thermostat trust
-     * manager (if any).
-     * 
-     * (non-Javadoc)
-     * 
-     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
-     */
-    @Override
-    public X509Certificate[] getAcceptedIssuers() {
-        Set<X509Certificate> trustedSet = new HashSet<>();
-        if (defaultX509TrustManager != null) {
-            trustedSet.addAll(Arrays.asList(defaultX509TrustManager
-                    .getAcceptedIssuers()));
-        }
-        if (ourX509TrustManager != null) {
-            trustedSet.addAll(Arrays.asList(ourX509TrustManager
-                    .getAcceptedIssuers()));
-        }
-        X509Certificate[] certs = trustedSet.toArray(new X509Certificate[0]);
-        return certs;
-    }
-
-}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/SSLKeystoreConfiguration.java	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.client.internal;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Properties;
-
-import com.redhat.thermostat.common.config.ConfigUtils;
-import com.redhat.thermostat.common.config.InvalidConfigurationException;
-
-public class SSLKeystoreConfiguration {
-
-    private static Properties clientProps = null;
-    private static final String KEYSTORE_FILE_KEY = "KEYSTORE_FILE";
-    private static final String KEYSTORE_FILE_PWD_KEY = "KEYSTORE_PASSWORD";
-
-    /**
-     * 
-     * @return The keystore file as specified in
-     *         $THERMOSTAT_HOME/client.properties if any. null otherwise.
-     */
-    public static File getKeystoreFile() {
-        try {
-            loadClientProperties();
-        } catch (InvalidConfigurationException e) {
-            // Thermostat home not set? Should have failed earlier. Do something
-            // reasonable.
-            return null;
-        }
-        String path = clientProps.getProperty(KEYSTORE_FILE_KEY);
-        if (path != null) {
-            File file = new File(path);
-            return file;
-        }
-        return null;
-    }
-
-    /**
-     * 
-     * @return The keystore file as specified in
-     *         $THERMOSTAT_HOME/client.properties if any. The empty string
-     *         otherwise.
-     * @throws InvalidConfigurationException
-     */
-    public static String getKeyStorePassword() {
-        try {
-            loadClientProperties();
-        } catch (InvalidConfigurationException e) {
-            // Thermostat home not set? Do something reasonable
-            return "";
-        }
-        String pwd = clientProps.getProperty(KEYSTORE_FILE_PWD_KEY);
-        if (pwd == null) {
-            return "";
-        } else {
-            return pwd;
-        }
-    }
-
-    // testing hook
-    static void initClientProperties(File clientPropertiesFile) {
-        clientProps = new Properties();
-        try {
-            clientProps.load(new FileInputStream(clientPropertiesFile));
-        } catch (IOException | IllegalArgumentException e) {
-            // Could not load client properties file. This is fine as it's
-            // an optional config after all.
-        }
-    }
-
-    private static void loadClientProperties()
-            throws InvalidConfigurationException {
-        if (clientProps == null) {
-            File thermostatEtcDir = new File(ConfigUtils.getThermostatHome(),
-                    "etc");
-            File clientPropertiesFile = new File(thermostatEtcDir,
-                    "client.properties");
-            initClientProperties(clientPropertiesFile);
-        }
-    }
-}
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Mon Dec 10 16:52:51 2012 -0500
+++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java	Tue Dec 11 12:04:58 2012 +0100
@@ -45,7 +45,6 @@
 import java.lang.reflect.Array;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.security.GeneralSecurityException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -57,8 +56,6 @@
 import java.util.logging.Logger;
 
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.http.Header;
@@ -83,9 +80,11 @@
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
-import com.redhat.thermostat.storage.core.AuthToken;
+import com.redhat.thermostat.common.ssl.SSLContextFactory;
+import com.redhat.thermostat.common.ssl.SslInitException;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
+import com.redhat.thermostat.storage.core.AuthToken;
 import com.redhat.thermostat.storage.core.Category;
 import com.redhat.thermostat.storage.core.Connection;
 import com.redhat.thermostat.storage.core.Cursor;
@@ -301,19 +300,11 @@
     private void registerSSLScheme(ClientConnectionManager conManager)
             throws StorageException {
         try {
-            SSLContext sc = SSLContext.getInstance("TLS");
-            X509TrustManager ourTm;
-            try {
-                ourTm = new CustomX509TrustManager();
-            } catch (Exception e) {
-                throw new StorageException(e);
-            }
-            TrustManager[] tms = new TrustManager[] { ourTm };
-            sc.init(null, tms, new SecureRandom());
+            SSLContext sc = SSLContextFactory.getClientContext();
             SSLSocketFactory socketFactory = new SSLSocketFactory(sc);
             Scheme sch = new Scheme("https", 443, socketFactory);
             conManager.getSchemeRegistry().register(sch);
-        } catch ( GeneralSecurityException e) {
+        } catch ( SslInitException e) {
             throw new StorageException(e);
         }
     }
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/CustomX509TrustManagerTest.java	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.client.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import java.io.File;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.X509TrustManager;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.web.client.internal.CustomX509TrustManager;
-
-/**
- * This trust manager test uses files in src/test/resources. Files are as
- * follows:
- * 
- * empty.keystore => emtpy file (not a real keystore file)
- * 
- * ca.crt => a openssl generated X509 certificate (representing a custom CA)
- * 
- * test_ca.keystore => a Java keystore file with ca.crt imported. Uses keystore
- * password "testpassword". Used command sequence to generate this file:
- * 
- * $ keytool -genkey -alias com.redhat -keyalg RSA -keystore test_ca.keystore -keysize 2048
- * $ keytool -import -trustcacerts -alias root -file ca.crt -keystore test_ca.keystore
- * 
- * 
- */
-public class CustomX509TrustManagerTest {
-
-    @Test
-    public void testEmptyDefaultOur() {
-        X509TrustManager tm = new CustomX509TrustManager(
-                (X509TrustManager) null, (X509TrustManager) null);
-        assertEquals(0, tm.getAcceptedIssuers().length);
-        try {
-            tm.checkClientTrusted(null, null);
-        } catch (Exception e) {
-            fail("Should not have thrown exception");
-        }
-        try {
-            tm.checkServerTrusted(null, null);
-            fail("Expected exception since there aren't any trust managers available");
-        } catch (CertificateException e) {
-            // pass
-        }
-    }
-
-    @Test
-    public void testLoadEmptyTrustStoreForOur() {
-        File emptyKeyStore = new File(this.getClass()
-                .getResource("/empty.keystore").getFile());
-        X509TrustManager tm = new CustomX509TrustManager(null, emptyKeyStore,
-                "");
-        assertEquals(0, tm.getAcceptedIssuers().length);
-        try {
-            tm.checkClientTrusted(null, null);
-        } catch (Exception e) {
-            fail("Should not have thrown exception");
-        }
-        try {
-            X509Certificate dummyCert = mock(X509Certificate.class);
-            tm.checkServerTrusted(new X509Certificate[] { dummyCert }, "RSA");
-            fail("Expected exception since there aren't any trust managers available");
-        } catch (CertificateException e) {
-            // pass
-        }
-    }
-
-    @Test
-    public void testLoadEmptyTrustStoreForOurDefaultAsUsual() throws Exception {
-        File emptyKeyStore = new File(this.getClass()
-                .getResource("/empty.keystore").getFile());
-        X509TrustManager tm = new CustomX509TrustManager(emptyKeyStore, "");
-        // Default list should not be empty
-        assertTrue(tm.getAcceptedIssuers().length > 0);
-        try {
-            tm.checkClientTrusted(null, null);
-        } catch (Exception e) {
-            fail("Should not have thrown exception");
-        }
-    }
-    
-    @Test
-    public void canGetCustomCaCertFromOurTrustManager() {
-        File ourKeyStore = new File(this.getClass()
-                .getResource("/test_ca.keystore").getFile());
-        X509TrustManager tm = new CustomX509TrustManager((X509TrustManager)null, ourKeyStore, "testpassword");
-        // keystore contains private key of itself + imported CA cert
-        assertEquals(2, tm.getAcceptedIssuers().length);
-        String issuerNameCustomCA = "1.2.840.113549.1.9.1=#16126a6572626f6161407265646861742e636f6d,CN=test.example.com,O=Red Hat Inc.,L=Saalfelden,ST=Salzburg,C=AT";
-        String issuerNameKeystoreCA = "CN=Unknown,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown";
-        assertEquals(issuerNameCustomCA, tm.getAcceptedIssuers()[0]
-                .getIssuerX500Principal().getName());
-        assertEquals(issuerNameKeystoreCA, tm.getAcceptedIssuers()[1]
-                .getIssuerX500Principal().getName());
-    }
-
-}
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/SSLKeystoreConfigurationTest.java	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.web.client.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.web.client.internal.SSLKeystoreConfiguration;
-
-public class SSLKeystoreConfigurationTest {
-
-    @Test
-    public void canGetKeystoreFileFromProps() throws Exception {
-        File clientProps = new File(this.getClass().getResource("/client.properties").getFile());
-        SSLKeystoreConfiguration.initClientProperties(clientProps);
-        String keystorePath = "/path/to/thermostat.keystore";
-        String keystorePwd = "some password";
-        assertEquals(keystorePath, SSLKeystoreConfiguration.getKeystoreFile().getAbsolutePath());
-        assertEquals(keystorePwd, SSLKeystoreConfiguration.getKeyStorePassword());
-    }
-    
-    @Test
-    public void notExistingPropertiesFileReturnsNull() throws Exception {
-        File clientProps = new File("i/am/not/there/file.txt");
-        SSLKeystoreConfiguration.initClientProperties(clientProps);
-        assertTrue(SSLKeystoreConfiguration.getKeystoreFile() == null);
-        assertEquals("", SSLKeystoreConfiguration.getKeyStorePassword());
-    }
-}
--- a/web/client/src/test/resources/ca.crt	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF6TCCA9GgAwIBAgIJAMqGn7zFkpycMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD
-VQQGEwJBVDERMA8GA1UECAwIU2FsemJ1cmcxEzARBgNVBAcMClNhYWxmZWxkZW4x
-FTATBgNVBAoMDFJlZCBIYXQgSW5jLjEZMBcGA1UEAwwQdGVzdC5leGFtcGxlLmNv
-bTEhMB8GCSqGSIb3DQEJARYSamVyYm9hYUByZWRoYXQuY29tMB4XDTEyMTIwMzEz
-MTc1M1oXDTE3MTIwMzEzMTc1M1owgYoxCzAJBgNVBAYTAkFUMREwDwYDVQQIDAhT
-YWx6YnVyZzETMBEGA1UEBwwKU2FhbGZlbGRlbjEVMBMGA1UECgwMUmVkIEhhdCBJ
-bmMuMRkwFwYDVQQDDBB0ZXN0LmV4YW1wbGUuY29tMSEwHwYJKoZIhvcNAQkBFhJq
-ZXJib2FhQHJlZGhhdC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
-AQDKdOtT5HmVdFWj05aTqWQPX9L2NA44/69hwsrIwQFHi09DD+BwobaTmRpWg3Tg
-6qr+128AFlj2N8gYHyKELSxt1rsBV1yleTcpywfsmP7XkcZfu9ZKgmB4xyXuK4IQ
-EYxGqeWIdGYFNncjFm7Na3i9aTJZqtGxGf+kkQX2OdzqMbiXg17AYxH21kqMbNPk
-R2mhWUE4sT9Nfj+qO+iUqHCUMPusJY4xi/tGjLA9phih85ShYyqRBXXHiplzDCm+
-0W/puPodPVDo1FdfAwXExYaj8QoKmqCnGT9U++gMQ0b1xkRyuyImdqF9o63HoCMm
-8/R7ye0QTU8yUXwRoujvowSiip6/FAfADe7QyhHmScP9uS2/tNR0daCKUBnkWnJf
-+PvbzNCT3V4MTwvg3LvphhU1JKXLSdQiZkSsLLKjnfUFE6BuT2RNFlWsbnuF2NcK
-H8ZDySDFL2LSeROPmi1lV2k+MScG2XOwKQXVQiU5GPgqNhhYvSClIk/kOagBoI74
-Ixq9hDW1viOHwKHZ315M3rNTg3Y4dq4eohUPP9iLmCFEBOW14MGDOMRKhzdFSUnG
-UBVdUiesqi3zwOSZ0EeqU2SgvmQKwvN1imWqsZlvkKV8p9mnFNmF/idbbkq2EWN0
-q/Hg7ekq/6mdN2f3XTGf0F85pTUtWWKpoyUM2qmZ72H+hQIDAQABo1AwTjAdBgNV
-HQ4EFgQUpknaZuFsL+AYna6uu5gSlKVUdbkwHwYDVR0jBBgwFoAUpknaZuFsL+AY
-na6uu5gSlKVUdbkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAyAlS
-DJ+h4SO0mfZLU88JuRF8LoADD2u2eO890aIC1PtxIm9Osrfrc104LukCGpeLJvSZ
-hee/yZklen6K7lEURCgYmHreDtWx6zkf+qGdhqq0+97cfzvnSH8pDwVJxzY8dr+Q
-K2XSFOszkmVVNOnvu/GgHjcpOvXBNItnalrAqGgFi4cOGRzFl9x4iWUEMiUWERnP
-ntsisNsG4yY8D50Vl/k9qrU02IAsNQ+pnjDI+8bPni4aDE6nGH1+aNmS0J1YBM0s
-pPpK/W9GIxltARUfHI/mnvRNMCPeaG7ohJKBaIJkvibTa5Ux6zx1lNhJmDTHH4t+
-jMdoF5+90/AxYTnOQFb9oTPTX4+HgOhib9YtaxA7mXH5lVGFB19UrT7eFFNZeUFu
-Du+HOCPSrtTgLUdrkix+znl7ai4SORYFGL/v7QDw9U3FCGgRWuKzyQasvm3xELea
-3GXOuttDMWyfsAAsBWGpcJVN+YN23B75j1xN2b8JMvNNQChifWiFcztp7DsA1qxo
-M4g88l6WlRFm7OKqi9ZMbPH9/LlmvAhak5fS4l6UI08v/bX9qUEWNo1RzBZlHA4U
-3Xs9P3VF7h2pp0O3ucWm6nWAcp0CfvmaTnjof+cW8LDRHqEK0tWLEdBLg1TnUnnk
-EUsxCO6b/aOvribtT0aDLRB6sF8MTAtOBkczmp4=
------END CERTIFICATE-----
--- a/web/client/src/test/resources/client.properties	Mon Dec 10 16:52:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-KEYSTORE_FILE=/path/to/thermostat.keystore
-KEYSTORE_PASSWORD=some password
\ No newline at end of file
Binary file web/client/src/test/resources/empty.keystore has changed
Binary file web/client/src/test/resources/test_ca.keystore has changed