diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-05-25 16:49:36 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-05-30 16:20:56 +0200 |
commit | 326fdc2edcddd10ff2b70b39345b01d97819e7c6 (patch) | |
tree | 955fe54adc355cbac027f143b63a3dc3cd577725 /container-core/src/main | |
parent | 3244b261356b944095215c204abda07ed2191029 (diff) |
Add `SslProvider` interface as replacement for `SslContextFactoryProvider`
Diffstat (limited to 'container-core/src/main')
7 files changed, 166 insertions, 6 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/SslConfigurer.java b/container-core/src/main/java/com/yahoo/jdisc/http/SslConfigurer.java new file mode 100644 index 00000000000..bbdba395910 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/jdisc/http/SslConfigurer.java @@ -0,0 +1,36 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http; + +import javax.net.ssl.SSLContext; +import java.security.KeyStore; +import java.util.List; + +/** + * Provides SSL/TLS configuration for a server connector. + * + * @author bjorncs + */ +public interface SslProvider extends AutoCloseable { + + interface ConnectorSsl { + enum ClientAuth { DISABLED, WANT, NEED } + ConnectorSsl setSslContext(SSLContext ctx); + ConnectorSsl setClientAuth(ConnectorSsl.ClientAuth auth); + ConnectorSsl setEnabledCipherSuites(List<String> ciphers); + ConnectorSsl setEnabledProtocolVersions(List<String> versions); + ConnectorSsl setKeystore(KeyStore keystore, char[] password); + ConnectorSsl setKeystore(KeyStore keystore); + ConnectorSsl setTruststore(KeyStore truststore, char[] password); + ConnectorSsl setTruststore(KeyStore truststore); + } + + /** + * Invoked during configuration of server connector + * @param ssl provides methods to modify default SSL configuration + * @param name The connector name + * @param port The connector listen port + */ + void configureSsl(ConnectorSsl ssl, String name, int port); + + @Override default void close() {} +} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index a7c5b83f6a6..b56743954f4 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java @@ -4,7 +4,9 @@ package com.yahoo.jdisc.http.server.jetty; import com.google.inject.Inject; import com.yahoo.jdisc.Metric; import com.yahoo.jdisc.http.ConnectorConfig; +import com.yahoo.jdisc.http.SslProvider; import com.yahoo.jdisc.http.ssl.SslContextFactoryProvider; +import com.yahoo.jdisc.http.ssl.impl.DefaultConnectorSsl; import com.yahoo.security.tls.MixedMode; import com.yahoo.security.tls.TransportSecurityUtils; import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; @@ -41,14 +43,14 @@ public class ConnectorFactory { private static final Logger log = Logger.getLogger(ConnectorFactory.class.getName()); private final ConnectorConfig connectorConfig; - private final SslContextFactoryProvider sslContextFactoryProvider; + private final SslProvider sslProvider; @Inject public ConnectorFactory(ConnectorConfig connectorConfig, - SslContextFactoryProvider sslContextFactoryProvider) { + SslProvider sslProvider) { runtimeConnectorConfigValidation(connectorConfig); this.connectorConfig = connectorConfig; - this.sslContextFactoryProvider = sslContextFactoryProvider; + this.sslProvider = sslProvider; } // Perform extra connector config validation that can only be performed at runtime, @@ -180,12 +182,28 @@ public class ConnectorFactory { } private SslConnectionFactory newSslConnectionFactory(Metric metric, ConnectionFactory wrappedFactory) { - SslContextFactory ctxFactory = sslContextFactoryProvider.getInstance(connectorConfig.name(), connectorConfig.listenPort()); - SslConnectionFactory connectionFactory = new SslConnectionFactory(ctxFactory, wrappedFactory.getProtocol()); + SslConnectionFactory connectionFactory = new SslConnectionFactory(createSslContextFactory(), wrappedFactory.getProtocol()); connectionFactory.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort())); return connectionFactory; } + @SuppressWarnings("removal") + private SslContextFactory createSslContextFactory() { + try { + DefaultConnectorSsl ssl = new DefaultConnectorSsl(); + sslProvider.configureSsl(ssl, connectorConfig.name(), connectorConfig.listenPort()); + return ssl.createSslContextFactory(); + } catch (UnsupportedOperationException e) { + // TODO(bjorncs) Vespa 8 Remove this compatibility workaround + if (sslProvider instanceof SslContextFactoryProvider) { + return ((SslContextFactoryProvider) sslProvider) + .getInstance(connectorConfig.name(), connectorConfig.listenPort()); + } else { + throw e; + } + } + } + private ALPNServerConnectionFactory newAlpnConnectionFactory() { ALPNServerConnectionFactory factory = new ALPNServerConnectionFactory("h2", "http/1.1"); factory.setDefaultProtocol("http/1.1"); diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactoryProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactoryProvider.java index 4383b511637..e786074e8d0 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactoryProvider.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactoryProvider.java @@ -1,14 +1,17 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.http.ssl; +import com.yahoo.jdisc.http.SslProvider; import org.eclipse.jetty.util.ssl.SslContextFactory; /** * A provider that is used to configure SSL connectors in JDisc * + * @deprecated Implement {@link SslProvider} instead * @author bjorncs */ -public interface SslContextFactoryProvider extends AutoCloseable { +@Deprecated(forRemoval = true, since = "7") +public interface SslContextFactoryProvider extends AutoCloseable, SslProvider { /** * This method is called once for each SSL connector. @@ -18,4 +21,10 @@ public interface SslContextFactoryProvider extends AutoCloseable { SslContextFactory getInstance(String containerId, int port); @Override default void close() {} + + @Override + default void configureSsl(ConnectorSsl ssl, String name, int port) { + // Signal that getInstance() should be invoked instead + throw new UnsupportedOperationException(); + } } diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java index 8916fd7760d..fcb8c468bac 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java @@ -31,6 +31,7 @@ import static com.yahoo.jdisc.http.ssl.impl.SslContextFactoryUtils.setEnabledPro * * @author bjorncs */ +@SuppressWarnings("removal") public class ConfiguredSslContextFactoryProvider implements SslContextFactoryProvider { private volatile AutoReloadingX509KeyManager keyManager; diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultConnectorSsl.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultConnectorSsl.java new file mode 100644 index 00000000000..9978a272e82 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultConnectorSsl.java @@ -0,0 +1,94 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.http.ssl.impl; + +import com.yahoo.jdisc.http.SslProvider; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +import javax.net.ssl.SSLContext; +import java.security.KeyStore; +import java.util.List; + +/** + * Default implementation of {@link SslProvider} backed by {@link SslContextFactory.Server} + * + * @author bjorncs + */ +public class DefaultConnectorSsl implements SslProvider.ConnectorSsl { + + private SSLContext sslContext; + private ClientAuth clientAuth; + private List<String> cipherSuites = List.of(); + private List<String> protocolVersions = List.of(); + private KeyStore keystore; + private char[] keystorePassword; + private KeyStore truststore; + private char[] truststorePassword; + + @Override + public SslProvider.ConnectorSsl setSslContext(SSLContext ctx) { + this.sslContext = ctx; return this; + } + + @Override + public SslProvider.ConnectorSsl setClientAuth(SslProvider.ConnectorSsl.ClientAuth auth) { + this.clientAuth = auth; return this; + } + + @Override + public SslProvider.ConnectorSsl setEnabledCipherSuites(List<String> ciphers) { + this.cipherSuites = ciphers; return this; + } + + @Override + public SslProvider.ConnectorSsl setEnabledProtocolVersions(List<String> versions) { + this.protocolVersions = versions; return this; + } + + @Override + public SslProvider.ConnectorSsl setKeystore(KeyStore keystore, char[] password) { + this.keystore = keystore; this.keystorePassword = password; return this; + } + + @Override + public SslProvider.ConnectorSsl setKeystore(KeyStore keystore) { + this.keystore = keystore; return this; + } + + @Override + public SslProvider.ConnectorSsl setTruststore(KeyStore truststore, char[] password) { + this.truststore = truststore; this.truststorePassword = password; return this; + } + + @Override + public SslProvider.ConnectorSsl setTruststore(KeyStore truststore) { + this.truststore = truststore; return this; + } + + public SslContextFactory.Server createSslContextFactory() { + SslContextFactory.Server ssl = new SslContextFactory.Server(); + if (sslContext != null) ssl.setSslContext(sslContext); + if (keystore != null) ssl.setKeyStore(keystore); + if (keystorePassword != null) ssl.setKeyStorePassword(new String(keystorePassword)); + if (truststore != null) ssl.setTrustStore(truststore); + if (truststorePassword != null) ssl.setTrustStorePassword(new String(truststorePassword)); + switch (clientAuth) { + case DISABLED: + ssl.setWantClientAuth(false); + ssl.setNeedClientAuth(false); + break; + case NEED: + ssl.setWantClientAuth(false); + ssl.setNeedClientAuth(true); + break; + case WANT: + ssl.setNeedClientAuth(true); + ssl.setNeedClientAuth(false); + break; + default: + throw new IllegalArgumentException(clientAuth.name()); + } + if (!cipherSuites.isEmpty()) SslContextFactoryUtils.setEnabledCipherSuites(ssl, sslContext, cipherSuites); + if (!protocolVersions.isEmpty()) SslContextFactoryUtils.setEnabledProtocols(ssl, sslContext, protocolVersions); + return ssl; + } +} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultSslContextFactoryProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultSslContextFactoryProvider.java index c3c99b71c46..28e95c18424 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultSslContextFactoryProvider.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/DefaultSslContextFactoryProvider.java @@ -18,6 +18,7 @@ import java.nio.file.Path; * * @author bjorncs */ +@SuppressWarnings("removal") public class DefaultSslContextFactoryProvider extends AbstractComponent implements SslContextFactoryProvider { private final SslContextFactoryProvider instance; diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/TlsContextBasedProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/TlsContextBasedProvider.java index 3d9e0bf39d3..73a6940afd9 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/TlsContextBasedProvider.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/TlsContextBasedProvider.java @@ -18,6 +18,7 @@ import static com.yahoo.jdisc.http.ssl.impl.SslContextFactoryUtils.setEnabledPro * * @author bjorncs */ +@SuppressWarnings("removal") public abstract class TlsContextBasedProvider extends AbstractComponent implements SslContextFactoryProvider { protected abstract TlsContext getTlsContext(String containerId, int port); |