diff options
author | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-28 17:10:50 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-28 17:10:50 +0100 |
commit | 6364de1e56f476f0f9dda76cdd9bd738febc88e6 (patch) | |
tree | 355f7f789c06913658c3b8be29cc46a37a64cd5d /jdisc_http_service | |
parent | 20cb715ad6a4f312d021435c5bb9bed2f3af1d37 (diff) |
Add SslTrustStoreConfigurator interface to JDisc
Diffstat (limited to 'jdisc_http_service')
7 files changed, 138 insertions, 29 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index 8255e16e0ee..69999ebc355 100644 --- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java @@ -7,7 +7,9 @@ import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.ConnectorConfig.Ssl; import com.yahoo.jdisc.http.SecretStore; import com.yahoo.jdisc.http.ssl.DefaultSslKeyStoreContext; +import com.yahoo.jdisc.http.ssl.DefaultSslTrustStoreContext; import com.yahoo.jdisc.http.ssl.SslKeyStoreConfigurator; +import com.yahoo.jdisc.http.ssl.SslTrustStoreConfigurator; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -26,27 +28,16 @@ import java.nio.channels.ServerSocketChannel; public class ConnectorFactory { private final ConnectorConfig connectorConfig; - private final SecretStore secretStore; private final SslKeyStoreConfigurator sslKeyStoreConfigurator; + private final SslTrustStoreConfigurator sslTrustStoreConfigurator; @Inject public ConnectorFactory(ConnectorConfig connectorConfig, - SecretStore secretStore, - SslKeyStoreConfigurator sslKeyStoreConfigurator) { + SslKeyStoreConfigurator sslKeyStoreConfigurator, + SslTrustStoreConfigurator sslTrustStoreConfigurator) { this.connectorConfig = connectorConfig; - this.secretStore = secretStore; this.sslKeyStoreConfigurator = sslKeyStoreConfigurator; - - if (connectorConfig.ssl().enabled()) - validateSslConfig(connectorConfig); - } - - // TODO: can be removed when we have dedicated SSL config in services.xml - private static void validateSslConfig(ConnectorConfig config) { - ConnectorConfig.Ssl ssl = config.ssl(); - if (!ssl.trustStorePath().isEmpty() && ssl.useTrustStorePassword() && ssl.keyDbKey().isEmpty()) { - throw new IllegalArgumentException("Missing password for JKS truststore"); - } + this.sslTrustStoreConfigurator = sslTrustStoreConfigurator; } public ConnectorConfig getConnectorConfig() { @@ -93,13 +84,13 @@ public class ConnectorFactory { return new HttpConnectionFactory(httpConfig); } - //TODO: does not support loading non-yahoo readable JKS key stores. private SslConnectionFactory newSslConnectionFactory() { Ssl sslConfig = connectorConfig.ssl(); SslContextFactory factory = new SslContextFactory(); sslKeyStoreConfigurator.configure(new DefaultSslKeyStoreContext(factory)); + sslTrustStoreConfigurator.configure(new DefaultSslTrustStoreContext(factory)); switch (sslConfig.clientAuth()) { case NEED_AUTH: @@ -144,16 +135,6 @@ public class ConnectorFactory { factory.setIncludeCipherSuites(ciphs); } - String keyDbPassword = sslConfig.keyDbKey(); - - if (!sslConfig.trustStorePath().isEmpty()) { - factory.setTrustStorePath(sslConfig.trustStorePath()); - factory.setTrustStoreType(sslConfig.trustStoreType().toString()); - if (sslConfig.useTrustStorePassword()) { - factory.setTrustStorePassword(secretStore.getSecret(keyDbPassword)); - } - } - factory.setKeyManagerFactoryAlgorithm(sslConfig.sslKeyManagerFactoryAlgorithm()); factory.setProtocol(sslConfig.protocol()); return new SslConnectionFactory(factory, HttpVersion.HTTP_1_1.asString()); diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreConfigurator.java new file mode 100644 index 00000000000..8af21d48e9a --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreConfigurator.java @@ -0,0 +1,40 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import com.google.inject.Inject; +import com.yahoo.jdisc.http.ConnectorConfig; +import com.yahoo.jdisc.http.SecretStore; + +/** + * @author bjorncs + */ +public class DefaultSslTrustStoreConfigurator implements SslTrustStoreConfigurator { + + private final SecretStore secretStore; + private final ConnectorConfig.Ssl config; + + @Inject + public DefaultSslTrustStoreConfigurator(ConnectorConfig config, SecretStore secretStore) { + validateConfig(config.ssl()); + this.secretStore = secretStore; + this.config = config.ssl(); + } + + @Override + public void configure(SslTrustStoreContext context) { + if (!config.enabled()) return; + String keyDbPassword = config.keyDbKey(); + if (!config.trustStorePath().isEmpty()) { + String password = config.useTrustStorePassword() ? secretStore.getSecret(keyDbPassword) : null; + context.updateTrustStore(config.trustStorePath(), config.trustStoreType().toString(), password); + } + } + + private static void validateConfig(ConnectorConfig.Ssl config) { + if (!config.enabled()) return; + if (!config.trustStorePath().isEmpty() && config.useTrustStorePassword() && config.keyDbKey().isEmpty()) { + throw new IllegalArgumentException("Missing password for JKS truststore"); + } + } + +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreContext.java new file mode 100644 index 00000000000..c2d91cca3ea --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslTrustStoreContext.java @@ -0,0 +1,54 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import org.eclipse.jetty.util.ssl.SslContextFactory; + +import java.security.KeyStore; +import java.util.function.Consumer; + +/** + * @author bjorncs + */ +public class DefaultSslTrustStoreContext implements SslTrustStoreContext { + + private final SslContextFactory sslContextFactory; + + public DefaultSslTrustStoreContext(SslContextFactory sslContextFactory) { + this.sslContextFactory = sslContextFactory; + } + + @Override + public void updateTrustStore(KeyStore trustStore) { + updateTrustStore(trustStore, null); + } + + @Override + public void updateTrustStore(KeyStore trustStore, String password) { + updateTrustStore(sslContextFactory -> { + sslContextFactory.setTrustStore(trustStore); + if (password != null) { + sslContextFactory.setTrustStorePassword(password); + } + }); + } + + @Override + public void updateTrustStore(String trustStorePath, String trustStoreType, String trustStorePassword) { + updateTrustStore(sslContextFactory -> { + sslContextFactory.setTrustStorePath(trustStorePath); + sslContextFactory.setTrustStoreType(trustStoreType); + if (trustStorePassword != null) { + sslContextFactory.setTrustStorePassword(trustStorePassword); + } + }); + } + + private void updateTrustStore(Consumer<SslContextFactory> reloader) { + try { + sslContextFactory.reload(reloader); + } catch (Exception e) { + throw new RuntimeException("Could not update truststore: " + e.getMessage(), e); + } + } + +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreConfigurator.java new file mode 100644 index 00000000000..de1119a5275 --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreConfigurator.java @@ -0,0 +1,14 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +/** + * An interface for an component that can configure an {@link SslTrustStoreContext}. The implementor can assume that + * the {@link SslTrustStoreContext} instance is thread-safe and be updated at any time + * during and after the call to{@link #configure(SslTrustStoreContext)}. + * Modifying the {@link SslKeyStoreContext} instance will trigger a hot reload of the truststore in JDisc. + * + * @author bjorncs + */ +public interface SslTrustStoreConfigurator { + void configure(SslTrustStoreContext context); +} diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreContext.java new file mode 100644 index 00000000000..fc8cf397b24 --- /dev/null +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslTrustStoreContext.java @@ -0,0 +1,16 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl; + +import java.security.KeyStore; + +/** + * An interface to update the truststore in JDisc. Any update will trigger a hot reload and new connections will + * authenticated using the update truststore. + * + * @author bjorncs + */ +public interface SslTrustStoreContext { + void updateTrustStore(KeyStore trustStore); + void updateTrustStore(KeyStore trustStore, String password); + void updateTrustStore(String trustStorePath, String trustStoreType, String trustStorePassword); +} diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/guiceModules/ConnectorFactoryRegistryModule.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/guiceModules/ConnectorFactoryRegistryModule.java index 0d8f433cc39..6281907e083 100644 --- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/guiceModules/ConnectorFactoryRegistryModule.java +++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/guiceModules/ConnectorFactoryRegistryModule.java @@ -12,6 +12,7 @@ import com.yahoo.jdisc.http.SecretStore; import com.yahoo.jdisc.http.server.jetty.ConnectorFactory; import com.yahoo.jdisc.http.server.jetty.TestDrivers; import com.yahoo.jdisc.http.ssl.DefaultSslKeyStoreConfigurator; +import com.yahoo.jdisc.http.ssl.DefaultSslTrustStoreConfigurator; /** * Guice module for test ConnectorFactories @@ -48,8 +49,8 @@ public class ConnectorFactoryRegistryModule implements Module { public StaticKeyDbConnectorFactory(ConnectorConfig connectorConfig) { super(connectorConfig, - new MockSecretStore(), - new DefaultSslKeyStoreConfigurator(connectorConfig, new MockSecretStore())); + new DefaultSslKeyStoreConfigurator(connectorConfig, new MockSecretStore()), + new DefaultSslTrustStoreConfigurator(connectorConfig, new MockSecretStore())); } } diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java index 781bc6a7b5f..103a317094b 100644 --- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java +++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java @@ -5,6 +5,7 @@ import com.yahoo.jdisc.Metric; import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.SecretStore; import com.yahoo.jdisc.http.ssl.DefaultSslKeyStoreConfigurator; +import com.yahoo.jdisc.http.ssl.DefaultSslTrustStoreConfigurator; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -107,7 +108,9 @@ public class ConnectorFactoryTest { private static ConnectorFactory createConnectorFactory(ConnectorConfig config) { ThrowingSecretStore secretStore = new ThrowingSecretStore(); - return new ConnectorFactory(config, secretStore, new DefaultSslKeyStoreConfigurator(config, secretStore)); + return new ConnectorFactory(config, + new DefaultSslKeyStoreConfigurator(config, secretStore), + new DefaultSslTrustStoreConfigurator(config, secretStore)); } private static class HelloWorldHandler extends AbstractHandler { |