summaryrefslogtreecommitdiffstats
path: root/jdisc_http_service/src/main/java/com/yahoo
diff options
context:
space:
mode:
Diffstat (limited to 'jdisc_http_service/src/main/java/com/yahoo')
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/HttpRequest.java10
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java10
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/JdiscFilterRequest.java11
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/ServletFilterRequest.java11
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java8
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java7
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java237
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java7
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java1
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java122
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java52
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/servlet/ServletRequest.java12
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java95
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java51
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/JKSKeyStore.java34
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/ReaderForPath.java22
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactory.java88
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStore.java29
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java14
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java16
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java4
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStore.java62
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStoreProvider.java20
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemSslKeyStore.java44
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ChunkReader.java124
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/FilterTestDriver.java70
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteClient.java53
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteServer.java110
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ServerTestDriver.java146
29 files changed, 458 insertions, 1012 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/HttpRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
index 2268b568b18..21e492fe57e 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
@@ -16,6 +16,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
+import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -71,6 +72,7 @@ public class HttpRequest extends Request implements ServletOrJdiscHttpRequest {
private final HeaderFields trailers = new HeaderFields();
private final Map<String, List<String>> parameters = new HashMap<>();
+ private Principal principal;
private final long connectedAt;
private Method method;
private Version version;
@@ -294,6 +296,14 @@ public class HttpRequest extends Request implements ServletOrJdiscHttpRequest {
return version == Version.HTTP_1_1;
}
+ public Principal getUserPrincipal() {
+ return principal;
+ }
+
+ public void setUserPrincipal(Principal principal) {
+ this.principal = principal;
+ }
+
public static HttpRequest newServerRequest(CurrentContainer container, URI uri) {
return newServerRequest(container, uri, Method.GET);
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java
index a46d35f8e70..617f0cbd184 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/DiscFilterRequest.java
@@ -36,14 +36,12 @@ public abstract class DiscFilterRequest {
protected static final String HTTPS_PREFIX = "https";
protected static final int DEFAULT_HTTP_PORT = 80;
protected static final int DEFAULT_HTTPS_PORT = 443;
- private static final String JDISC_REQUEST_PRINCIPAL = "jdisc.request.principal";
private final ServletOrJdiscHttpRequest parent;
protected final InetSocketAddress localAddress;
protected final Map<String, List<String>> untreatedParams;
private final HeaderFields untreatedHeaders;
private List<Cookie> untreatedCookies = null;
- private Principal userPrincipal = null;
private String remoteUser = null;
private String[] roles = null;
private boolean overrideIsUserInRole = false;
@@ -330,9 +328,7 @@ public abstract class DiscFilterRequest {
return port;
}
- public Principal getUserPrincipal() {
- return (Principal) getAttribute(JDISC_REQUEST_PRINCIPAL);
- }
+ public abstract Principal getUserPrincipal();
public boolean isSecure() {
if(getScheme().equalsIgnoreCase(HTTPS_PREFIX)) {
@@ -375,9 +371,7 @@ public abstract class DiscFilterRequest {
this.remoteUser = remoteUser;
}
- public void setUserPrincipal(Principal principal) {
- setAttribute(JDISC_REQUEST_PRINCIPAL, principal);
- }
+ public abstract void setUserPrincipal(Principal principal);
public void setUserRoles(String[] roles) {
this.roles = roles;
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/JdiscFilterRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/JdiscFilterRequest.java
index 1e9d09ecb17..07e3b97ba90 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/JdiscFilterRequest.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/JdiscFilterRequest.java
@@ -5,6 +5,7 @@ import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpRequest;
import java.net.URI;
+import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -103,6 +104,16 @@ public class JdiscFilterRequest extends DiscFilterRequest {
}
@Override
+ public Principal getUserPrincipal() {
+ return parent.getUserPrincipal();
+ }
+
+ @Override
+ public void setUserPrincipal(Principal principal) {
+ this.parent.setUserPrincipal(principal);
+ }
+
+ @Override
public void clearCookies() {
parent.headers().remove(HttpHeaders.Names.COOKIE);
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/ServletFilterRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/ServletFilterRequest.java
index 0fd52d3f12a..11c2baf0176 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/ServletFilterRequest.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/filter/ServletFilterRequest.java
@@ -6,6 +6,7 @@ import com.yahoo.jdisc.http.servlet.ServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URI;
+import java.security.Principal;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -128,6 +129,16 @@ class ServletFilterRequest extends DiscFilterRequest {
}
@Override
+ public Principal getUserPrincipal() {
+ return parent.getUserPrincipal();
+ }
+
+ @Override
+ public void setUserPrincipal(Principal principal) {
+ parent.setUserPrincipal(principal);
+ }
+
+ @Override
public void removeHeaders(String name) {
parent.removeHeaders(name);
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
index 3363c7d3284..c3c83474e56 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
@@ -5,6 +5,7 @@ import com.google.common.base.Objects;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.AccessLogEntry;
+import com.yahoo.jdisc.http.servlet.ServletRequest;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
@@ -17,6 +18,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
+import java.security.Principal;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -107,6 +109,12 @@ public class AccessLogRequestLog extends AbstractLifeCycle implements RequestLog
accessLogEntry.setPeerPort(peerPort);
}
accessLogEntry.setHttpVersion(request.getProtocol());
+ accessLogEntry.setScheme(request.getScheme());
+ accessLogEntry.setLocalPort(request.getLocalPort());
+ Principal principal = (Principal) request.getAttribute(ServletRequest.JDISC_REQUEST_PRINCIPAL);
+ if (principal != null) {
+ accessLogEntry.setUserPrincipal(principal);
+ }
}
private static String getRemoteAddress(final HttpServletRequest request) {
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java
index 43513b4efba..e30d50ecdbf 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLoggingRequestHandler.java
@@ -54,24 +54,27 @@ public class AccessLoggingRequestHandler extends AbstractRequestHandler {
Preconditions.checkArgument(request instanceof HttpRequest, "Expected HttpRequest, got " + request);
final HttpRequest httpRequest = (HttpRequest) request;
httpRequest.context().put(CONTEXT_KEY_ACCESS_LOG_ENTRY, accessLogEntry);
- final ResponseHandler accessLoggingResponseHandler = new AccessLoggingResponseHandler(handler, accessLogEntry);
+ final ResponseHandler accessLoggingResponseHandler = new AccessLoggingResponseHandler(httpRequest, handler, accessLogEntry);
final ContentChannel requestContentChannel = delegate.handleRequest(request, accessLoggingResponseHandler);
return requestContentChannel;
}
private static class AccessLoggingResponseHandler implements ResponseHandler {
+ private final HttpRequest request;
private final ResponseHandler delegateHandler;
private final AccessLogEntry accessLogEntry;
public AccessLoggingResponseHandler(
- final ResponseHandler delegateHandler,
+ HttpRequest request, final ResponseHandler delegateHandler,
final AccessLogEntry accessLogEntry) {
+ this.request = request;
this.delegateHandler = delegateHandler;
this.accessLogEntry = accessLogEntry;
}
@Override
public ContentChannel handleResponse(Response response) {
+ accessLogEntry.setUserPrincipal(request.getUserPrincipal());
return delegateHandler.handleResponse(response);
}
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 96180f48229..8255e16e0ee 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
@@ -1,66 +1,41 @@
// 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.server.jetty;
-import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.ConnectorConfig.Ssl;
-import com.yahoo.jdisc.http.ConnectorConfig.Ssl.PemKeyStore;
import com.yahoo.jdisc.http.SecretStore;
-import com.yahoo.jdisc.http.ssl.ReaderForPath;
-import com.yahoo.jdisc.http.ssl.SslKeyStore;
-import com.yahoo.jdisc.http.ssl.pem.PemSslKeyStore;
+import com.yahoo.jdisc.http.ssl.DefaultSslKeyStoreContext;
+import com.yahoo.jdisc.http.ssl.SslKeyStoreConfigurator;
import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnectionStatistics;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.util.ssl.SslContextFactory;
-import javax.servlet.ServletRequest;
-import java.io.IOException;
-import java.io.Reader;
-import java.lang.reflect.Field;
-import java.net.Socket;
-import java.net.SocketException;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.KeyStore;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
-import java.util.function.Supplier;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static com.google.common.io.Closeables.closeQuietly;
-import static com.yahoo.jdisc.http.ConnectorConfig.Ssl.KeyStoreType.Enum.JKS;
-import static com.yahoo.jdisc.http.ConnectorConfig.Ssl.KeyStoreType.Enum.PEM;
-import static com.yahoo.jdisc.http.server.jetty.Exceptions.throwUnchecked;
/**
* @author Einar M R Rosenvinge
+ * @author bjorncs
*/
public class ConnectorFactory {
- private final static Logger log = Logger.getLogger(ConnectorFactory.class.getName());
private final ConnectorConfig connectorConfig;
private final SecretStore secretStore;
+ private final SslKeyStoreConfigurator sslKeyStoreConfigurator;
@Inject
- public ConnectorFactory(ConnectorConfig connectorConfig, SecretStore secretStore) {
+ public ConnectorFactory(ConnectorConfig connectorConfig,
+ SecretStore secretStore,
+ SslKeyStoreConfigurator sslKeyStoreConfigurator) {
this.connectorConfig = connectorConfig;
this.secretStore = secretStore;
+ this.sslKeyStoreConfigurator = sslKeyStoreConfigurator;
if (connectorConfig.ssl().enabled())
validateSslConfig(connectorConfig);
@@ -69,14 +44,8 @@ public class ConnectorFactory {
// 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.keyStoreType() == JKS) {
- if (! ssl.pemKeyStore().keyPath().isEmpty() || ! ssl.pemKeyStore().certificatePath().isEmpty())
- throw new IllegalArgumentException("pemKeyStore attributes can not be set when keyStoreType is JKS.");
- }
- if (ssl.keyStoreType() == PEM) {
- if (! ssl.keyStorePath().isEmpty())
- throw new IllegalArgumentException("keyStorePath can not be set when keyStoreType is PEM");
+ if (!ssl.trustStorePath().isEmpty() && ssl.useTrustStorePassword() && ssl.keyDbKey().isEmpty()) {
+ throw new IllegalArgumentException("Missing password for JKS truststore");
}
}
@@ -84,11 +53,11 @@ public class ConnectorFactory {
return connectorConfig;
}
- public ServerConnector createConnector(final Metric metric, final Server server, final ServerSocketChannel ch, Map<Path, FileChannel> keyStoreChannels) {
+ public ServerConnector createConnector(final Metric metric, final Server server, final ServerSocketChannel ch) {
ServerConnector connector;
if (connectorConfig.ssl().enabled()) {
connector = new JDiscServerConnector(connectorConfig, metric, server, ch,
- newSslConnectionFactory(keyStoreChannels),
+ newSslConnectionFactory(),
newHttpConnectionFactory());
} else {
connector = new JDiscServerConnector(connectorConfig, metric, server, ch,
@@ -125,10 +94,13 @@ public class ConnectorFactory {
}
//TODO: does not support loading non-yahoo readable JKS key stores.
- private SslConnectionFactory newSslConnectionFactory(Map<Path, FileChannel> keyStoreChannels) {
+ private SslConnectionFactory newSslConnectionFactory() {
Ssl sslConfig = connectorConfig.ssl();
SslContextFactory factory = new SslContextFactory();
+
+ sslKeyStoreConfigurator.configure(new DefaultSslKeyStoreContext(factory));
+
switch (sslConfig.clientAuth()) {
case NEED_AUTH:
factory.setNeedClientAuth(true);
@@ -172,25 +144,14 @@ public class ConnectorFactory {
factory.setIncludeCipherSuites(ciphs);
}
- Optional<String> keyDbPassword = secret(sslConfig.keyDbKey());
- switch (sslConfig.keyStoreType()) {
- case PEM:
- factory.setKeyStore(getKeyStore(sslConfig.pemKeyStore(), keyStoreChannels));
- if (keyDbPassword.isPresent())
- log.warning("Encrypted PEM key stores are not supported.");
- break;
- case JKS:
- factory.setKeyStorePath(sslConfig.keyStorePath());
- factory.setKeyStoreType(sslConfig.keyStoreType().toString());
- factory.setKeyStorePassword(keyDbPassword.orElseThrow(passwordRequiredForJKSKeyStore("key")));
- break;
- }
+ String keyDbPassword = sslConfig.keyDbKey();
if (!sslConfig.trustStorePath().isEmpty()) {
factory.setTrustStorePath(sslConfig.trustStorePath());
factory.setTrustStoreType(sslConfig.trustStoreType().toString());
- if (sslConfig.useTrustStorePassword())
- factory.setTrustStorePassword(keyDbPassword.orElseThrow(passwordRequiredForJKSKeyStore("trust")));
+ if (sslConfig.useTrustStorePassword()) {
+ factory.setTrustStorePassword(secretStore.getSecret(keyDbPassword));
+ }
}
factory.setKeyManagerFactoryAlgorithm(sslConfig.sslKeyManagerFactoryAlgorithm());
@@ -198,162 +159,4 @@ public class ConnectorFactory {
return new SslConnectionFactory(factory, HttpVersion.HTTP_1_1.asString());
}
- /** Returns the secret password with the given name, or empty if the password name is null or empty */
- private Optional<String> secret(String keyname) {
- return Optional.of(keyname).filter(key -> !key.isEmpty()).map(secretStore::getSecret);
- }
-
- @SuppressWarnings("ThrowableInstanceNeverThrown")
- private Supplier<RuntimeException> passwordRequiredForJKSKeyStore(String type) {
- return () -> new RuntimeException(String.format("Password is required for JKS %s store", type));
- }
-
- private KeyStore getKeyStore(PemKeyStore pemKeyStore, Map<Path, FileChannel> keyStoreChannels) {
- Preconditions.checkArgument(!pemKeyStore.certificatePath().isEmpty(), "Missing certificate path.");
- Preconditions.checkArgument(!pemKeyStore.keyPath().isEmpty(), "Missing key path.");
-
- class KeyStoreReaderForPath implements AutoCloseable {
- private final Optional<FileChannel> channel;
- public final ReaderForPath readerForPath;
-
-
- KeyStoreReaderForPath(String pathString) {
- Path path = Paths.get(pathString);
- channel = Optional.ofNullable(keyStoreChannels.get(path));
- readerForPath = new ReaderForPath(channel.map(this::getReader).orElseGet(() -> getReader(path)), path);
- }
-
- private Reader getReader(FileChannel channel) {
- try {
- channel.position(0);
- return Channels.newReader(channel, StandardCharsets.UTF_8.newDecoder(), -1);
- } catch (IOException e) {
- throw throwUnchecked(e);
- }
-
- }
-
- private Reader getReader(Path path) {
- try {
- return Files.newBufferedReader(path);
- } catch (IOException e) {
- throw new RuntimeException("Failed opening " + path, e);
- }
- }
-
- @Override
- public void close() {
- //channels are reused
- if (!channel.isPresent()) {
- closeQuietly(readerForPath.reader);
- }
- }
- }
-
- try (KeyStoreReaderForPath certificateReader = new KeyStoreReaderForPath(pemKeyStore.certificatePath());
- KeyStoreReaderForPath keyReader = new KeyStoreReaderForPath(pemKeyStore.keyPath())) {
- SslKeyStore keyStore = new PemSslKeyStore(
- new com.yahoo.jdisc.http.ssl.pem.PemKeyStore.KeyStoreLoadParameter(
- certificateReader.readerForPath, keyReader.readerForPath));
- return keyStore.loadJavaKeyStore();
- } catch (Exception e) {
- throw new RuntimeException("Failed setting up key store for " + pemKeyStore.keyPath() + ", " + pemKeyStore.certificatePath(), e);
- }
- }
-
- public static class JDiscServerConnector extends ServerConnector {
- public static final String REQUEST_ATTRIBUTE = JDiscServerConnector.class.getName();
- private final static Logger log = Logger.getLogger(JDiscServerConnector.class.getName());
- private final Metric.Context metricCtx;
- private final ServerConnectionStatistics statistics;
- private final boolean tcpKeepAlive;
- private final boolean tcpNoDelay;
- private final ServerSocketChannel channelOpenedByActivator;
-
- private JDiscServerConnector(ConnectorConfig config, Metric metric, Server server,
- ServerSocketChannel channelOpenedByActivator, ConnectionFactory... factories) {
- super(server, factories);
- this.channelOpenedByActivator = channelOpenedByActivator;
- this.tcpKeepAlive = config.tcpKeepAliveEnabled();
- this.tcpNoDelay = config.tcpNoDelay();
- this.metricCtx = createMetricContext(config, metric);
-
- this.statistics = new ServerConnectionStatistics();
- addBean(statistics);
- }
-
- private Metric.Context createMetricContext(ConnectorConfig config, Metric metric) {
- Map<String, Object> props = new TreeMap<>();
- props.put(JettyHttpServer.Metrics.NAME_DIMENSION, config.name());
- props.put(JettyHttpServer.Metrics.PORT_DIMENSION, config.listenPort());
- return metric.createContext(props);
- }
-
- @Override
- protected void configure(final Socket socket) {
- super.configure(socket);
- try {
- socket.setKeepAlive(tcpKeepAlive);
- socket.setTcpNoDelay(tcpNoDelay);
- } catch (SocketException ignored) {
- }
- }
-
- @Override
- public void open() throws IOException {
- if (channelOpenedByActivator == null) {
- log.log(Level.INFO, "No channel set by activator, opening channel ourselves.");
- try {
- super.open();
- } catch (RuntimeException e) {
- log.log(Level.SEVERE, "failed org.eclipse.jetty.server.Server open() with port "+getPort());
- throw e;
- }
- return;
- }
- log.log(Level.INFO, "Using channel set by activator: " + channelOpenedByActivator);
-
- channelOpenedByActivator.socket().setReuseAddress(getReuseAddress());
- int localPort = channelOpenedByActivator.socket().getLocalPort();
- try {
- uglySetLocalPort(localPort);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- throw new RuntimeException("Could not set local port.", e);
- }
- if (localPort <= 0) {
- throw new IOException("Server channel not bound");
- }
- addBean(channelOpenedByActivator);
- channelOpenedByActivator.configureBlocking(true);
- addBean(channelOpenedByActivator);
-
- try {
- uglySetChannel(channelOpenedByActivator);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- throw new RuntimeException("Could not set server channel.", e);
- }
- }
-
- private void uglySetLocalPort(int localPort) throws NoSuchFieldException, IllegalAccessException {
- Field localPortField = ServerConnector.class.getDeclaredField("_localPort");
- localPortField.setAccessible(true);
- localPortField.set(this, localPort);
- }
-
- private void uglySetChannel(ServerSocketChannel channelOpenedByActivator) throws NoSuchFieldException,
- IllegalAccessException {
- Field acceptChannelField = ServerConnector.class.getDeclaredField("_acceptChannel");
- acceptChannelField.setAccessible(true);
- acceptChannelField.set(this, channelOpenedByActivator);
- }
-
- public ServerConnectionStatistics getStatistics() { return statistics; }
-
- public Metric.Context getMetricContext() { return metricCtx; }
-
- public static JDiscServerConnector fromRequest(ServletRequest request) {
- return (JDiscServerConnector)request.getAttribute(REQUEST_ATTRIBUTE);
- }
- }
-
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
index 7f169c7c8d0..5cabe8acd27 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
@@ -12,6 +12,7 @@ import com.yahoo.jdisc.handler.OverloadException;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpRequest;
+import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.HttpConnection;
import javax.servlet.AsyncContext;
@@ -122,7 +123,11 @@ class HttpRequestDispatch {
boolean reportedError = false;
if (error != null) {
- if (!(error instanceof OverloadException || error instanceof BindingNotFoundException)) {
+ if (error instanceof EofException) {
+ log.log(Level.FINE,
+ "Network connection was unexpectedly terminated: " + parent.servletRequest.getRequestURI(),
+ error);
+ } else if (!(error instanceof OverloadException || error instanceof BindingNotFoundException)) {
log.log(Level.WARNING, "Request failed: " + parent.servletRequest.getRequestURI(), error);
}
reportedError = true;
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
index 543cf8ab43e..27f72c7b4bf 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
@@ -20,7 +20,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnection;
-import static com.yahoo.jdisc.http.server.jetty.ConnectorFactory.JDiscServerConnector;
/**
* @author Simon Thoresen Hult
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
new file mode 100644
index 00000000000..8dd50074c32
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
@@ -0,0 +1,122 @@
+// 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.server.jetty;
+
+import com.yahoo.jdisc.Metric;
+import com.yahoo.jdisc.http.ConnectorConfig;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnectionStatistics;
+import org.eclipse.jetty.server.ServerConnector;
+
+import javax.servlet.ServletRequest;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.channels.ServerSocketChannel;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author bjorncs
+ */
+class JDiscServerConnector extends ServerConnector {
+ public static final String REQUEST_ATTRIBUTE = JDiscServerConnector.class.getName();
+ private final static Logger log = Logger.getLogger(JDiscServerConnector.class.getName());
+ private final Metric.Context metricCtx;
+ private final ServerConnectionStatistics statistics;
+ private final boolean tcpKeepAlive;
+ private final boolean tcpNoDelay;
+ private final ServerSocketChannel channelOpenedByActivator;
+
+ JDiscServerConnector(ConnectorConfig config, Metric metric, Server server,
+ ServerSocketChannel channelOpenedByActivator, ConnectionFactory... factories) {
+ super(server, factories);
+ this.channelOpenedByActivator = channelOpenedByActivator;
+ this.tcpKeepAlive = config.tcpKeepAliveEnabled();
+ this.tcpNoDelay = config.tcpNoDelay();
+ this.metricCtx = createMetricContext(config, metric);
+
+ this.statistics = new ServerConnectionStatistics();
+ addBean(statistics);
+ }
+
+ private Metric.Context createMetricContext(ConnectorConfig config, Metric metric) {
+ Map<String, Object> props = new TreeMap<>();
+ props.put(JettyHttpServer.Metrics.NAME_DIMENSION, config.name());
+ props.put(JettyHttpServer.Metrics.PORT_DIMENSION, config.listenPort());
+ return metric.createContext(props);
+ }
+
+ @Override
+ protected void configure(final Socket socket) {
+ super.configure(socket);
+ try {
+ socket.setKeepAlive(tcpKeepAlive);
+ socket.setTcpNoDelay(tcpNoDelay);
+ } catch (SocketException ignored) {
+ }
+ }
+
+ @Override
+ public void open() throws IOException {
+ if (channelOpenedByActivator == null) {
+ log.log(Level.INFO, "No channel set by activator, opening channel ourselves.");
+ try {
+ super.open();
+ } catch (RuntimeException e) {
+ log.log(Level.SEVERE, "failed org.eclipse.jetty.server.Server open() with port " + getPort());
+ throw e;
+ }
+ return;
+ }
+ log.log(Level.INFO, "Using channel set by activator: " + channelOpenedByActivator);
+
+ channelOpenedByActivator.socket().setReuseAddress(getReuseAddress());
+ int localPort = channelOpenedByActivator.socket().getLocalPort();
+ try {
+ uglySetLocalPort(localPort);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException("Could not set local port.", e);
+ }
+ if (localPort <= 0) {
+ throw new IOException("Server channel not bound");
+ }
+ addBean(channelOpenedByActivator);
+ channelOpenedByActivator.configureBlocking(true);
+ addBean(channelOpenedByActivator);
+
+ try {
+ uglySetChannel(channelOpenedByActivator);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException("Could not set server channel.", e);
+ }
+ }
+
+ private void uglySetLocalPort(int localPort) throws NoSuchFieldException, IllegalAccessException {
+ Field localPortField = ServerConnector.class.getDeclaredField("_localPort");
+ localPortField.setAccessible(true);
+ localPortField.set(this, localPort);
+ }
+
+ private void uglySetChannel(ServerSocketChannel channelOpenedByActivator) throws NoSuchFieldException,
+ IllegalAccessException {
+ Field acceptChannelField = ServerConnector.class.getDeclaredField("_acceptChannel");
+ acceptChannelField.setAccessible(true);
+ acceptChannelField.set(this, channelOpenedByActivator);
+ }
+
+ public ServerConnectionStatistics getStatistics() {
+ return statistics;
+ }
+
+ public Metric.Context getMetricContext() {
+ return metricCtx;
+ }
+
+ public static JDiscServerConnector fromRequest(ServletRequest request) {
+ return (JDiscServerConnector) request.getAttribute(REQUEST_ATTRIBUTE);
+ }
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 509bf42d466..7bff685e780 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -44,15 +44,11 @@ import javax.servlet.DispatcherType;
import java.lang.management.ManagementFactory;
import java.net.BindException;
import java.net.MalformedURLException;
-import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
-import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -62,9 +58,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import static com.yahoo.jdisc.http.server.jetty.ConnectorFactory.JDiscServerConnector;
-import static com.yahoo.jdisc.http.server.jetty.Exceptions.throwUnchecked;
-
/**
* @author Simon Thoresen Hult
* @author bjorncs
@@ -147,11 +140,9 @@ public class JettyHttpServer extends AbstractServerProvider {
setupJmx(server, serverConfig);
((QueuedThreadPool)server.getThreadPool()).setMaxThreads(serverConfig.maxWorkerThreads());
- Map<Path, FileChannel> keyStoreChannels = getKeyStoreFileChannels(osgiFramework.bundleContext());
-
for (ConnectorFactory connectorFactory : connectorFactories.allComponents()) {
ServerSocketChannel preBoundChannel = getChannelFromServiceLayer(connectorFactory.getConnectorConfig().listenPort(), osgiFramework.bundleContext());
- server.addConnector(connectorFactory.createConnector(metric, server, preBoundChannel, keyStoreChannels));
+ server.addConnector(connectorFactory.createConnector(metric, server, preBoundChannel));
listenedPorts.add(connectorFactory.getConnectorConfig().listenPort());
}
@@ -257,43 +248,6 @@ public class JettyHttpServer extends AbstractServerProvider {
return "/" + servletPathsConfig.servlets(id.stringValue()).path();
}
- // Ugly trick to get generic type literal.
- @SuppressWarnings("unchecked")
- private static final Class<Map<?, ?>> mapClass = (Class<Map<?, ?>>) (Object) Map.class;
-
- private Map<Path, FileChannel> getKeyStoreFileChannels(BundleContext bundleContext) {
- try {
- Collection<ServiceReference<Map<?, ?>>> serviceReferences = bundleContext.getServiceReferences(mapClass,
- "(role=com.yahoo.container.standalone.StandaloneContainerActivator.KeyStoreFileChannels)");
-
- if (serviceReferences == null || serviceReferences.isEmpty())
- return Collections.emptyMap();
-
- if (serviceReferences.size() != 1)
- throw new IllegalStateException("Multiple KeyStoreFileChannels registered");
-
- return getKeyStoreFileChannels(bundleContext, serviceReferences.iterator().next());
- } catch (InvalidSyntaxException e) {
- throw throwUnchecked(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- private Map<Path, FileChannel> getKeyStoreFileChannels(BundleContext bundleContext, ServiceReference<Map<?, ?>> keyStoreFileChannelReference) {
- Map<?, ?> fileChannelMap = bundleContext.getService(keyStoreFileChannelReference);
- try {
- if (fileChannelMap == null)
- return Collections.emptyMap();
-
- Map<Path, FileChannel> result = (Map<Path, FileChannel>) fileChannelMap;
- log.fine("Using file channel for " + result.keySet());
- return result;
- } finally {
- //if we change this to be anything other than a simple map, we should hold the reference as long as the object is in use.
- bundleContext.ungetService(keyStoreFileChannelReference);
- }
- }
-
private ServletContextHandler createServletContextHandler() {
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/");
@@ -324,8 +278,8 @@ public class JettyHttpServer extends AbstractServerProvider {
return bundleContext.getService(ref);
}
- private static ExecutorService newJanitor(final ThreadFactory factory) {
- final int threadPoolSize = Runtime.getRuntime().availableProcessors();
+ private static ExecutorService newJanitor(ThreadFactory factory) {
+ int threadPoolSize = Runtime.getRuntime().availableProcessors();
log.info("Creating janitor executor with " + threadPoolSize + " threads");
return Executors.newFixedThreadPool(
threadPoolSize,
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/servlet/ServletRequest.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/servlet/ServletRequest.java
index 3cbe415d39d..db8780b087c 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/servlet/ServletRequest.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/servlet/ServletRequest.java
@@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletRequestWrapper;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
+import java.security.Principal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
@@ -36,6 +37,7 @@ import static com.yahoo.jdisc.http.core.HttpServletRequestUtils.getConnection;
* @since 5.27
*/
public class ServletRequest extends HttpServletRequestWrapper implements ServletOrJdiscHttpRequest {
+ public static final String JDISC_REQUEST_PRINCIPAL = "jdisc.request.principal";
private final HttpServletRequest request;
private final HeaderFields headerFields;
@@ -252,4 +254,14 @@ public class ServletRequest extends HttpServletRequestWrapper implements Servlet
public long getConnectedAt(TimeUnit unit) {
return unit.convert(connectedAt, TimeUnit.MILLISECONDS);
}
+
+ @Override
+ public Principal getUserPrincipal() {
+ // NOTE: The principal from the underlying servlet request is ignored. JDisc filters are the source-of-truth.
+ return (Principal) request.getAttribute(JDISC_REQUEST_PRINCIPAL);
+ }
+
+ public void setUserPrincipal(Principal principal) {
+ request.setAttribute(JDISC_REQUEST_PRINCIPAL, principal);
+ }
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java
new file mode 100644
index 00000000000..fb0a5869bb3
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreConfigurator.java
@@ -0,0 +1,95 @@
+// 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;
+import com.yahoo.jdisc.http.ssl.pem.PemSslKeyStore;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.util.logging.Logger;
+
+/**
+ * @author bjorncs
+ */
+public class DefaultSslKeyStoreConfigurator implements SslKeyStoreConfigurator {
+
+ private static final Logger log = Logger.getLogger(DefaultSslKeyStoreConfigurator.class.getName());
+
+ private final SecretStore secretStore;
+ private final ConnectorConfig.Ssl config;
+
+ @Inject
+ public DefaultSslKeyStoreConfigurator(ConnectorConfig config, SecretStore secretStore) {
+ validateConfig(config.ssl());
+ this.secretStore = secretStore;
+ this.config = config.ssl();
+ }
+
+ private static void validateConfig(ConnectorConfig.Ssl config) {
+ if (!config.enabled()) return;
+ switch (config.keyStoreType()) {
+ case JKS:
+ validateJksConfig(config);
+ break;
+ case PEM:
+ validatePemConfig(config);
+ break;
+ }
+ }
+
+ @Override
+ public void configure(SslKeyStoreContext context) {
+ if (!config.enabled()) return;
+ switch (config.keyStoreType()) {
+ case JKS:
+ context.updateKeyStore(config.keyStorePath(), "JKS", secretStore.getSecret(config.keyDbKey()));
+ break;
+ case PEM:
+ context.updateKeyStore(createPemKeyStore(config.pemKeyStore()));
+ break;
+ }
+ }
+
+ private static void validateJksConfig(ConnectorConfig.Ssl ssl) {
+ if (!ssl.pemKeyStore().keyPath().isEmpty() || ! ssl.pemKeyStore().certificatePath().isEmpty()) {
+ throw new IllegalArgumentException("pemKeyStore attributes can not be set when keyStoreType is JKS.");
+ }
+ if (ssl.keyDbKey().isEmpty()) {
+ throw new IllegalArgumentException("Missing password for JKS keystore");
+ }
+ }
+
+ private static void validatePemConfig(ConnectorConfig.Ssl ssl) {
+ if (! ssl.keyStorePath().isEmpty()) {
+ throw new IllegalArgumentException("keyStorePath can not be set when keyStoreType is PEM");
+ }
+ if (!ssl.keyDbKey().isEmpty()) {
+ // TODO Make an error once there are separate passwords for truststore and keystore
+ log.warning("Encrypted PEM key stores are not supported. Password is only applied to truststore");
+ }
+ if (ssl.pemKeyStore().certificatePath().isEmpty()) {
+ throw new IllegalArgumentException("Missing certificate path.");
+ }
+ if (ssl.pemKeyStore().keyPath().isEmpty()) {
+ throw new IllegalArgumentException("Missing key path.");
+ }
+ }
+
+ private static KeyStore createPemKeyStore(ConnectorConfig.Ssl.PemKeyStore pemKeyStore) {
+ try {
+ Path certificatePath = Paths.get(pemKeyStore.certificatePath());
+ Path keyPath = Paths.get(pemKeyStore.keyPath());
+ return new PemSslKeyStore(certificatePath, keyPath).loadJavaKeyStore();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed setting up key store for " + pemKeyStore.keyPath() + ", " + pemKeyStore.certificatePath(), e);
+ }
+ }
+
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java
new file mode 100644
index 00000000000..44a9c606576
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/DefaultSslKeyStoreContext.java
@@ -0,0 +1,51 @@
+// 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 DefaultSslKeyStoreContext implements SslKeyStoreContext {
+
+ private final SslContextFactory sslContextFactory;
+
+ public DefaultSslKeyStoreContext(SslContextFactory sslContextFactory) {
+ this.sslContextFactory = sslContextFactory;
+ }
+
+ @Override
+ public void updateKeyStore(KeyStore keyStore) {
+ updateKeyStore(keyStore, null);
+ }
+
+ @Override
+ public void updateKeyStore(KeyStore keyStore, String password) {
+ updateKeyStore(sslContextFactory -> {
+ sslContextFactory.setKeyStore(keyStore);
+ if (password != null) {
+ sslContextFactory.setKeyStorePassword(password);
+ }
+ });
+ }
+
+ @Override
+ public void updateKeyStore(String keyStorePath, String keyStoreType, String keyStorePassword) {
+ updateKeyStore(sslContextFactory -> {
+ sslContextFactory.setKeyStorePath(keyStorePath);
+ sslContextFactory.setKeyStoreType(keyStoreType);
+ sslContextFactory.setKeyStorePassword(keyStorePassword);
+ });
+ }
+
+ private void updateKeyStore(Consumer<SslContextFactory> reloader) {
+ try {
+ sslContextFactory.reload(reloader);
+ } catch (Exception e) {
+ throw new RuntimeException("Could not update keystore: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/JKSKeyStore.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/JKSKeyStore.java
deleted file mode 100644
index ce3c6f6ea4a..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/JKSKeyStore.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-
-/**
- * @author tonytv
- */
-public class JKSKeyStore extends SslKeyStore {
-
- private static final String keyStoreType = "JKS";
- private final Path keyStoreFile;
-
- public JKSKeyStore(Path keyStoreFile) {
- this.keyStoreFile = keyStoreFile;
- }
-
- @Override
- public KeyStore loadJavaKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
- try(InputStream stream = Files.newInputStream(keyStoreFile)) {
- KeyStore keystore = KeyStore.getInstance(keyStoreType);
- keystore.load(stream, getKeyStorePassword().map(String::toCharArray).orElse(null));
- return keystore;
- }
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/ReaderForPath.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/ReaderForPath.java
deleted file mode 100644
index b04d91d7403..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/ReaderForPath.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.io.Reader;
-import java.nio.file.Path;
-
-/**
- * A reader along with the path used to construct it.
- *
- * @author tonytv
- */
-public final class ReaderForPath {
-
- public final Reader reader;
- public final Path path;
-
- public ReaderForPath(Reader reader, Path path) {
- this.reader = reader;
- this.path = path;
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactory.java
deleted file mode 100644
index 0f39c132b67..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslContextFactory.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.IOException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * @author <a href="mailto:charlesk@yahoo-inc.com">Charles Kim</a>
- */
-public class SslContextFactory {
-
- private static final Logger log = Logger.getLogger(SslContextFactory.class.getName());
- private static final String DEFAULT_ALGORITHM = "SunX509";
- private static final String DEFAULT_PROTOCOL = "TLS";
- private final SSLContext sslContext;
-
- private SslContextFactory(SSLContext sslContext) {
- this.sslContext = sslContext;
- }
-
- public SSLContext getServerSSLContext() {
- return this.sslContext;
- }
-
- public static SslContextFactory newInstanceFromTrustStore(SslKeyStore trustStore) {
- return newInstance(DEFAULT_ALGORITHM, DEFAULT_PROTOCOL, null, trustStore);
- }
-
- public static SslContextFactory newInstance(SslKeyStore trustStore, SslKeyStore keyStore) {
- return newInstance(DEFAULT_ALGORITHM, DEFAULT_PROTOCOL, keyStore, trustStore);
- }
-
- public static SslContextFactory newInstance(String sslAlgorithm, String sslProtocol,
- SslKeyStore keyStore, SslKeyStore trustStore) {
- log.fine("Configuring SSLContext...");
- log.fine("Using " + sslAlgorithm + " algorithm.");
- try {
- SSLContext sslContext = SSLContext.getInstance(sslProtocol);
- sslContext.init(
- keyStore == null ? null : getKeyManagers(keyStore, sslAlgorithm),
- trustStore == null ? null : getTrustManagers(trustStore, sslAlgorithm),
- null);
- return new SslContextFactory(sslContext);
- } catch (Exception e) {
- log.log(Level.SEVERE, "Got exception creating SSLContext.", e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Used for the key store, which contains the SSL cert and private key.
- */
- public static javax.net.ssl.KeyManager[] getKeyManagers(SslKeyStore keyStore,
- String sslAlgorithm)
- throws NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException,
- KeyStoreException {
-
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(sslAlgorithm);
- keyManagerFactory.init(
- keyStore.loadJavaKeyStore(),
- keyStore.getKeyStorePassword().map(String::toCharArray).orElse(null));
- log.fine("KeyManagerFactory initialized with keystore");
- return keyManagerFactory.getKeyManagers();
- }
-
- /**
- * Used for the trust store, which contains certificates from other parties that you expect to communicate with,
- * or from Certificate Authorities that you trust to identify other parties.
- */
- public static javax.net.ssl.TrustManager[] getTrustManagers(SslKeyStore trustStore,
- String sslAlgorithm)
- throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
-
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(sslAlgorithm);
- trustManagerFactory.init(trustStore.loadJavaKeyStore());
- log.fine("TrustManagerFactory initialized with truststore.");
- return trustManagerFactory.getTrustManagers();
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStore.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStore.java
deleted file mode 100644
index 1201bb08afc..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStore.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.io.IOException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.util.Optional;
-
-/**
- *
- * @author <a href="mailto:charlesk@yahoo-inc.com">Charles Kim</a>
- */
-public abstract class SslKeyStore {
-
- private Optional<String> keyStorePassword = Optional.empty();
-
- public Optional<String> getKeyStorePassword() {
- return keyStorePassword;
- }
-
- public void setKeyStorePassword(String keyStorePassword) {
- this.keyStorePassword = Optional.of(keyStorePassword);
- }
-
- public abstract KeyStore loadJavaKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException;
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.java
new file mode 100644
index 00000000000..619f4a636ed
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreConfigurator.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 SslKeyStoreContext}. The implementor can assume that
+ * the {@link SslKeyStoreContext} instance is thread-safe and be updated at any time
+ * during and after the call to{@link #configure(SslKeyStoreContext)}.
+ * Modifying the {@link SslKeyStoreContext} instance will trigger a hot reload of the keystore in JDisc.
+ *
+ * @author bjorncs
+ */
+public interface SslKeyStoreConfigurator {
+ void configure(SslKeyStoreContext context);
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.java
new file mode 100644
index 00000000000..2a25f6d78b5
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/SslKeyStoreContext.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 keystore in JDisc. Any update will trigger a hot reload and new connections will
+ * immediately see the new certificate chain.
+ *
+ * @author bjorncs
+ */
+public interface SslKeyStoreContext {
+ void updateKeyStore(KeyStore keyStore);
+ void updateKeyStore(KeyStore keyStore, String password);
+ void updateKeyStore(String keyStorePath, String keyStoreType, String keyStorePassword);
+}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java
index c47d36991d4..5f817d4cfc2 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/package-info.java
@@ -1,4 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @author bjorncs
+ */
@ExportPackage
package com.yahoo.jdisc.http.ssl;
+
import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStore.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStore.java
index 21272f202ea..b52e923662f 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStore.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStore.java
@@ -2,7 +2,6 @@
package com.yahoo.jdisc.http.ssl.pem;
import com.google.common.base.Preconditions;
-import com.yahoo.jdisc.http.ssl.ReaderForPath;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
@@ -16,9 +15,13 @@ import javax.annotation.concurrent.GuardedBy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.Key;
+import java.security.KeyStore;
import java.security.KeyStore.LoadStoreParameter;
-import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
@@ -58,10 +61,6 @@ public class PemKeyStore extends KeyStoreSpi {
@GuardedBy("this")
private final Map<String, Certificate> aliasToCertificate = new LinkedHashMap<>();
-
- public PemKeyStore() {}
-
-
/**
* The user is responsible for closing any readers given in the parameter.
*/
@@ -287,30 +286,51 @@ public class PemKeyStore extends KeyStoreSpi {
}
}
- public static class PemLoadStoreParameter implements LoadStoreParameter {
- private PemLoadStoreParameter() {}
+ // A reader along with the path used to construct it.
+ private static class ReaderForPath {
+ final Reader reader;
+ final Path path;
- @Override
- public ProtectionParameter getProtectionParameter() {
- return null;
+ private ReaderForPath(Reader reader, Path path) {
+ this.reader = reader;
+ this.path = path;
+ }
+
+ static ReaderForPath of(Path path) {
+ try {
+ return new ReaderForPath(Files.newBufferedReader(path), path);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
}
- public static final class KeyStoreLoadParameter extends PemLoadStoreParameter {
- public final ReaderForPath certificateReader;
- public final ReaderForPath keyReader;
+ static class TrustStoreLoadParameter implements KeyStore.LoadStoreParameter {
+ final ReaderForPath certificateReader;
- public KeyStoreLoadParameter(ReaderForPath certificateReader, ReaderForPath keyReader) {
- this.certificateReader = certificateReader;
- this.keyReader = keyReader;
+ TrustStoreLoadParameter(Path certificateReader) {
+ this.certificateReader = ReaderForPath.of(certificateReader);
+ }
+
+ @Override
+ public KeyStore.ProtectionParameter getProtectionParameter() {
+ return null;
}
}
- public static final class TrustStoreLoadParameter extends PemLoadStoreParameter {
- public final ReaderForPath certificateReader;
+ static class KeyStoreLoadParameter implements KeyStore.LoadStoreParameter {
+ final ReaderForPath certificateReader;
+ final ReaderForPath keyReader;
+
+ KeyStoreLoadParameter(Path certificateReader, Path keyReader) {
+ this.certificateReader = ReaderForPath.of(certificateReader);
+ this.keyReader = ReaderForPath.of(keyReader);
+ }
- public TrustStoreLoadParameter(ReaderForPath certificateReader) {
- this.certificateReader = certificateReader;
+ @Override
+ public KeyStore.ProtectionParameter getProtectionParameter() {
+ return null;
}
}
+
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStoreProvider.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStoreProvider.java
deleted file mode 100644
index c1fcf8c33bf..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemKeyStoreProvider.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.pem;
-
-import java.security.Provider;
-
-/**
- * @author Tony Vaagenes
- */
-public class PemKeyStoreProvider extends Provider {
-
- public static final String name = "PEMKeyStoreProvider";
- public static final double version = 1;
- public static final String description = "Provides PEM keystore support";
-
- public PemKeyStoreProvider() {
- super(name, version, description);
- putService(new Service(this, "KeyStore", "PEM", PemKeyStore. class.getName(), PemKeyStore.aliases, PemKeyStore.attributes));
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemSslKeyStore.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemSslKeyStore.java
index bf91f0eb259..2ae1894a8d4 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemSslKeyStore.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/ssl/pem/PemSslKeyStore.java
@@ -1,15 +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.pem;
-import com.yahoo.jdisc.http.ssl.SslKeyStore;
import com.yahoo.jdisc.http.ssl.pem.PemKeyStore.KeyStoreLoadParameter;
-import com.yahoo.jdisc.http.ssl.pem.PemKeyStore.PemLoadStoreParameter;
import com.yahoo.jdisc.http.ssl.pem.PemKeyStore.TrustStoreLoadParameter;
import java.io.IOException;
+import java.nio.file.Path;
import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
import java.security.Security;
import java.security.cert.CertificateException;
@@ -17,37 +18,46 @@ import java.security.cert.CertificateException;
* Responsible for creating pem key stores.
*
* @author Tony Vaagenes
+ * @author bjorncs
*/
-public class PemSslKeyStore extends SslKeyStore {
+public class PemSslKeyStore {
static {
Security.addProvider(new PemKeyStoreProvider());
}
- private static final String keyStoreType = "PEM";
- private final PemLoadStoreParameter loadParameter;
+ private static final String KEY_STORE_TYPE = "PEM";
+
+ private final LoadStoreParameter loadParameter;
private KeyStore keyStore;
- public PemSslKeyStore(KeyStoreLoadParameter loadParameter) {
- this.loadParameter = loadParameter;
+ public PemSslKeyStore(Path certificatePath, Path keyPath) {
+ this.loadParameter = new KeyStoreLoadParameter(certificatePath, keyPath);
}
- public PemSslKeyStore(TrustStoreLoadParameter loadParameter) {
- this.loadParameter = loadParameter;
+ public PemSslKeyStore(Path certificatePath) {
+ this.loadParameter = new TrustStoreLoadParameter(certificatePath);
}
- @Override
- public KeyStore loadJavaKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
- if (getKeyStorePassword().isPresent()) {
- throw new UnsupportedOperationException("PEM key store with password is currently not supported. Please file a feature request.");
- }
-
- //cached since Reader(in loadParameter) can only be used one time.
+ public KeyStore loadJavaKeyStore()
+ throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
if (keyStore == null) {
- keyStore = KeyStore.getInstance(keyStoreType);
+ keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
keyStore.load(loadParameter);
}
return keyStore;
}
+ private static class PemKeyStoreProvider extends Provider {
+
+ static final String NAME = "PEMKeyStoreProvider";
+ static final double VERSION = 1;
+ static final String DESCRIPTION = "Provides PEM keystore support";
+
+ PemKeyStoreProvider() {
+ super(NAME, VERSION, DESCRIPTION);
+ putService(new Service(this, "KeyStore", "PEM", PemKeyStore. class.getName(), PemKeyStore.aliases, PemKeyStore.attributes));
+ }
+ }
+
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ChunkReader.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ChunkReader.java
deleted file mode 100644
index a550a013a3b..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ChunkReader.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// 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.test;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class ChunkReader {
-
- private static final Pattern CONTENT_LENGTH = Pattern.compile(".+^content-length: (\\d+)$.*",
- Pattern.CASE_INSENSITIVE |
- Pattern.MULTILINE |
- Pattern.DOTALL);
- private static final Pattern CHUNKED_ENCODING = Pattern.compile(".+^transfer-encoding: chunked$.*",
- Pattern.CASE_INSENSITIVE |
- Pattern.MULTILINE |
- Pattern.DOTALL);
- private final InputStream in;
- private StringBuilder reading = new StringBuilder();
- private boolean readingHeader = true;
-
- public ChunkReader(InputStream in) {
- this.in = in;
- }
-
- public boolean isEndOfContent() throws IOException {
- if (in.available() != 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(in.available()).append(": ");
- for(int c = in.read(); c != -1; c = in.read()) {
- sb.append('\'');
- sb.append(c);
- sb.append("' ");
- }
- throw new IllegalStateException("This is not the end '" + sb.toString());
- }
- return in.available() == 0;
- }
-
- public String readChunk() throws IOException {
- while (true) {
- String ret = removeNextChunk();
- if (ret != null) {
- return ret;
- }
- readFromStream();
- }
- }
-
- private String readContent(int length) throws IOException {
- while (reading.length() < length) {
- readFromStream();
- }
- return splitReadBuffer(length);
- }
-
- private void readFromStream() throws IOException {
- byte[] buf = new byte[4096];
- try {
- while (!Thread.currentThread().isInterrupted()) {
- int len = in.read(buf, 0, buf.length);
- if (len < 0) {
- throw new IOException("Socket is closed.");
- }
- if (len > 0) {
- reading.append(StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buf, 0, len)));
- break;
- }
- Thread.sleep(10);
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
-
- private String removeNextChunk() throws IOException {
- if (readingHeader) {
- int pos = reading.indexOf("\r\n\r\n");
- if (pos < 0) {
- return null;
- }
- String ret = splitReadBuffer(pos + 4);
- Matcher m = CONTENT_LENGTH.matcher(ret);
- if (m.matches()) {
- ret += readContent(Integer.valueOf(m.group(1)));
- }
- readingHeader = !CHUNKED_ENCODING.matcher(ret).matches();
- return ret;
- } else if (reading.indexOf("0\r\n") == 0) {
- int pos = reading.indexOf("\r\n\r\n", 1);
- if (pos < 0) {
- return null;
- }
- readingHeader = true;
- return splitReadBuffer(pos + 4);
- } else {
- int pos = reading.indexOf("\r\n");
- if (pos < 0) {
- return null;
- }
- pos = reading.indexOf("\r\n", pos + 2);
- if (pos < 0) {
- return null;
- }
- return splitReadBuffer(pos + 2);
- }
- }
-
- private String splitReadBuffer(int pos) {
- String ret = reading.substring(0, pos);
- if (pos < reading.length()) {
- reading = new StringBuilder(reading.substring(pos));
- } else {
- reading = new StringBuilder();
- }
- return ret;
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/FilterTestDriver.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/FilterTestDriver.java
deleted file mode 100644
index 1532bc65bdf..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/FilterTestDriver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.test;
-
-import com.yahoo.jdisc.Request;
-import com.yahoo.jdisc.Response;
-import com.yahoo.jdisc.application.BindingRepository;
-import com.yahoo.jdisc.handler.AbstractRequestHandler;
-import com.yahoo.jdisc.handler.ContentChannel;
-import com.yahoo.jdisc.handler.ResponseDispatch;
-import com.yahoo.jdisc.handler.ResponseHandler;
-import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.jdisc.http.filter.RequestFilter;
-import com.yahoo.jdisc.http.filter.ResponseFilter;
-
-import java.io.IOException;
-import java.util.concurrent.Exchanger;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import static com.yahoo.jdisc.http.test.ServerTestDriver.newFilterModule;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- *
- * TODO: dead code?
- */
-public class FilterTestDriver {
-
- private final ServerTestDriver driver;
- private final MyRequestHandler requestHandler;
-
- private FilterTestDriver(ServerTestDriver driver, MyRequestHandler requestHandler) {
- this.driver = driver;
- this.requestHandler = requestHandler;
- }
-
- public boolean close() throws IOException {
- return driver.close();
- }
-
- public HttpRequest filterRequest(String request) throws IOException, TimeoutException, InterruptedException {
- driver.client().writeRequest(request);
- return (HttpRequest)requestHandler.exchanger.exchange(null, 60, TimeUnit.SECONDS);
- }
-
- public static FilterTestDriver newInstance(final BindingRepository<RequestFilter> requestFilters,
- final BindingRepository<ResponseFilter> responseFilters)
- throws IOException {
- MyRequestHandler handler = new MyRequestHandler();
- return new FilterTestDriver(ServerTestDriver.newInstance(handler,
- newFilterModule(requestFilters, responseFilters)),
- handler);
- }
-
- private static class MyRequestHandler extends AbstractRequestHandler {
-
- final Exchanger<Request> exchanger = new Exchanger<>();
-
- @Override
- public ContentChannel handleRequest(Request request, ResponseHandler handler) {
- ResponseDispatch.newInstance(Response.Status.OK).dispatch(handler);
- try {
- exchanger.exchange(request);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return null;
- }
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteClient.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteClient.java
deleted file mode 100644
index dd6033c9975..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteClient.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.test;
-
-import com.yahoo.jdisc.http.server.jetty.JettyHttpServer;
-import com.yahoo.jdisc.http.ssl.SslContextFactory;
-import com.yahoo.jdisc.http.ssl.SslKeyStore;
-
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-public class RemoteClient extends ChunkReader {
-
- private final Socket socket;
-
- private RemoteClient(Socket socket) throws IOException {
- super(socket.getInputStream());
- this.socket = socket;
- }
-
- public void close() throws IOException {
- socket.close();
- }
-
- public void writeRequest(String request) throws IOException {
- socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
- }
-
- public static RemoteClient newInstance(JettyHttpServer server) throws IOException {
- return newInstance(server.getListenPort());
- }
-
- public static RemoteClient newInstance(int listenPort) throws IOException {
- return new RemoteClient(new Socket("localhost", listenPort));
- }
-
- public static RemoteClient newSslInstance(int listenPort, SslKeyStore sslKeyStore) throws IOException {
- SSLContext ctx = SslContextFactory.newInstanceFromTrustStore(sslKeyStore).getServerSSLContext();
- if (ctx == null) {
- throw new RuntimeException("Failed to create socket with SSLContext.");
- }
- return new RemoteClient(ctx.getSocketFactory().createSocket("localhost", listenPort));
- }
-
- public static RemoteClient newSslInstance(JettyHttpServer server, SslKeyStore keyStore) throws IOException {
- return newSslInstance(server.getListenPort(), keyStore);
- }
-
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteServer.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteServer.java
deleted file mode 100644
index 62b4bb306ed..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/RemoteServer.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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.test;
-
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
- */
-public class RemoteServer implements Runnable {
-
- private final Thread thread = new Thread(this, "RemoteServer@" + System.identityHashCode(this));
- private final LinkedBlockingQueue<Socket> clients = new LinkedBlockingQueue<>();
- private final ServerSocket server;
-
- private RemoteServer(int listenPort) throws IOException {
- this.server = new ServerSocket(listenPort);
- }
-
- @Override
- public void run() {
- try {
- while (!Thread.interrupted()) {
- Socket client = server.accept();
- if (client != null) {
- clients.add(client);
- }
- }
- } catch (IOException e) {
- if (!server.isClosed()) {
- e.printStackTrace();
- }
- }
- }
-
- public URI newRequestUri(String uri) {
- return newRequestUri(URI.create(uri));
- }
-
- public URI newRequestUri(URI uri) {
- URI serverUri = connectionSpec();
- try {
- return new URI(serverUri.getScheme(), serverUri.getUserInfo(), serverUri.getHost(),
- serverUri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment());
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public URI connectionSpec() {
- return URI.create("http://localhost:" + server.getLocalPort() + "/");
- }
-
- public Connection awaitConnection(int timeout, TimeUnit unit) throws InterruptedException, IOException {
- Socket client = clients.poll(timeout, unit);
- if (client == null) {
- return null;
- }
- return new Connection(client);
- }
-
- public boolean close(int timeout, TimeUnit unit) {
- try {
- server.close();
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- try {
- thread.join(unit.toMillis(timeout));
- } catch (InterruptedException e) {
- return false;
- }
- return !thread.isAlive();
- }
-
- public static RemoteServer newInstance() throws IOException {
- RemoteServer ret = new RemoteServer(0);
- ret.thread.start();
- return ret;
- }
-
- public static class Connection extends ChunkReader {
-
- private final Socket socket;
- private final PrintWriter out;
-
- private Connection(Socket socket) throws IOException {
- super(socket.getInputStream());
- this.socket = socket;
- this.out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
- }
-
- public void writeChunk(String chunk) {
- out.print(chunk);
- }
-
- public void close() throws IOException {
- out.close();
- socket.close();
- }
- }
-}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ServerTestDriver.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ServerTestDriver.java
deleted file mode 100644
index 03e2257ce70..00000000000
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/test/ServerTestDriver.java
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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.test;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
-import com.google.inject.TypeLiteral;
-import com.yahoo.jdisc.application.BindingRepository;
-import com.yahoo.jdisc.application.ContainerActivator;
-import com.yahoo.jdisc.application.ContainerBuilder;
-import com.yahoo.jdisc.handler.RequestHandler;
-import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.jdisc.http.filter.RequestFilter;
-import com.yahoo.jdisc.http.filter.ResponseFilter;
-import com.yahoo.jdisc.http.server.jetty.JettyHttpServer;
-import com.yahoo.jdisc.http.ssl.SslKeyStore;
-import com.yahoo.jdisc.test.TestDriver;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
- */
-public class ServerTestDriver {
-
- private final TestDriver driver;
- private final JettyHttpServer server;
- private final RemoteClient client;
-
- private ServerTestDriver(TestDriver driver, JettyHttpServer server, RemoteClient client) {
- this.driver = driver;
- this.server = server;
- this.client = client;
- }
-
- public boolean close() throws IOException {
- client.close();
- server.close();
- server.release();
- return driver.close();
- }
-
- public TestDriver parent() {
- return driver;
- }
-
- public ContainerActivator containerActivator() {
- return driver;
- }
-
- public JettyHttpServer server() {
- return server;
- }
-
- public RemoteClient client() {
- return client;
- }
-
- public HttpRequest newRequest(HttpRequest.Method method, String uri, HttpRequest.Version version) {
- return HttpRequest.newServerRequest(driver, newRequestUri(uri), method, version);
- }
-
- public URI newRequestUri(String uri) {
- return newRequestUri(URI.create(uri));
- }
-
- public URI newRequestUri(URI uri) {
- try {
- return new URI("http", null, "locahost",
- server.getListenPort(), uri.getPath(), uri.getQuery(), uri.getFragment());
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public static ServerTestDriver newInstance(RequestHandler requestHandler, Module... guiceModules) throws IOException {
- return newInstance(requestHandler, Arrays.asList(guiceModules));
- }
-
- public static ServerTestDriver newInstance(RequestHandler requestHandler, Iterable<Module> guiceModules)
- throws IOException {
- List<Module> lst = new LinkedList<>();
- lst.add(newDefaultModule());
- for (Module module : guiceModules) {
- lst.add(module);
- }
- TestDriver driver = TestDriver.newSimpleApplicationInstanceWithoutOsgi(lst.toArray(new Module[lst.size()]));
- ContainerBuilder builder = driver.newContainerBuilder();
- builder.serverBindings().bind("*://*/*", requestHandler);
- JettyHttpServer server = builder.guiceModules().getInstance(JettyHttpServer.class);
- return newInstance(null, driver, builder, server);
- }
-
- private static ServerTestDriver newInstance(SslKeyStore clientTrustStore, TestDriver driver, ContainerBuilder builder,
- JettyHttpServer server) throws IOException {
- builder.serverProviders().install(server);
- driver.activateContainer(builder);
- try {
- server.start();
- } catch (RuntimeException e) {
- server.release();
- driver.close();
- throw e;
- }
- RemoteClient client;
- if (clientTrustStore == null) {
- client = RemoteClient.newInstance(server);
- } else {
- client = RemoteClient.newSslInstance(server, clientTrustStore);
- }
- return new ServerTestDriver(driver, server, client);
- }
-
- public static Module newDefaultModule() {
- return new AbstractModule() {
-
- @Override
- protected void configure() {
- bind(new TypeLiteral<BindingRepository<RequestFilter>>() { })
- .toInstance(new BindingRepository<>());
- bind(new TypeLiteral<BindingRepository<ResponseFilter>>() { })
- .toInstance(new BindingRepository<>());
- }
- };
- }
-
- public static Module newFilterModule(final BindingRepository<RequestFilter> requestFilters,
- final BindingRepository<ResponseFilter> responseFilters) {
- return new AbstractModule() {
-
- @Override
- protected void configure() {
- if (requestFilters != null) {
- bind(new TypeLiteral<BindingRepository<RequestFilter>>() { }).toInstance(requestFilters);
- }
- if (responseFilters != null) {
- bind(new TypeLiteral<BindingRepository<ResponseFilter>>() { }).toInstance(responseFilters);
- }
- }
- };
- }
-}