diff options
Diffstat (limited to 'jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java')
-rw-r--r-- | jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java | 72 |
1 files changed, 59 insertions, 13 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index 54338c64c1e..96180f48229 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 @@ -8,6 +8,8 @@ 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 org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.ConnectionFactory; @@ -22,11 +24,15 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import javax.servlet.ServletRequest; import java.io.IOException; -import java.io.UncheckedIOException; +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; @@ -37,8 +43,10 @@ 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 @@ -76,11 +84,11 @@ public class ConnectorFactory { return connectorConfig; } - public ServerConnector createConnector(final Metric metric, final Server server, final ServerSocketChannel ch) { + public ServerConnector createConnector(final Metric metric, final Server server, final ServerSocketChannel ch, Map<Path, FileChannel> keyStoreChannels) { ServerConnector connector; if (connectorConfig.ssl().enabled()) { connector = new JDiscServerConnector(connectorConfig, metric, server, ch, - newSslConnectionFactory(), + newSslConnectionFactory(keyStoreChannels), newHttpConnectionFactory()); } else { connector = new JDiscServerConnector(connectorConfig, metric, server, ch, @@ -117,7 +125,7 @@ public class ConnectorFactory { } //TODO: does not support loading non-yahoo readable JKS key stores. - private SslConnectionFactory newSslConnectionFactory() { + private SslConnectionFactory newSslConnectionFactory(Map<Path, FileChannel> keyStoreChannels) { Ssl sslConfig = connectorConfig.ssl(); SslContextFactory factory = new SslContextFactory(); @@ -167,7 +175,7 @@ public class ConnectorFactory { Optional<String> keyDbPassword = secret(sslConfig.keyDbKey()); switch (sslConfig.keyStoreType()) { case PEM: - factory.setKeyStore(getKeyStore(sslConfig.pemKeyStore())); + factory.setKeyStore(getKeyStore(sslConfig.pemKeyStore(), keyStoreChannels)); if (keyDbPassword.isPresent()) log.warning("Encrypted PEM key stores are not supported."); break; @@ -200,16 +208,54 @@ public class ConnectorFactory { return () -> new RuntimeException(String.format("Password is required for JKS %s store", type)); } - private static KeyStore getKeyStore(PemKeyStore pemKeyStore) { + 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."); - 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); + + 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); } |