Mercurial > hg > release > thermostat-1.2
changeset 1341:70ab2071e074
servicify SSLConfiguration
reviewed-by: omajid
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-November/008728.html
line wrap: on
line diff
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/Activator.java Fri Nov 15 16:15:18 2013 -0700 +++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/Activator.java Fri Nov 15 17:28:05 2013 -0700 @@ -41,30 +41,61 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.redhat.thermostat.agent.command.ConfigurationServer; import com.redhat.thermostat.agent.command.ReceiverRegistry; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; public class Activator implements BundleActivator { private static final Logger logger = LoggingUtils.getLogger(Activator.class); + @SuppressWarnings("rawtypes") private ServiceRegistration confServerRegistration; private ReceiverRegistry receivers; + @SuppressWarnings("rawtypes") + private ServiceTracker sslConfigTracker; + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override - public void start(BundleContext context) throws Exception { + public void start(final BundleContext context) throws Exception { logger.log(Level.INFO, "activating thermostat-agent-confserver"); receivers = new ReceiverRegistry(context); receivers.registerReceiver(new PingReceiver()); - ConfigurationServerImpl confServer = new ConfigurationServerImpl(new ConfigurationServerContext(context)); - confServerRegistration = context.registerService(ConfigurationServer.class.getName(), confServer, null); + sslConfigTracker = new ServiceTracker(context, SSLConfiguration.class, new ServiceTrackerCustomizer() { + + @Override + public Object addingService(ServiceReference reference) { + SSLConfiguration sslConf = (SSLConfiguration) context.getService(reference); + ConfigurationServerImpl confServer = new ConfigurationServerImpl(new ConfigurationServerContext(context, sslConf)); + confServerRegistration = context.registerService(ConfigurationServer.class.getName(), confServer, null); + return confServer; + } + + @Override + public void modifiedService(ServiceReference reference, + Object service) { + // Do nothing + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + confServerRegistration.unregister(); + confServerRegistration = null; + context.ungetService(reference); + }}); + sslConfigTracker.open(); } @Override public void stop(BundleContext context) throws Exception { + sslConfigTracker.close(); if (confServerRegistration != null) { confServerRegistration.unregister(); }
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ConfigurationServerContext.java Fri Nov 15 16:15:18 2013 -0700 +++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ConfigurationServerContext.java Fri Nov 15 17:28:05 2013 -0700 @@ -57,10 +57,10 @@ import com.redhat.thermostat.agent.command.ReceiverRegistry; import com.redhat.thermostat.common.command.ConfigurationCommandContext; import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.ssl.SslInitException; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.InvalidConfigurationException; +import com.redhat.thermostat.shared.config.SSLConfiguration; class ConfigurationServerContext implements ConfigurationCommandContext { @@ -69,11 +69,13 @@ private final ServerBootstrap bootstrap; private final ChannelGroup channels; private final BundleContext context; + private final SSLConfiguration sslConf; - ConfigurationServerContext(BundleContext context) { + ConfigurationServerContext(BundleContext context, SSLConfiguration sslConf) { bootstrap = createBootstrap(); channels = createChannelGroup(); this.context = context; + this.sslConf = sslConf; } @Override @@ -81,6 +83,11 @@ return bootstrap; } + @Override + public SSLConfiguration getSSLConfiguration() { + return sslConf; + } + private ChannelGroup createChannelGroup() { return new DefaultChannelGroup(ConfigurationServerImpl.class.getName()); } @@ -108,10 +115,10 @@ @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); - if (SSLConfiguration.enableForCmdChannel()) { + if (sslConf.enableForCmdChannel()) { SSLEngine engine = null; try { - SSLContext ctxt = SSLContextFactory.getServerContext(); + SSLContext ctxt = SSLContextFactory.getServerContext(sslConf); engine = ctxt.createSSLEngine(); engine.setUseClientMode(false); } catch (SslInitException | InvalidConfigurationException e) { @@ -123,7 +130,7 @@ } pipeline.addLast("decoder", new RequestDecoder()); pipeline.addLast("encoder", new ResponseEncoder()); - pipeline.addLast("handler", new ServerHandler(new ReceiverRegistry(context))); + pipeline.addLast("handler", new ServerHandler(new ReceiverRegistry(context), sslConf)); return pipeline; }
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ServerHandler.java Fri Nov 15 16:15:18 2013 -0700 +++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/internal/ServerHandler.java Fri Nov 15 17:28:05 2013 -0700 @@ -59,8 +59,8 @@ import com.redhat.thermostat.common.command.Request; import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.core.AuthToken; import com.redhat.thermostat.storage.core.SecureStorage; import com.redhat.thermostat.storage.core.Storage; @@ -69,9 +69,11 @@ private static final Logger logger = LoggingUtils.getLogger(ServerHandler.class); private ReceiverRegistry receivers; + private SSLConfiguration sslConf; - public ServerHandler(ReceiverRegistry receivers) { + public ServerHandler(ReceiverRegistry receivers, SSLConfiguration sslConf) { this.receivers = receivers; + this.sslConf = sslConf; } @Override @@ -86,7 +88,7 @@ @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - if (SSLConfiguration.enableForCmdChannel()) { + if (sslConf.enableForCmdChannel()) { // Get the SslHandler in the current pipeline. // We added it in ConfigurationServerContext$ServerPipelineFactory. final SslHandler sslHandler = ctx.getPipeline().get(
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/ConfigurationServerContextTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/ConfigurationServerContextTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -39,6 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -60,20 +61,23 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import com.redhat.thermostat.common.ssl.SSLConfiguration; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.common.ssl.SSLContextFactory; @RunWith(PowerMockRunner.class) -@PrepareForTest({ SSLConfiguration.class, SSLContextFactory.class, +@PrepareForTest({ SSLContextFactory.class, SSLEngine.class, SSLContext.class }) public class ConfigurationServerContextTest { ConfigurationServerContext ctx; + SSLConfiguration mockSSLConf; @Before public void setUp() { BundleContext bCtx = mock(BundleContext.class); - ctx = new ConfigurationServerContext(bCtx); + mockSSLConf = mock(SSLConfiguration.class); + when(mockSSLConf.enableForCmdChannel()).thenReturn(false); + ctx = new ConfigurationServerContext(bCtx, mockSSLConf); } @Test @@ -113,12 +117,11 @@ @Test public void testBootstrapSSL() throws Exception { - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.enableForCmdChannel()).thenReturn(true); + when(mockSSLConf.enableForCmdChannel()).thenReturn(true); PowerMockito.mockStatic(SSLContextFactory.class); // SSL classes need to be mocked with PowerMockito SSLContext context = PowerMockito.mock(SSLContext.class); - when(SSLContextFactory.getServerContext()).thenReturn(context); + when(SSLContextFactory.getServerContext(isA(SSLConfiguration.class))).thenReturn(context); SSLEngine engine = PowerMockito.mock(SSLEngine.class); when(context.createSSLEngine()).thenReturn(engine);
--- a/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/ServerHandlerTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/agent/command/src/test/java/com/redhat/thermostat/agent/command/internal/ServerHandlerTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -46,25 +46,17 @@ import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.handler.ssl.SslHandler; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import com.redhat.thermostat.agent.command.internal.ServerHandler.SSLHandshakeDoneListener; -import com.redhat.thermostat.common.ssl.SSLConfiguration; +import com.redhat.thermostat.shared.config.SSLConfiguration; -@RunWith(PowerMockRunner.class) -@PrepareForTest({ SSLConfiguration.class}) public class ServerHandlerTest { @Test public void channelConnectedAddsSSLListener() throws Exception { - ServerHandler handler = new ServerHandler(null); - - // enable ssl - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.enableForCmdChannel()).thenReturn(true); + SSLConfiguration mockSSLConf = mock(SSLConfiguration.class); + when(mockSSLConf.enableForCmdChannel()).thenReturn(true); + ServerHandler handler = new ServerHandler(null, mockSSLConf); ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); ChannelPipeline pipeline = mock(ChannelPipeline.class);
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/internal/Activator.java Fri Nov 15 16:15:18 2013 -0700 +++ b/client/command/src/main/java/com/redhat/thermostat/client/command/internal/Activator.java Fri Nov 15 17:28:05 2013 -0700 @@ -38,11 +38,15 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.redhat.thermostat.client.command.RequestQueue; import com.redhat.thermostat.client.command.cli.PingCommand; import com.redhat.thermostat.common.cli.CommandRegistryImpl; +import com.redhat.thermostat.shared.config.SSLConfiguration; public class Activator implements BundleActivator { @@ -50,31 +54,73 @@ private ServiceRegistration queueRegistration; private ConfigurationRequestContext configContext; private CommandRegistryImpl reg; + private ServiceTracker queueDepsTracker; - public Activator() { - configContext = new ConfigurationRequestContext(); - queue = new RequestQueueImpl(configContext); + @Override + public void start(BundleContext context) throws Exception { + queueDepsTracker = new ServiceTracker(context, SSLConfiguration.class, new DepsCustomizer(context)); + queueDepsTracker.open(); } @Override - public void start(BundleContext context) throws Exception { + public void stop(BundleContext context) throws Exception { + if (queueDepsTracker != null) { + queueDepsTracker.close(); + queueDepsTracker = null; + } + deactivate(); + } + + private class DepsCustomizer implements ServiceTrackerCustomizer { + + private BundleContext context; + + DepsCustomizer(BundleContext context) { + this.context = context; + } + + @Override + public Object addingService(ServiceReference reference) { + SSLConfiguration sslConf = (SSLConfiguration) context.getService(reference); + activate(sslConf, context); + return sslConf; + } + + @Override + public void modifiedService(ServiceReference reference, Object service) { + // Do nothing + } + + @Override + public void removedService(ServiceReference reference, Object service) { + deactivate(); + context.ungetService(reference); + } + } + + private synchronized void activate(SSLConfiguration sslConf, BundleContext context) { + configContext = new ConfigurationRequestContext(sslConf); + queue = new RequestQueueImpl(configContext); queueRegistration = context.registerService(RequestQueue.class.getName(), queue, null); queue.startProcessingRequests(); - reg = new CommandRegistryImpl(context); reg.registerCommand("ping", new PingCommand()); } - @Override - public void stop(BundleContext context) throws Exception { - queue.stopProcessingRequests(); + private synchronized void deactivate() { + if (reg != null) { + reg.unregisterCommands(); + reg = null; + } + if (queue != null) { + queue.stopProcessingRequests(); + queue = null; + } if (queueRegistration != null) { queueRegistration.unregister(); + queueRegistration = null; } configContext.getBootstrap().releaseExternalResources(); - - reg.unregisterCommands(); } - }
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContext.java Fri Nov 15 16:15:18 2013 -0700 +++ b/client/command/src/main/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContext.java Fri Nov 15 17:28:05 2013 -0700 @@ -53,8 +53,8 @@ import com.redhat.thermostat.common.command.ConfigurationCommandContext; import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; public class ConfigurationRequestContext implements ConfigurationCommandContext { @@ -62,16 +62,23 @@ private final ClientBootstrap bootstrap; - ConfigurationRequestContext() { + private final SSLConfiguration sslConf; + + ConfigurationRequestContext(SSLConfiguration sslConf) { + this.sslConf = sslConf; this.bootstrap = createBootstrap(); } @Override - public - Bootstrap getBootstrap() { + public Bootstrap getBootstrap() { return bootstrap; } + @Override + public SSLConfiguration getSSLConfiguration() { + return sslConf; + } + private ClientBootstrap createBootstrap() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( @@ -95,8 +102,8 @@ @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); - if (SSLConfiguration.enableForCmdChannel()) { - SSLContext ctxt = SSLContextFactory.getClientContext(); + if (sslConf.enableForCmdChannel()) { + SSLContext ctxt = SSLContextFactory.getClientContext(sslConf); SSLEngine engine = ctxt.createSSLEngine(); engine.setUseClientMode(true); // intentionally don't set the endpoint identification algo,
--- a/client/command/src/main/java/com/redhat/thermostat/client/command/internal/RequestQueueImpl.java Fri Nov 15 16:15:18 2013 -0700 +++ b/client/command/src/main/java/com/redhat/thermostat/client/command/internal/RequestQueueImpl.java Fri Nov 15 17:28:05 2013 -0700 @@ -57,7 +57,6 @@ import com.redhat.thermostat.common.command.RequestResponseListener; import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.AuthToken; import com.redhat.thermostat.storage.core.SecureStorage; @@ -156,7 +155,7 @@ if (f.isSuccess()) { Channel c = f.getChannel(); ChannelPipeline pipeline = c.getPipeline(); - if (SSLConfiguration.enableForCmdChannel()) { + if (ctx.getSSLConfiguration().enableForCmdChannel()) { doSSLHandShake(pipeline, request); } pipeline.addLast("responseHandler", new ResponseHandler(request)); @@ -188,7 +187,7 @@ // Register a future listener, since it gives us a way to // report an error on client side and to perform (optional) host name verification. - boolean performHostnameCheck = !SSLConfiguration.disableHostnameVerification(); + boolean performHostnameCheck = !ctx.getSSLConfiguration().disableHostnameVerification(); future.addListener(new SSLHandshakeFinishedListener(request, performHostnameCheck, sslHandler, this)); }
--- a/client/command/src/test/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContextTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/client/command/src/test/java/com/redhat/thermostat/client/command/internal/ConfigurationRequestContextTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -39,8 +39,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.io.File; + import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; @@ -59,7 +63,7 @@ import org.powermock.modules.junit4.PowerMockRunner; import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SSLConfiguration; +import com.redhat.thermostat.shared.config.SSLConfiguration; @RunWith(PowerMockRunner.class) @PrepareForTest({ SSLConfiguration.class, SSLContextFactory.class, @@ -67,10 +71,15 @@ public class ConfigurationRequestContextTest { ConfigurationRequestContext ctx; + SSLConfiguration mockSSLConf; @Before public void setUp() { - ctx = new ConfigurationRequestContext(); + mockSSLConf = mock(SSLConfiguration.class); + when(mockSSLConf.enableForCmdChannel()).thenReturn(false); + when(mockSSLConf.getKeystoreFile()).thenReturn(new File("/opt/not/really/here")); + when(mockSSLConf.getKeyStorePassword()).thenReturn("fizzle"); + ctx = new ConfigurationRequestContext(mockSSLConf); } @After @@ -80,13 +89,11 @@ @Test public void testSSLHandlersAdded() throws Exception { - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.enableForCmdChannel()).thenReturn( - true); + when(mockSSLConf.enableForCmdChannel()).thenReturn(true); PowerMockito.mockStatic(SSLContextFactory.class); // SSL classes need to be mocked with PowerMockito SSLContext context = PowerMockito.mock(SSLContext.class); - when(SSLContextFactory.getClientContext()).thenReturn(context); + when(SSLContextFactory.getClientContext(isA(SSLConfiguration.class))).thenReturn(context); SSLEngine engine = PowerMockito.mock(SSLEngine.class); when(context.createSSLEngine()).thenReturn(engine);
--- a/common/command/src/main/java/com/redhat/thermostat/common/command/ConfigurationCommandContext.java Fri Nov 15 16:15:18 2013 -0700 +++ b/common/command/src/main/java/com/redhat/thermostat/common/command/ConfigurationCommandContext.java Fri Nov 15 17:28:05 2013 -0700 @@ -38,9 +38,13 @@ import org.jboss.netty.bootstrap.Bootstrap; +import com.redhat.thermostat.shared.config.SSLConfiguration; + public interface ConfigurationCommandContext { public Bootstrap getBootstrap(); + public SSLConfiguration getSSLConfiguration(); + }
--- a/common/core/src/main/java/com/redhat/thermostat/common/internal/CustomX509TrustManager.java Fri Nov 15 16:15:18 2013 -0700 +++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/CustomX509TrustManager.java Fri Nov 15 17:28:05 2013 -0700 @@ -53,9 +53,9 @@ import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.ssl.SslInitException; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; /** * Custom X509TrustManager which first attempts to verify peer certificates @@ -99,8 +99,8 @@ /* * Main constructor, which uses ssl.properties as config if present. */ - CustomX509TrustManager() throws SslInitException { - this(SSLConfiguration.getKeystoreFile(), SSLConfiguration.getKeyStorePassword()); + CustomX509TrustManager(SSLConfiguration sslConf) throws SslInitException { + this(sslConf.getKeystoreFile(), sslConf.getKeyStorePassword()); } private X509TrustManager getDefaultTrustManager() throws SslInitException {
--- a/common/core/src/main/java/com/redhat/thermostat/common/internal/TrustManagerFactory.java Fri Nov 15 16:15:18 2013 -0700 +++ b/common/core/src/main/java/com/redhat/thermostat/common/internal/TrustManagerFactory.java Fri Nov 15 17:28:05 2013 -0700 @@ -39,6 +39,7 @@ import javax.net.ssl.X509TrustManager; import com.redhat.thermostat.common.ssl.SslInitException; +import com.redhat.thermostat.shared.config.SSLConfiguration; /** @@ -51,8 +52,8 @@ * @return the thermostat X509TrustManager. * @throws SslInitException if an error occured retrieving the trust manager. */ - public static X509TrustManager getTrustManager() throws SslInitException { - return new CustomX509TrustManager(); + public static X509TrustManager getTrustManager(SSLConfiguration sslConf) throws SslInitException { + return new CustomX509TrustManager(sslConf); } }
--- a/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLConfiguration.java Fri Nov 15 16:15:18 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * Copyright 2012, 2013 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.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.Configuration; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; - -public class SSLConfiguration { - - private static Properties clientProps = null; - private static final String KEYSTORE_FILE_KEY = "KEYSTORE_FILE"; - private static final String KEYSTORE_FILE_PWD_KEY = "KEYSTORE_PASSWORD"; - private static final String CMD_CHANNEL_SSL_KEY = "COMMAND_CHANNEL_USE_SSL"; - private static final String BACKING_STORAGE_USE_SSL_KEY = "BACKING_STORAGE_CONNECTION_USE_SSL"; - private static final String DISABLE_HOSTNAME_VERIFICATION = "DISABLE_HOSTNAME_VERIFICATION"; - private static final Logger logger = LoggingUtils.getLogger(SSLConfiguration.class); - - /** - * - * @return The keystore file as specified in $THERMOSTAT_HOME/etc/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/etc/ssl.properties - * if any, null otherwise. - */ - public static String getKeyStorePassword() { - try { - loadClientProperties(); - } catch (InvalidConfigurationException e) { - // Thermostat home not set? Do something reasonable - return null; - } - String pwd = clientProps.getProperty(KEYSTORE_FILE_PWD_KEY); - return pwd; - } - - /** - * - * @return true if and only if SSL should be enabled for command channel - * communication between agent and client. I.e. if - * $THERMOSTAT_HOME/etc/ssl.properties exists and proper config has - * been added. false otherwise. - */ - public static boolean enableForCmdChannel() { - return readBooleanProperty(CMD_CHANNEL_SSL_KEY); - } - - /** - * - * @return true if and only if SSL should be used for backing storage - * connections. I.e. if $THERMOSTAT_HOME/etc/ssl.properties exists - * and proper config has been added. false otherwise. - */ - public static boolean enableForBackingStorage() { - return readBooleanProperty(BACKING_STORAGE_USE_SSL_KEY); - } - - /** - * - * @return true if and only if host name verification should not be - * performed during SSL handshake. In other words if - * $THERMOSTAT_HOME/etc/ssl.properties exists and proper config has - * been added. false otherwise. - */ - public static boolean disableHostnameVerification() { - return readBooleanProperty(DISABLE_HOSTNAME_VERIFICATION); - } - - // 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 boolean readBooleanProperty(final String property) { - boolean result = false; - try { - loadClientProperties(); - } catch (InvalidConfigurationException e) { - logger.log(Level.WARNING, - "THERMOSTAT_HOME not set and config file attempted to be " + - "read from there! Returning false."); - return result; - } - String token = clientProps.getProperty(property); - if (token != null) { - result = Boolean.parseBoolean(token); - } - return result; - } - - private static void loadClientProperties() - throws InvalidConfigurationException { - if (clientProps == null) { - File clientPropertiesFile = new File(new Configuration().getUserConfigurationDirectory(), - "ssl.properties"); - initClientProperties(clientPropertiesFile); - } - } -} -
--- a/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLContextFactory.java Fri Nov 15 16:15:18 2013 -0700 +++ b/common/core/src/main/java/com/redhat/thermostat/common/ssl/SSLContextFactory.java Fri Nov 15 17:28:05 2013 -0700 @@ -64,6 +64,7 @@ import com.redhat.thermostat.common.internal.DelegateSSLSocketFactory; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.InvalidConfigurationException; +import com.redhat.thermostat.shared.config.SSLConfiguration; public class SSLContextFactory { @@ -82,12 +83,12 @@ * @throws SslInitException * @throws InvalidConfigurationException */ - public static SSLContext getServerContext() throws SslInitException, + public static SSLContext getServerContext(SSLConfiguration sslConf) throws SslInitException, InvalidConfigurationException { if (serverContext != null) { return serverContext; } - initServerContext(); + initServerContext(sslConf); return serverContext; } @@ -97,11 +98,11 @@ * registered. * @throws SslInitException if SSL initialization failed. */ - public static SSLContext getClientContext() throws SslInitException { + public static SSLContext getClientContext(SSLConfiguration sslConf) throws SslInitException { if (clientContext != null) { return clientContext; } - initClientContext(); + initClientContext(sslConf); return clientContext; } @@ -131,24 +132,23 @@ return params; } - private static void initClientContext() throws SslInitException { + private static void initClientContext(SSLConfiguration sslConf) throws SslInitException { SSLContext clientCtxt = null; try { clientCtxt = getContextInstance(); // Don't need key managers for client mode - clientCtxt.init(null, getTrustManagers(), new SecureRandom()); + clientCtxt.init(null, getTrustManagers(sslConf), new SecureRandom()); } catch (KeyManagementException e) { throw new SslInitException(e); } clientContext = clientCtxt; } - private static void initServerContext() throws SslInitException, + private static void initServerContext(SSLConfiguration sslConf) throws SslInitException, InvalidConfigurationException { SSLContext serverCtxt = null; - File trustStoreFile = SSLConfiguration.getKeystoreFile(); - String keyStorePassword = SSLConfiguration - .getKeyStorePassword(); + File trustStoreFile = sslConf.getKeystoreFile(); + String keyStorePassword = sslConf.getKeyStorePassword(); KeyStore ks = KeyStoreProvider.getKeyStore(trustStoreFile, keyStorePassword); if (ks == null) { @@ -162,15 +162,15 @@ serverCtxt = getContextInstance(); // Initialize the SSLContext to work with our key and trust managers. serverCtxt.init(getKeyManagers(ks, keyStorePassword), - getTrustManagers(), new SecureRandom()); + getTrustManagers(sslConf), new SecureRandom()); } catch (GeneralSecurityException e) { throw new SslInitException(e); } serverContext = serverCtxt; } - private static TrustManager[] getTrustManagers() throws SslInitException { - TrustManager tm = TrustManagerFactory.getTrustManager(); + private static TrustManager[] getTrustManagers(SSLConfiguration sslConf) throws SslInitException { + TrustManager tm = TrustManagerFactory.getTrustManager(sslConf); return new TrustManager[] { tm }; }
--- a/common/core/src/test/java/com/redhat/thermostat/common/ssl/SSLConfigurationTest.java Fri Nov 15 16:15:18 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright 2012, 2013 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 static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.File; - -import org.junit.Test; - -import com.redhat.thermostat.common.ssl.SSLConfiguration; - -public class SSLConfigurationTest { - - @Test - public void canGetKeystoreFileFromProps() throws Exception { - File clientProps = new File(this.getClass().getResource("/client.properties").getFile()); - SSLConfiguration.initClientProperties(clientProps); - String keystorePath = "/path/to/thermostat.keystore"; - String keystorePwd = "some password"; - assertEquals(keystorePath, SSLConfiguration.getKeystoreFile().getAbsolutePath()); - assertEquals(keystorePwd, SSLConfiguration.getKeyStorePassword()); - } - - @Test - public void notExistingPropertiesFileReturnsNull() throws Exception { - File clientProps = new File("i/am/not/there/file.txt"); - SSLConfiguration.initClientProperties(clientProps); - assertTrue(SSLConfiguration.getKeystoreFile() == null); - assertEquals(null, SSLConfiguration.getKeyStorePassword()); - } - - @Test - public void canGetSSLEnabledConfigs() { - File clientProps = new File(this.getClass().getResource("/client.properties").getFile()); - SSLConfiguration.initClientProperties(clientProps); - assertTrue(SSLConfiguration.enableForCmdChannel()); - assertTrue(SSLConfiguration.enableForBackingStorage()); - assertTrue(SSLConfiguration.disableHostnameVerification()); - clientProps = new File(this.getClass().getResource("/ssl.properties").getFile()); - SSLConfiguration.initClientProperties(clientProps); - assertFalse(SSLConfiguration.enableForCmdChannel()); - assertFalse(SSLConfiguration.enableForBackingStorage()); - assertFalse(SSLConfiguration.disableHostnameVerification()); - } -} -
--- a/common/core/src/test/java/com/redhat/thermostat/common/ssl/SSLContextFactoryTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/common/core/src/test/java/com/redhat/thermostat/common/ssl/SSLContextFactoryTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -39,6 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,9 +63,10 @@ import org.powermock.modules.junit4.PowerMockRunner; import com.redhat.thermostat.common.internal.TrustManagerFactory; +import com.redhat.thermostat.shared.config.SSLConfiguration; @RunWith(PowerMockRunner.class) -@PrepareForTest({ SSLConfiguration.class, SSLContext.class, KeyManagerFactory.class, javax.net.ssl.TrustManagerFactory.class }) +@PrepareForTest({ SSLContext.class, KeyManagerFactory.class, javax.net.ssl.TrustManagerFactory.class }) public class SSLContextFactoryTest { /* @@ -83,10 +85,10 @@ File keystoreFile = new File(this.getClass() .getResource("/cmdChanServer.keystore").getFile()); - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.getKeystoreFile()).thenReturn( + SSLConfiguration sslConf = mock(SSLConfiguration.class); + when(sslConf.getKeystoreFile()).thenReturn( keystoreFile); - when(SSLConfiguration.getKeyStorePassword()).thenReturn( + when(sslConf.getKeyStorePassword()).thenReturn( "testpassword"); PowerMockito.mockStatic(SSLContext.class); @@ -106,7 +108,7 @@ when(mockTrustFactory.getTrustManagers()).thenReturn(new TrustManager[0]); when(javax.net.ssl.TrustManagerFactory.getInstance("SunX509", "SunJSSE")).thenReturn(mockTrustFactory); - SSLContextFactory.getServerContext(); + SSLContextFactory.getServerContext(sslConf); verify(context).init(keymanagersCaptor.capture(), tmsCaptor.capture(), any(SecureRandom.class)); KeyManager[] kms = keymanagersCaptor.getValue(); @@ -128,10 +130,10 @@ File keystoreFile = new File(this.getClass() .getResource("/cmdChanServer.keystore").getFile()); - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.getKeystoreFile()).thenReturn( + SSLConfiguration sslConf = mock(SSLConfiguration.class); + when(sslConf.getKeystoreFile()).thenReturn( keystoreFile); - when(SSLConfiguration.getKeyStorePassword()).thenReturn( + when(sslConf.getKeyStorePassword()).thenReturn( "testpassword"); PowerMockito.mockStatic(SSLContext.class); @@ -144,7 +146,7 @@ ArgumentCaptor<TrustManager[]> tmsCaptor = ArgumentCaptor .forClass(TrustManager[].class); - SSLContextFactory.getClientContext(); + SSLContextFactory.getClientContext(sslConf); verify(context).init(any(KeyManager[].class), tmsCaptor.capture(), any(SecureRandom.class)); TrustManager[] tms = tmsCaptor.getValue(); @@ -157,6 +159,7 @@ @Test @PrepareForTest({TrustManagerFactory.class, SSLContext.class}) public void verifyTLSVersionFallsBackProperlyToTLS11() throws Exception { + SSLConfiguration sslConf = mock(SSLConfiguration.class); PowerMockito.mockStatic(SSLContext.class); when(SSLContext.getInstance("TLSv1.2", "SunJSSE")).thenThrow( NoSuchAlgorithmException.class); @@ -164,8 +167,8 @@ when(SSLContext.getInstance("TLSv1.1", "SunJSSE")).thenReturn(context); PowerMockito.mockStatic(TrustManagerFactory.class); X509TrustManager tm = PowerMockito.mock(X509TrustManager.class); - when(TrustManagerFactory.getTrustManager()).thenReturn(tm); - SSLContextFactory.getClientContext(); + when(TrustManagerFactory.getTrustManager(isA(SSLConfiguration.class))).thenReturn(tm); + SSLContextFactory.getClientContext(sslConf); verify(context).init(any(KeyManager[].class), any(TrustManager[].class), any(SecureRandom.class)); } @@ -174,6 +177,7 @@ @Test @PrepareForTest({TrustManagerFactory.class, SSLContext.class}) public void verifyTLSVersionFallsBackProperlyToTLS10() throws Exception { + SSLConfiguration sslConf = mock(SSLConfiguration.class); PowerMockito.mockStatic(SSLContext.class); when(SSLContext.getInstance("TLSv1.2", "SunJSSE")).thenThrow( NoSuchAlgorithmException.class); @@ -183,8 +187,8 @@ when(SSLContext.getInstance("TLSv1", "SunJSSE")).thenReturn(context); PowerMockito.mockStatic(TrustManagerFactory.class); X509TrustManager tm = PowerMockito.mock(X509TrustManager.class); - when(TrustManagerFactory.getTrustManager()).thenReturn(tm); - SSLContextFactory.getClientContext(); + when(TrustManagerFactory.getTrustManager(isA(SSLConfiguration.class))).thenReturn(tm); + SSLContextFactory.getClientContext(sslConf); verify(context).init(any(KeyManager[].class), any(TrustManager[].class), any(SecureRandom.class)); } @@ -194,6 +198,7 @@ @PrepareForTest({TrustManagerFactory.class, SSLContext.class}) public void throwAssertionErrorIfNoReasonableTlsAvailable() throws Exception { + SSLConfiguration sslConf = mock(SSLConfiguration.class); PowerMockito.mockStatic(SSLContext.class); when(SSLContext.getInstance("TLSv1.2", "SunJSSE")).thenThrow( NoSuchAlgorithmException.class); @@ -202,7 +207,7 @@ when(SSLContext.getInstance("TLSv1", "SunJSSE")).thenThrow( NoSuchAlgorithmException.class); try { - SSLContextFactory.getClientContext(); + SSLContextFactory.getClientContext(sslConf); fail("No suitable algos available, which should trigger AssertionError"); } catch (AssertionError e) { // pass
--- a/common/core/src/test/resources/client.properties Fri Nov 15 16:15:18 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -# Random comment -KEYSTORE_FILE=/path/to/thermostat.keystore -KEYSTORE_PASSWORD=some password -COMMAND_CHANNEL_USE_SSL=true -BACKING_STORAGE_CONNECTION_USE_SSL=true -DISABLE_HOSTNAME_VERIFICATION=true \ No newline at end of file
--- a/common/core/src/test/resources/ssl.properties Fri Nov 15 16:15:18 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -COMMAND_CHANNEL_USE_SSL=somethingNotABoolean -# this does not parse as a boolean -DISABLE_HOSTNAME_VERIFICATION=yes \ No newline at end of file
--- a/config/pom.xml Fri Nov 15 16:15:18 2013 -0700 +++ b/config/pom.xml Fri Nov 15 17:28:05 2013 -0700 @@ -21,10 +21,14 @@ <instructions> <Bundle-SymbolicName>com.redhat.thermostat.configuration</Bundle-SymbolicName> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> + <Bundle-Activator>com.redhat.thermostat.shared.config.internal.Activator</Bundle-Activator> <Export-Package> com.redhat.thermostat.shared.locale, com.redhat.thermostat.shared.config, </Export-Package> + <Private-Package> + com.redhat.thermostat.shared.config.internal, + </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses> </instructions> @@ -57,5 +61,11 @@ <version>${project.version}</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> </dependencies> </project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/main/java/com/redhat/thermostat/shared/config/SSLConfiguration.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright 2012, 2013 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.shared.config; + +import java.io.File; + +public interface SSLConfiguration { + + /** + * + * @return The keystore file as specified in $THERMOSTAT_HOME/etc/ssl.properties + * if any. null otherwise. + */ + public File getKeystoreFile(); + + /** + * + * @return The keystore password as specified in $THERMOSTAT_HOME/etc/ssl.properties + * if any, null otherwise. + */ + public String getKeyStorePassword(); + + /** + * + * @return true if and only if SSL should be enabled for command channel + * communication between agent and client. I.e. if + * $THERMOSTAT_HOME/etc/ssl.properties exists and proper config has + * been added. false otherwise. + */ + public boolean enableForCmdChannel(); + + /** + * + * @return true if and only if SSL should be used for backing storage + * connections. I.e. if $THERMOSTAT_HOME/etc/ssl.properties exists + * and proper config has been added. false otherwise. + */ + public boolean enableForBackingStorage(); + + /** + * + * @return true if and only if host name verification should not be + * performed during SSL handshake. In other words if + * $THERMOSTAT_HOME/etc/ssl.properties exists and proper config has + * been added. false otherwise. + */ + public boolean disableHostnameVerification(); + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/main/java/com/redhat/thermostat/shared/config/internal/Activator.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright 2013 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.shared.config.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +import com.redhat.thermostat.shared.config.SSLConfiguration; + +public class Activator implements BundleActivator { + + @Override + public void start(BundleContext context) throws Exception { + SSLConfiguration sslConf = new SSLConfigurationImpl(); + context.registerService(SSLConfiguration.class.getName(), sslConf, null); + } + + @Override + public void stop(BundleContext context) throws Exception { + // Nothing to do + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/main/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImpl.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,141 @@ +/* + * Copyright 2012, 2013 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.shared.config.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.shared.config.Configuration; +import com.redhat.thermostat.shared.config.InvalidConfigurationException; +import com.redhat.thermostat.shared.config.SSLConfiguration; + +public class SSLConfigurationImpl implements SSLConfiguration { + + private Properties clientProps = null; + private static final String KEYSTORE_FILE_KEY = "KEYSTORE_FILE"; + private static final String KEYSTORE_FILE_PWD_KEY = "KEYSTORE_PASSWORD"; + private static final String CMD_CHANNEL_SSL_KEY = "COMMAND_CHANNEL_USE_SSL"; + private static final String BACKING_STORAGE_USE_SSL_KEY = "BACKING_STORAGE_CONNECTION_USE_SSL"; + private static final String DISABLE_HOSTNAME_VERIFICATION = "DISABLE_HOSTNAME_VERIFICATION"; + private static final Logger logger = Logger.getLogger(SSLConfigurationImpl.class.getName()); + + @Override + public 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; + } + + @Override + public String getKeyStorePassword() { + try { + loadClientProperties(); + } catch (InvalidConfigurationException e) { + // Thermostat home not set? Do something reasonable + return null; + } + String pwd = clientProps.getProperty(KEYSTORE_FILE_PWD_KEY); + return pwd; + } + + @Override + public boolean enableForCmdChannel() { + return readBooleanProperty(CMD_CHANNEL_SSL_KEY); + } + + @Override + public boolean enableForBackingStorage() { + return readBooleanProperty(BACKING_STORAGE_USE_SSL_KEY); + } + + @Override + public boolean disableHostnameVerification() { + return readBooleanProperty(DISABLE_HOSTNAME_VERIFICATION); + } + + // testing hook + 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 boolean readBooleanProperty(final String property) { + boolean result = false; + try { + loadClientProperties(); + } catch (InvalidConfigurationException e) { + logger.log(Level.WARNING, + "THERMOSTAT_HOME not set and config file attempted to be " + + "read from there! Returning false."); + return result; + } + String token = clientProps.getProperty(property); + if (token != null) { + result = Boolean.parseBoolean(token); + } + return result; + } + + private void loadClientProperties() + throws InvalidConfigurationException { + if (clientProps == null) { + File clientPropertiesFile = new File(new Configuration().getUserConfigurationDirectory(), + "ssl.properties"); + initClientProperties(clientPropertiesFile); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/test/java/com/redhat/thermostat/shared/config/internal/ActivatorTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright 2013 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.shared.config.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.testutils.StubBundleContext; + +public class ActivatorTest { + + @Test + public void verifyServiceRegistered() throws Exception { + StubBundleContext ctx = new StubBundleContext(); + Activator activator = new Activator(); + activator.start(ctx); + + assertTrue(ctx.isServiceRegistered(SSLConfiguration.class.getName(), + SSLConfigurationImpl.class)); + assertEquals(1, ctx.getAllServices().size()); + + } + + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/test/java/com/redhat/thermostat/shared/config/internal/SSLConfigurationImplTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,91 @@ +/* + * Copyright 2012, 2013 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.shared.config.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl; + +public class SSLConfigurationImplTest { + + private SSLConfigurationImpl sslConf; + + @Before + public void setUp() { + sslConf = new SSLConfigurationImpl(); + File clientProps = new File(this.getClass().getResource("/client.properties").getFile()); + sslConf.initClientProperties(clientProps); + } + + @Test + public void canGetKeystoreFileFromProps() throws Exception { + String keystorePath = "/path/to/thermostat.keystore"; + String keystorePwd = "some password"; + assertEquals(keystorePath, sslConf.getKeystoreFile().getAbsolutePath()); + assertEquals(keystorePwd, sslConf.getKeyStorePassword()); + } + + @Test + public void notExistingPropertiesFileReturnsNull() throws Exception { + SSLConfigurationImpl badSSLConf = new SSLConfigurationImpl(); + File clientProps = new File("i/am/not/there/file.txt"); + badSSLConf.initClientProperties(clientProps); + assertTrue(badSSLConf.getKeystoreFile() == null); + assertEquals(null, badSSLConf.getKeyStorePassword()); + } + + @Test + public void canGetSSLEnabledConfigs() { + assertTrue(sslConf.enableForCmdChannel()); + assertTrue(sslConf.enableForBackingStorage()); + assertTrue(sslConf.disableHostnameVerification()); + File disabledSSLProps = new File(this.getClass().getResource("/ssl.properties").getFile()); + SSLConfigurationImpl disabledSSLConf = new SSLConfigurationImpl(); + disabledSSLConf.initClientProperties(disabledSSLProps); + assertFalse(disabledSSLConf.enableForCmdChannel()); + assertFalse(disabledSSLConf.enableForBackingStorage()); + assertFalse(disabledSSLConf.disableHostnameVerification()); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/test/resources/client.properties Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,6 @@ +# Random comment +KEYSTORE_FILE=/path/to/thermostat.keystore +KEYSTORE_PASSWORD=some password +COMMAND_CHANNEL_USE_SSL=true +BACKING_STORAGE_CONNECTION_USE_SSL=true +DISABLE_HOSTNAME_VERIFICATION=true \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/src/test/resources/ssl.properties Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,3 @@ +COMMAND_CHANNEL_USE_SSL=somethingNotABoolean +# this does not parse as a boolean +DISABLE_HOSTNAME_VERIFICATION=yes \ No newline at end of file
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -55,6 +55,8 @@ import com.redhat.thermostat.host.cpu.common.CpuStatDAO; import com.redhat.thermostat.host.cpu.common.model.CpuStat; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.BackingStorage; @@ -142,7 +144,8 @@ } }; - BackingStorage storage = new MongoStorage(config); + SSLConfiguration sslConf = new SSLConfigurationImpl(); + BackingStorage storage = new MongoStorage(config, sslConf); if (listener != null) { storage.getConnection().addListener(listener); }
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -75,6 +75,8 @@ import com.redhat.thermostat.common.ApplicationInfo; import com.redhat.thermostat.host.cpu.common.CpuStatDAO; import com.redhat.thermostat.host.cpu.common.model.CpuStat; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl; import com.redhat.thermostat.storage.config.ConnectionConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Add; @@ -300,7 +302,35 @@ private static BackingStorage getAndConnectBackingStorage() { String url = "mongodb://127.0.0.1:27518"; StartupConfiguration config = new ConnectionConfiguration(url, "", ""); - BackingStorage storage = new MongoStorage(config); + SSLConfiguration sslConfig = new SSLConfiguration() { + + @Override + public File getKeystoreFile() { + return null; + } + + @Override + public String getKeyStorePassword() { + return null; + } + + @Override + public boolean enableForCmdChannel() { + // Simple case. + return false; + } + + @Override + public boolean enableForBackingStorage() { + return false; + } + + @Override + public boolean disableHostnameVerification() { + return false; + } + }; + BackingStorage storage = new MongoStorage(config, sslConfig); storage.getConnection().connect(); return storage; } @@ -327,7 +357,8 @@ setupJAASForUser(roleNames, username, password); String url = "http://localhost:" + port + "/thermostat/storage"; StartupConfiguration config = new ConnectionConfiguration(url, username, password); - Storage storage = new WebStorage(config); + SSLConfiguration sslConf = new SSLConfigurationImpl(); + Storage storage = new WebStorage(config, sslConf); if (listener != null) { storage.getConnection().addListener(listener); }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/StorageProvider.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/StorageProvider.java Fri Nov 15 17:28:05 2013 -0700 @@ -36,6 +36,7 @@ package com.redhat.thermostat.storage.core; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; /** @@ -56,8 +57,9 @@ * {@link StorageProvider#canHandleProtocol()}. * * @param config + * @param sslConf */ - void setConfig(StartupConfiguration config); + void setConfig(StartupConfiguration config, SSLConfiguration sslConf); /** * Method which determines if this StorageProvider can handle the given
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java Fri Nov 15 17:28:05 2013 -0700 @@ -47,6 +47,7 @@ import org.osgi.framework.ServiceRegistration; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.ConnectionConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; @@ -68,6 +69,7 @@ private Storage storage; private BundleContext context; private String dbUrl; + private static ServiceReference sslConfRef; DbServiceImpl(String username, String password, String dbUrl) throws StorageException { BundleContext context = FrameworkUtil.getBundle(DbService.class).getBundleContext(); @@ -103,10 +105,17 @@ // during connection handling. doSynchronousConnect(); } catch (Exception cause) { + if (sslConfRef != null) { + context.ungetService(sslConfRef); + } throw new ConnectionException(cause); } // Connection didn't throw an exception. Now it is safe to register - // services. + // services for general consumption and unregister services used + // only while creating and connecting Storage. + if (sslConfRef != null) { + context.ungetService(sslConfRef); + } dbServiceReg = context.registerService(DbService.class, this, null); storageReg = context.registerService(Storage.class.getName(), this.storage, null); } @@ -224,9 +233,14 @@ if (refs == null) { throw new StorageException("No storage provider available"); } + sslConfRef = context.getServiceReference(SSLConfiguration.class.getName()); + if (sslConfRef == null) { + throw new StorageException("No SSL configuration available"); + } + SSLConfiguration sslConf = (SSLConfiguration) context.getService(sslConfRef); for (int i = 0; i < refs.length; i++) { StorageProvider prov = (StorageProvider) context.getService(refs[i]); - prov.setConfig(config); + prov.setConfig(config, sslConf); if (prov.canHandleProtocol()) { return prov; }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -51,6 +51,7 @@ import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.core.Connection; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; @@ -73,6 +74,8 @@ @Before public void setup() { context = new StubBundleContext(); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + context.registerService(SSLConfiguration.class.getName(), sslConf, null); storage = mock(Storage.class); when(storage.getConnection()).thenReturn(connection);
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/MongoStorageProvider.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/MongoStorageProvider.java Fri Nov 15 17:28:05 2013 -0700 @@ -36,6 +36,7 @@ package com.redhat.thermostat.storage.mongodb; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.QueuedStorage; import com.redhat.thermostat.storage.core.Storage; @@ -45,14 +46,16 @@ public class MongoStorageProvider implements StorageProvider { private StartupConfiguration configuration; + private SSLConfiguration sslConf; - public void setConfig(StartupConfiguration configuration) { + public void setConfig(StartupConfiguration configuration, SSLConfiguration sslConf) { this.configuration = configuration; + this.sslConf = sslConf; } @Override public Storage createStorage() { - MongoStorage storage = new MongoStorage(configuration); + MongoStorage storage = new MongoStorage(configuration, sslConf); return new QueuedStorage(storage); }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java Fri Nov 15 17:28:05 2013 -0700 @@ -51,11 +51,11 @@ import com.mongodb.MongoOptions; import com.mongodb.ServerAddress; import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SSLConfiguration; import com.redhat.thermostat.common.ssl.SslInitException; import com.redhat.thermostat.common.utils.HostPortPair; import com.redhat.thermostat.common.utils.HostPortsParser; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Connection; @@ -69,9 +69,11 @@ private Mongo m = null; private DB db = null; private StartupConfiguration conf; + SSLConfiguration sslConf; - MongoConnection(StartupConfiguration conf) { + MongoConnection(StartupConfiguration conf, SSLConfiguration sslConf) { this.conf = conf; + this.sslConf = sslConf; } @Override @@ -121,8 +123,9 @@ return db; } - private void createConnection() throws MongoException, UnknownHostException { - if (SSLConfiguration.enableForBackingStorage()) { + // package visibility for testing purposes. + void createConnection() throws MongoException, UnknownHostException { + if (sslConf.enableForBackingStorage()) { logger.log(Level.FINE, "Using SSL socket for mongodb:// protocol"); this.m = getSSLMongo(); } else { @@ -136,14 +139,14 @@ MongoOptions opts = new MongoOptions(); SSLContext ctxt = null; try { - ctxt = SSLContextFactory.getClientContext(); + ctxt = SSLContextFactory.getClientContext(sslConf); } catch (SslInitException e) { logger.log(Level.WARNING, "Failed to get SSL context!", e); throw new MongoException(e.getMessage(), e); } SSLParameters params = SSLContextFactory.getSSLParameters(ctxt); // Perform HTTPS compatible host name checking. - if (!SSLConfiguration.disableHostnameVerification()) { + if (!sslConf.disableHostnameVerification()) { params.setEndpointIdentificationAlgorithm("HTTPS"); } SSLSocketFactory factory = SSLContextFactory.wrapSSLFactory(
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Fri Nov 15 17:28:05 2013 -0700 @@ -54,6 +54,7 @@ import com.mongodb.gridfs.GridFS; import com.mongodb.gridfs.GridFSDBFile; import com.mongodb.gridfs.GridFSInputFile; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.AbstractQuery.Sort; import com.redhat.thermostat.storage.core.Add; @@ -287,8 +288,8 @@ this.conn = null; } - public MongoStorage(StartupConfiguration conf) { - conn = new MongoConnection(conf); + public MongoStorage(StartupConfiguration conf, SSLConfiguration sslConf) { + conn = new MongoConnection(conf, sslConf); connectedLatch = new CountDownLatch(1); conn.addListener(new ConnectionListener() { @Override
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnectionTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnectionTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -41,6 +41,8 @@ import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -72,7 +74,7 @@ import com.mongodb.MongoURI; import com.mongodb.ServerAddress; import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SSLConfiguration; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; @@ -89,12 +91,16 @@ private MongoConnection conn; private ConnectionListener listener; + private SSLConfiguration mockSSLConf; @Before public void setUp() { StartupConfiguration conf = mock(StartupConfiguration.class); + mockSSLConf = mock(SSLConfiguration.class); + when(mockSSLConf.enableForBackingStorage()).thenReturn(false); when(conf.getDBConnectionString()).thenReturn("mongodb://127.0.0.1:27518"); - conn = new MongoConnection(conf); + + conn = new MongoConnection(conf, mockSSLConf); listener = mock(ConnectionListener.class); conn.addListener(listener); } @@ -165,17 +171,16 @@ assertTrue(exceptionThrown); } - @PrepareForTest({ MongoConnection.class, SSLConfiguration.class, + @PrepareForTest({ MongoConnection.class, SSLContextFactory.class, SSLContext.class, SSLSocketFactory.class }) @Test public void verifySSLSocketFactoryUsedIfSSLEnabled() throws Exception { - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.enableForBackingStorage()).thenReturn(true); + when(mockSSLConf.enableForBackingStorage()).thenReturn(true); PowerMockito.mockStatic(SSLContextFactory.class); // SSL classes need to be mocked with PowerMockito SSLContext context = PowerMockito.mock(SSLContext.class); - when(SSLContextFactory.getClientContext()).thenReturn(context); + when(SSLContextFactory.getClientContext(isA(SSLConfiguration.class))).thenReturn(context); SSLSocketFactory factory = PowerMockito.mock(SSLSocketFactory.class); when(SSLContextFactory.wrapSSLFactory(any(SSLSocketFactory.class), any(SSLParameters.class))).thenReturn(factory); SSLParameters params = mock(SSLParameters.class); @@ -198,14 +203,20 @@ assertEquals(factory, opts.socketFactory); } - @PrepareForTest({ SSLConfiguration.class, - SSLContextFactory.class, SSLContext.class, SSLSocketFactory.class }) + @PrepareForTest({ MongoConnection.class, SSLContextFactory.class, SSLContext.class, SSLSocketFactory.class }) @Test public void verifyNoSSLSocketFactoryUsedIfSSLDisabled() throws Exception { - PowerMockito.mockStatic(SSLConfiguration.class); - when(SSLConfiguration.enableForBackingStorage()).thenReturn(false); - + DBCollection collection = mock(DBCollection.class); + DB db = mock(DB.class); + when(db.getCollection("agent-config")).thenReturn(collection); + Mongo mockMongo = mock(Mongo.class); + when(mockMongo.getDB(MongoConnection.THERMOSTAT_DB_NAME)).thenReturn(db); + PowerMockito.whenNew(Mongo.class).withParameterTypes(ServerAddress.class) + .withArguments(any(ServerAddress.class)).thenReturn(mockMongo); MongoConnection connection = mock(MongoConnection.class); + doCallRealMethod().when(connection).connect(); + doCallRealMethod().when(connection).createConnection(); + connection.sslConf = mock(SSLConfiguration.class); connection.connect(); verify(connection, Mockito.times(0)).getSSLMongo(); } @@ -219,7 +230,8 @@ return "mongodb://127.0.1.1:23452"; } }; - MongoConnection connection = new MongoConnection(config); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + MongoConnection connection = new MongoConnection(config, sslConf); ServerAddress addr = null; try { addr = connection.getServerAddress(); @@ -236,7 +248,7 @@ return "fluff://willnotwork.com:23452"; } }; - connection = new MongoConnection(config); + connection = new MongoConnection(config, sslConf); try { connection.getServerAddress(); fail("should not have been able to parse address");
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageProviderTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageProviderTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -56,7 +56,7 @@ StartupConfiguration config = mock(StartupConfiguration.class); when(config.getDBConnectionString()).thenReturn("mongodb://something.com"); MongoStorageProvider provider = new MongoStorageProvider(); - provider.setConfig(config); + provider.setConfig(config, null); Storage result = provider.createStorage(); assertTrue(result instanceof QueuedStorage); assertFalse(result instanceof SecureStorage);
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -82,6 +82,7 @@ import com.mongodb.gridfs.GridFS; import com.mongodb.gridfs.GridFSDBFile; import com.mongodb.gridfs.GridFSInputFile; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.Add; import com.redhat.thermostat.storage.core.BackingStorage; @@ -173,6 +174,7 @@ private static final Category<TestClass> emptyTestCategory = new Category<>("MongoEmptyCategory", TestClass.class); private StartupConfiguration conf; + private SSLConfiguration sslConf; private Mongo m; private DB db; private DBCollection testCollection, emptyTestCollection, mockedCollection; @@ -180,7 +182,7 @@ private ExpressionFactory factory; private MongoStorage makeStorage() { - MongoStorage storage = new MongoStorage(conf); + MongoStorage storage = new MongoStorage(conf, sslConf); storage.mapCategoryToDBCollection(testCategory, testCollection); storage.mapCategoryToDBCollection(emptyTestCategory, emptyTestCollection); return storage; @@ -190,6 +192,7 @@ public void setUp() throws Exception { conf = mock(StartupConfiguration.class); when(conf.getDBConnectionString()).thenReturn("mongodb://127.0.0.1:27518"); + sslConf = mock(SSLConfiguration.class); db = PowerMockito.mock(DB.class); m = PowerMockito.mock(Mongo.class); mockedCollection = mock(DBCollection.class); @@ -253,7 +256,7 @@ @Test public void isBackingStorage() { - MongoStorage storage = new MongoStorage(conf); + MongoStorage storage = new MongoStorage(conf, sslConf); assertTrue(storage instanceof BackingStorage); } @@ -590,7 +593,7 @@ public void verifyMongoCloseOnShutdown() throws Exception { Mongo mockMongo = mock(Mongo.class); when(db.getMongo()).thenReturn(mockMongo); - MongoStorage storage = new MongoStorage(conf); + MongoStorage storage = new MongoStorage(conf, sslConf); setDbFieldInStorage(storage); storage.shutdown(); verify(mockMongo).close();
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorage.java Fri Nov 15 17:28:05 2013 -0700 @@ -83,6 +83,7 @@ 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.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.AuthToken; @@ -319,17 +320,19 @@ private WebConnection conn; // for testing - WebStorage(StartupConfiguration config, DefaultHttpClient client, ClientConnectionManager connManager) { - init(config, client, connManager); + WebStorage(StartupConfiguration config, DefaultHttpClient client, + ClientConnectionManager connManager, SSLConfiguration sslConf) { + init(config, client, connManager, sslConf); } - public WebStorage(StartupConfiguration config) throws StorageException { + public WebStorage(StartupConfiguration config, SSLConfiguration sslConf) throws StorageException { ClientConnectionManager connManager = new ThreadSafeClientConnManager(); DefaultHttpClient client = new DefaultHttpClient(connManager); - init(config, client, connManager); + init(config, client, connManager, sslConf); } - private void init(StartupConfiguration config, DefaultHttpClient client, ClientConnectionManager connManager) { + private void init(StartupConfiguration config, DefaultHttpClient client, + ClientConnectionManager connManager, SSLConfiguration sslConf) { categoryIds = new HashMap<>(); gson = new GsonBuilder().registerTypeHierarchyAdapter(Pojo.class, new ThermostatGSONConverter()) @@ -348,14 +351,14 @@ } // setup SSL if necessary if (config.getDBConnectionString().startsWith(HTTPS_PREFIX)) { - registerSSLScheme(connManager); + registerSSLScheme(connManager, sslConf); } } - private void registerSSLScheme(ClientConnectionManager conManager) + private void registerSSLScheme(ClientConnectionManager conManager, SSLConfiguration sslConf) throws StorageException { try { - SSLContext sc = SSLContextFactory.getClientContext(); + SSLContext sc = SSLContextFactory.getClientContext(sslConf); SSLSocketFactory socketFactory = new SSLSocketFactory(sc); Scheme sch = new Scheme("https", 443, socketFactory); conManager.getSchemeRegistry().register(sch);
--- a/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorageProvider.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/client/src/main/java/com/redhat/thermostat/web/client/internal/WebStorageProvider.java Fri Nov 15 17:28:05 2013 -0700 @@ -36,6 +36,7 @@ package com.redhat.thermostat.web.client.internal; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.SecureQueuedStorage; @@ -45,10 +46,11 @@ public class WebStorageProvider implements StorageProvider { private StartupConfiguration config; + private SSLConfiguration sslConf; @Override public Storage createStorage() { - WebStorage storage = new WebStorage(config); + WebStorage storage = new WebStorage(config, sslConf); storage.setEndpoint(config.getDBConnectionString()); if (config instanceof AuthenticationConfiguration) { AuthenticationConfiguration authConf = (AuthenticationConfiguration) config; @@ -58,8 +60,9 @@ } @Override - public void setConfig(StartupConfiguration config) { + public void setConfig(StartupConfiguration config, SSLConfiguration sslConf) { this.config = config; + this.sslConf = sslConf; } @Override
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageProviderTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -45,6 +45,7 @@ import org.junit.Test; import org.mockito.Mockito; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.AuthenticationConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.BackingStorage; @@ -59,7 +60,8 @@ WebStorageProvider provider = new WebStorageProvider(); MockConfiguration config = mock(MockConfiguration.class); when(config.getDBConnectionString()).thenReturn("http://something"); - provider.setConfig(config); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + provider.setConfig(config, sslConf); Storage storage = provider.createStorage(); assertTrue(storage instanceof SecureStorage); assertTrue(storage instanceof QueuedStorage);
--- a/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/client/src/test/java/com/redhat/thermostat/web/client/internal/WebStorageTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -84,6 +84,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.redhat.thermostat.shared.config.SSLConfiguration; import com.redhat.thermostat.storage.config.StartupConfiguration; import com.redhat.thermostat.storage.core.AuthToken; import com.redhat.thermostat.storage.core.Categories; @@ -165,7 +166,8 @@ return "http://fluff.example.org"; } }; - storage = new WebStorage(config); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + storage = new WebStorage(config, sslConf); storage.setEndpoint("http://localhost:" + port + "/"); headers = new HashMap<>(); registerCategory(); @@ -534,7 +536,8 @@ return "https://onlyHttpsPrefixUsed.example.com"; } }; - WebStorage storage = new WebStorage(config); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + WebStorage storage = new WebStorage(config, sslConf); HttpClient client = storage.httpClient; SchemeRegistry schemeReg = client.getConnectionManager().getSchemeRegistry(); Scheme scheme = schemeReg.getScheme("https"); @@ -603,7 +606,8 @@ return "http://fluff.example.org"; } }; - storage = new WebStorage(config, client, connManager); + SSLConfiguration sslConf = mock(SSLConfiguration.class); + storage = new WebStorage(config, client, connManager, sslConf); storage.setEndpoint("http://localhost:" + port + "/"); CountDownLatch latch = new CountDownLatch(1);
--- a/web/common/src/main/java/com/redhat/thermostat/web/common/StorageWrapper.java Fri Nov 15 16:15:18 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright 2012, 2013 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.common; - -import com.redhat.thermostat.storage.config.ConnectionConfiguration; -import com.redhat.thermostat.storage.config.StartupConfiguration; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageProvider; -import com.redhat.thermostat.storage.mongodb.MongoStorageProvider; - -public class StorageWrapper { - - private static Storage storage; - - public static Storage getStorage(String storageClass, final String storageEndpoint, final String username, final String password) { - if (storage != null) { - return storage; - } - StartupConfiguration conf = new ConnectionConfiguration(storageEndpoint, username, password);; - try { - StorageProvider provider = (StorageProvider) Class.forName(storageClass).newInstance(); - provider.setConfig(conf); - storage = provider.createStorage(); - storage.getConnection().connect(); - return storage; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - // This fallback should infact not be used. But it gives us an automatic - // Import-Package in the OSGi descriptor, which actually *prevents* this same - // exception from happening (a recursive self-defeating catch-block) :-) - System.err.println("could not instantiate provider: " + storageClass + ", falling back to MongoStorage"); - e.printStackTrace(); - StorageProvider provider = new MongoStorageProvider(); - provider.setConfig(conf); - storage = provider.createStorage(); - return storage; - } - } - public static void setStorage(Storage storage) { - StorageWrapper.storage = storage; - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java Fri Nov 15 17:28:05 2013 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright 2012, 2013 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.server; + +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl; +import com.redhat.thermostat.storage.config.ConnectionConfiguration; +import com.redhat.thermostat.storage.config.StartupConfiguration; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.StorageProvider; +import com.redhat.thermostat.storage.mongodb.MongoStorageProvider; + +class StorageFactory { + + private static Storage storage; + + // Web server is not OSGi, this factory method is workaround. + static Storage getStorage(String storageClass, final String storageEndpoint, final String username, final String password) { + if (storage != null) { + return storage; + } + StartupConfiguration conf = new ConnectionConfiguration(storageEndpoint, username, password); + SSLConfiguration sslConf = new SSLConfigurationImpl(); + try { + StorageProvider provider = (StorageProvider) Class.forName(storageClass).newInstance(); + provider.setConfig(conf, sslConf); + storage = provider.createStorage(); + storage.getConnection().connect(); + return storage; + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + // This fallback should infact not be used. But it gives us an automatic + // Import-Package in the OSGi descriptor, which actually *prevents* this same + // exception from happening (a recursive self-defeating catch-block) :-) + System.err.println("could not instantiate provider: " + storageClass + ", falling back to MongoStorage"); + e.printStackTrace(); + StorageProvider provider = new MongoStorageProvider(); + provider.setConfig(conf, sslConf); + storage = provider.createStorage(); + return storage; + } + } + + // Testing hook used in WebStorageEndpointTest + static void setStorage(Storage storage) { + StorageFactory.storage = storage; + } +} +
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Fri Nov 15 17:28:05 2013 -0700 @@ -98,7 +98,6 @@ import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.web.common.PreparedParameterSerializer; import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.ThermostatGSONConverter; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; @@ -214,7 +213,7 @@ String storageEndpoint = getServletConfig().getInitParameter(STORAGE_ENDPOINT); String username = getServletConfig().getInitParameter(STORAGE_USERNAME); String password = getServletConfig().getInitParameter(STORAGE_PASSWORD); - storage = StorageWrapper.getStorage(storageClass, storageEndpoint, username, password); + storage = StorageFactory.getStorage(storageClass, storageEndpoint, username, password); } String uri = req.getRequestURI(); int lastPartIdx = uri.lastIndexOf("/");
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Fri Nov 15 16:15:18 2013 -0700 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Fri Nov 15 17:28:05 2013 -0700 @@ -127,7 +127,6 @@ import com.redhat.thermostat.test.FreePortFinder.TryPort; import com.redhat.thermostat.web.common.PreparedParameterSerializer; import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.StorageWrapper; import com.redhat.thermostat.web.common.ThermostatGSONConverter; import com.redhat.thermostat.web.common.WebPreparedStatement; import com.redhat.thermostat.web.common.WebPreparedStatementResponse; @@ -230,7 +229,7 @@ public void setUp() throws Exception { mockStorage = mock(BackingStorage.class); - StorageWrapper.setStorage(mockStorage); + StorageFactory.setStorage(mockStorage); } private void startServer(int port, LoginService loginService) throws Exception {