summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java17
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CustomSslProvider.java27
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/DefaultSslProvider.java62
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java31
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/JettyContainerModelBuilderTest.java95
-rw-r--r--jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def21
6 files changed, 244 insertions, 9 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java
index 33f5edded3c..8e4288d5f5e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java
@@ -11,12 +11,15 @@ import com.yahoo.text.XML;
import com.yahoo.vespa.model.container.component.SimpleComponent;
import org.w3c.dom.Element;
+import java.util.Optional;
+
import static com.yahoo.component.ComponentSpecification.fromString;
import static com.yahoo.jdisc.http.ConnectorConfig.Ssl.KeyStoreType;
/**
* @author Einar M R Rosenvinge
* @author bjorncs
+ * @author mortent
*/
public class ConnectorFactory extends SimpleComponent implements ConnectorConfig.Producer {
@@ -25,14 +28,15 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig
private final Element legacyConfig;
public ConnectorFactory(String name, int listenPort) {
- this(name, listenPort, null, null, null);
+ this(name, listenPort, null, null, null, null);
}
public ConnectorFactory(String name,
int listenPort,
Element legacyConfig,
Element sslKeystoreConfigurator,
- Element sslTruststoreConfigurator) {
+ Element sslTruststoreConfigurator,
+ SimpleComponent sslProviderComponent) {
super(new ComponentModel(
new BundleInstantiationSpecification(new ComponentId(name),
fromString("com.yahoo.jdisc.http.server.jetty.ConnectorFactory"),
@@ -40,6 +44,10 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig
this.name = name;
this.listenPort = listenPort;
this.legacyConfig = legacyConfig;
+ Optional.ofNullable(sslProviderComponent).ifPresent(component -> {
+ addChild(component);
+ inject(component);
+ });
addSslKeyStoreConfigurator(name, sslKeystoreConfigurator);
addSslTrustStoreConfigurator(name, sslTruststoreConfigurator);
}
@@ -153,6 +161,7 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig
}
}
+
private void addSslKeyStoreConfigurator(String name, Element sslKeystoreConfigurator) {
addSslConfigurator("ssl-keystore-configurator@" + name,
DefaultSslKeyStoreConfigurator.class,
@@ -172,11 +181,9 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig
String bundleName = configuratorElement.getAttribute("bundle");
configuratorComponent = new SimpleComponent(new ComponentModel(idSpec, className, bundleName));
} else {
- configuratorComponent =
- new SimpleComponent(new ComponentModel(idSpec, defaultImplementation.getName(), "jdisc_http_service"));
+ configuratorComponent = new SimpleComponent(new ComponentModel(idSpec, defaultImplementation.getName(), "jdisc_http_service"));
}
addChild(configuratorComponent);
inject(configuratorComponent);
}
-
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CustomSslProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CustomSslProvider.java
new file mode 100644
index 00000000000..46daa2e5c43
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CustomSslProvider.java
@@ -0,0 +1,27 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.http.ssl;
+
+import com.yahoo.component.ComponentId;
+import com.yahoo.container.bundle.BundleInstantiationSpecification;
+import com.yahoo.jdisc.http.ConnectorConfig;
+import com.yahoo.osgi.provider.model.ComponentModel;
+import com.yahoo.vespa.model.container.component.SimpleComponent;
+
+import static com.yahoo.component.ComponentSpecification.fromString;
+
+/**
+ * @author mortent
+ */
+public class CustomSslProvider extends SimpleComponent implements ConnectorConfig.Producer {
+ public CustomSslProvider(String componentId, String className, String bundle) {
+ super(new ComponentModel(
+ new BundleInstantiationSpecification(new ComponentId(componentId),
+ fromString(className),
+ fromString(bundle))));
+ }
+
+ @Override
+ public void getConfig(ConnectorConfig.Builder builder) {
+ builder.ssl.enabled(true);
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/DefaultSslProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/DefaultSslProvider.java
new file mode 100644
index 00000000000..36ab07f977a
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/DefaultSslProvider.java
@@ -0,0 +1,62 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.http.ssl;
+
+import com.yahoo.component.ComponentId;
+import com.yahoo.container.bundle.BundleInstantiationSpecification;
+import com.yahoo.jdisc.http.ConnectorConfig;
+import com.yahoo.osgi.provider.model.ComponentModel;
+import com.yahoo.vespa.model.container.component.SimpleComponent;
+
+import java.util.Optional;
+
+import static com.yahoo.component.ComponentSpecification.fromString;
+
+/**
+ * @author mortent
+ */
+public class DefaultSslProvider extends SimpleComponent implements ConnectorConfig.Producer {
+ public static final String COMPONENT_ID = "default-ssl-provider";
+ public static final String COMPONENT_CLASS = "com.yahoo.jdisc.http.ssl.DefaultSslContextFactoryProvider";
+ public static final String COMPONENT_BUNDLE = "jdisc_http_service";
+
+ private final String privateKeyPath;
+ private final String certificatePath;
+ private final String caCertificatePath;
+ private final ConnectorConfig.Ssl.ClientAuth.Enum clientAuthentication;
+
+ public DefaultSslProvider(String privateKeyPath, String certificatePath, String caCertificatePath, String clientAuthentication) {
+ super(new ComponentModel(
+ new BundleInstantiationSpecification(new ComponentId(COMPONENT_ID),
+ fromString(COMPONENT_CLASS),
+ fromString(COMPONENT_BUNDLE))));
+ this.privateKeyPath = privateKeyPath;
+ this.certificatePath = certificatePath;
+ this.caCertificatePath = caCertificatePath;
+ this.clientAuthentication = mapToConfigEnum(clientAuthentication);
+ }
+
+ @Override
+ public void getConfig(ConnectorConfig.Builder builder) {
+ builder.ssl.enabled(true);
+ builder.ssl.privateKeyFile(privateKeyPath);
+ builder.ssl.certificateFile(certificatePath);
+ builder.ssl.caCertificateFile(Optional.ofNullable(caCertificatePath).orElse(""));
+ builder.ssl.clientAuth(clientAuthentication);
+ }
+
+ public SimpleComponent getComponent() {
+ return new SimpleComponent(new ComponentModel(COMPONENT_ID, COMPONENT_CLASS, COMPONENT_BUNDLE));
+ }
+
+ private static ConnectorConfig.Ssl.ClientAuth.Enum mapToConfigEnum(String clientAuthValue) {
+ if ("disabled".equals(clientAuthValue)) {
+ return ConnectorConfig.Ssl.ClientAuth.Enum.DISABLED;
+ } else if ("want".equals(clientAuthValue)) {
+ return ConnectorConfig.Ssl.ClientAuth.Enum.WANT_AUTH;
+ } else if ("need".equals(clientAuthValue)) {
+ return ConnectorConfig.Ssl.ClientAuth.Enum.NEED_AUTH;
+ } else {
+ return ConnectorConfig.Ssl.ClientAuth.Enum.DISABLED;
+ }
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java
index f88c091cd37..5c15c9bfe7d 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java
@@ -5,14 +5,19 @@ import com.yahoo.config.model.builder.xml.XmlHelper;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.text.XML;
import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder;
+import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.http.ConnectorFactory;
+import com.yahoo.vespa.model.container.http.ssl.CustomSslProvider;
+import com.yahoo.vespa.model.container.http.ssl.DefaultSslProvider;
import org.w3c.dom.Element;
+import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Einar M R Rosenvinge
+ * @author mortent
*/
public class JettyConnectorBuilder extends VespaDomBuilder.DomConfigProducerBuilder<ConnectorFactory> {
private static final Logger log = Logger.getLogger(JettyConnectorBuilder.class.getName());
@@ -34,7 +39,31 @@ public class JettyConnectorBuilder extends VespaDomBuilder.DomConfigProducerBuil
}
Element sslKeystoreConfigurator = XML.getChild(serverSpec, "ssl-keystore-configurator");
Element sslTruststoreConfigurator = XML.getChild(serverSpec, "ssl-truststore-configurator");
- return new ConnectorFactory(name, port, legacyServerConfig, sslKeystoreConfigurator, sslTruststoreConfigurator);
+ SimpleComponent sslProviderComponent = getSslConfigComponents(name, serverSpec);
+ return new ConnectorFactory(name, port, legacyServerConfig, sslKeystoreConfigurator, sslTruststoreConfigurator, sslProviderComponent);
}
+ SimpleComponent getSslConfigComponents(String serverName, Element serverSpec) {
+ Element sslConfigurator = XML.getChild(serverSpec, "ssl");
+ Element sslProviderConfigurator = XML.getChild(serverSpec, "ssl-provider");
+
+ if (sslConfigurator != null) {
+ String privateKeyFile = XML.getValue(XML.getChild(sslConfigurator, "private-key-file"));
+ String certificateFile = XML.getValue(XML.getChild(sslConfigurator, "certificate-file"));
+ Optional<String> caCertificateFile = XmlHelper.getOptionalChildValue(sslConfigurator, "ca-certificates-file");
+ Optional<String> clientAuthentication = XmlHelper.getOptionalChildValue(sslConfigurator, "client-authentication");
+ return new DefaultSslProvider(
+ privateKeyFile,
+ certificateFile,
+ caCertificateFile.orElse(null),
+ clientAuthentication.orElse(null));
+ } else if (sslProviderConfigurator != null) {
+ String id = sslProviderConfigurator.getAttribute("id");
+ String className = sslProviderConfigurator.getAttribute("class");
+ String bundle = sslProviderConfigurator.getAttribute("bundle");
+ return new CustomSslProvider(id, className, bundle);
+ }
+ // No ssl config..
+ return null;
+ }
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JettyContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JettyContainerModelBuilderTest.java
index 54c4aabf44c..4f51d4cca7e 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JettyContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JettyContainerModelBuilderTest.java
@@ -12,6 +12,8 @@ import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.http.ConnectorFactory;
import com.yahoo.vespa.model.container.http.JettyHttpServer;
+
+import com.yahoo.vespa.model.container.http.ssl.DefaultSslProvider;
import org.junit.Test;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
@@ -19,6 +21,7 @@ import org.xml.sax.SAXException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import static com.yahoo.jdisc.http.ConnectorConfig.Ssl.KeyStoreType;
@@ -28,9 +31,11 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
* @author einarmr
+ * @author mortent
*/
public class JettyContainerModelBuilderTest extends ContainerModelBuilderTestBase {
@@ -229,6 +234,87 @@ public class JettyContainerModelBuilderTest extends ContainerModelBuilderTestBas
}
}
+ @Test
+ public void verify_default_ssl_configuration() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<jdisc id='default' version='1.0' jetty='true'>\n" +
+ " <http>\n" +
+ " <server port='9000' id='minimal'>\n" +
+ " <ssl>\n" +
+ " <private-key-file>/foo/key</private-key-file>\n" +
+ " <certificate-file>/foo/cert</certificate-file>\n" +
+ " </ssl>\n" +
+ " </server>\n" +
+ " <server port='9001' id='with-cacerts'>\n" +
+ " <ssl>\n" +
+ " <private-key-file>/foo/key</private-key-file>\n" +
+ " <certificate-file>/foo/cert</certificate-file>\n" +
+ " <ca-certificates-file>/foo/cacerts</ca-certificates-file>\n" +
+ " </ssl>\n" +
+ " </server>\n" +
+ " <server port='9002' id='need-client-auth'>\n" +
+ " <ssl>\n" +
+ " <private-key-file>/foo/key</private-key-file>\n" +
+ " <certificate-file>/foo/cert</certificate-file>\n" +
+ " <client-authentication>need</client-authentication>\n" +
+ " </ssl>\n" +
+ " </server>\n" +
+ " </http>" +
+ nodesXml +
+ "\n" +
+ "</jdisc>");
+
+ createModel(root, clusterElem);
+ ConnectorConfig minimalCfg = root.getConfig(ConnectorConfig.class, "default/http/jdisc-jetty/minimal/default-ssl-provider");
+ assertTrue(minimalCfg.ssl().enabled());
+ assertThat(minimalCfg.ssl().privateKeyFile(), is(equalTo("/foo/key")));
+ assertThat(minimalCfg.ssl().certificateFile(), is(equalTo("/foo/cert")));
+ assertThat(minimalCfg.ssl().caCertificateFile(), is(equalTo("")));
+ assertThat(minimalCfg.ssl().clientAuth(), is(equalTo(ConnectorConfig.Ssl.ClientAuth.Enum.DISABLED)));
+
+ ConnectorConfig withCaCerts = root.getConfig(ConnectorConfig.class, "default/http/jdisc-jetty/with-cacerts/default-ssl-provider");
+ assertTrue(withCaCerts.ssl().enabled());
+ assertThat(withCaCerts.ssl().privateKeyFile(), is(equalTo("/foo/key")));
+ assertThat(withCaCerts.ssl().certificateFile(), is(equalTo("/foo/cert")));
+ assertThat(withCaCerts.ssl().caCertificateFile(), is(equalTo("/foo/cacerts")));
+ assertThat(withCaCerts.ssl().clientAuth(), is(equalTo(ConnectorConfig.Ssl.ClientAuth.Enum.DISABLED)));
+
+ ConnectorConfig needClientAuth = root.getConfig(ConnectorConfig.class, "default/http/jdisc-jetty/need-client-auth/default-ssl-provider");
+ assertTrue(needClientAuth.ssl().enabled());
+ assertThat(needClientAuth.ssl().privateKeyFile(), is(equalTo("/foo/key")));
+ assertThat(needClientAuth.ssl().certificateFile(), is(equalTo("/foo/cert")));
+ assertThat(needClientAuth.ssl().caCertificateFile(), is(equalTo("")));
+ assertThat(needClientAuth.ssl().clientAuth(), is(equalTo(ConnectorConfig.Ssl.ClientAuth.Enum.NEED_AUTH)));
+
+ ContainerCluster cluster = (ContainerCluster) root.getChildren().get("default");
+ List<ConnectorFactory> connectorFactories = cluster.getChildrenByTypeRecursive(ConnectorFactory.class);
+ connectorFactories.forEach(connectorFactory -> assertChildComponentExists(connectorFactory, DefaultSslProvider.COMPONENT_ID, DefaultSslProvider.COMPONENT_CLASS));
+ }
+
+ @Test
+ public void verify_ssl_provider_configuration() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<jdisc id='default' version='1.0' jetty='true'>\n" +
+ " <http>\n" +
+ " <server port='9000' id='ssl'>\n" +
+ " <ssl-provider id='ssl-provider' class='com.yahoo.CustomSslProvider' bundle='mybundle'/>\n" +
+ " </server>\n" +
+ " </http>" +
+ nodesXml +
+ "\n" +
+ "</jdisc>");
+
+ createModel(root, clusterElem);
+ ConnectorConfig sslProvider = root.getConfig(ConnectorConfig.class, "default/http/jdisc-jetty/ssl/ssl-provider");
+
+ assertTrue(sslProvider.ssl().enabled());
+
+ ContainerCluster cluster = (ContainerCluster) root.getChildren().get("default");
+ List<ConnectorFactory> connectorFactories = cluster.getChildrenByTypeRecursive(ConnectorFactory.class);
+ ConnectorFactory connectorFactory = connectorFactories.get(0);
+ assertChildComponentExists(connectorFactory, "ssl-provider", "com.yahoo.CustomSslProvider");
+ }
+
private static void assertConnectorHasInjectedComponents(ConnectorFactory connectorFactory, String... componentNames) {
Set<String> injectedComponentIds = connectorFactory.getInjectedComponentIds();
assertThat(injectedComponentIds.size(), equalTo(componentNames.length));
@@ -248,6 +334,15 @@ public class JettyContainerModelBuilderTest extends ContainerModelBuilderTestBas
assertThat(spec.bundle.toString(), is(bundleName));
}
+ private static void assertChildComponentExists(ConnectorFactory connectorFactory, String componentId, String className) {
+ Optional<SimpleComponent> simpleComponent = connectorFactory.getChildren().values().stream()
+ .map(z -> (SimpleComponent) z)
+ .filter(component -> component.getComponentId().stringValue().equals(componentId) &&
+ component.getClassId().stringValue().equals(className))
+ .findFirst();
+ assertTrue(simpleComponent.isPresent());
+ }
+
private void assertJettyServerInConfig() {
ContainerCluster cluster = (ContainerCluster) root.getChildren().get("default");
List<JettyHttpServer> jettyServers = cluster.getChildrenByTypeRecursive(JettyHttpServer.class);
diff --git a/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def b/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
index 9ae4713c633..157ffabdd63 100644
--- a/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
+++ b/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
@@ -44,6 +44,23 @@ tcpNoDelay bool default=true
# Whether to enable SSL for this connector.
ssl.enabled bool default=false
+# File with private key in PEM format
+ssl.privateKeyFile string default=""
+
+# File with certificate in PEM format
+ssl.certificateFile string default=""
+
+# with trusted CA certificates in PEM format. Used to verify clients
+ssl.caCertificateFile string default=""
+
+# Client authentication mode. See SSLEngine.getNeedClientAuth()/getWantClientAuth() for details.
+ssl.clientAuth enum { DISABLED, WANT_AUTH, NEED_AUTH } default=DISABLED
+
+
+#########################################################################################
+# Config below is deprecated. Do not use
+#########################################################################################
+
# The name of the key to the password to the key store if in the secret store, if JKS is used.
# Must be empty with PEM
# By default this is also used to look up the password to the trust store.
@@ -89,11 +106,9 @@ ssl.sslKeyManagerFactoryAlgorithm string default="SunX509"
# The SSL protocol passed to SSLContext.getInstance()
ssl.protocol string default="TLS"
-# Client authentication mode. See SSLEngine.getNeedClientAuth()/getWantClientAuth() for details.
-ssl.clientAuth enum { DISABLED, WANT_AUTH, NEED_AUTH } default=DISABLED
-
# The SecureRandom implementation passed to SSLEngine.init()
# Java have a default pseudo-random number generator (PRNG) for crypto operations. This default may have performance
# issues on some platform (e.g. NativePRNG in Linux utilizes a global lock). Changing the generator to SHA1PRNG may
# improve performance. Set value to empty string to use the default generator.
ssl.prng string default=""
+