From 6bfd013fc5699ca5084ea9ba477cb729f4c54754 Mon Sep 17 00:00:00 2001 From: Tigran Mkrtchyan Date: Fri, 14 Jun 2024 13:45:19 +0200 Subject: [PATCH] standalone: update server to support tls Motivation: As standalone server is used to demonstrate xrootd4j implementations capabilities, the TLS setup should be included into the functionality. Modification: Update DataServerConfiguration to support `--tls`, `--hostcert` and `--hostkey` options. Update DataServerChannelInitializer to optionally enable TLS. Update pom to use "sslcontext-kickstart" library for handle certificates in pem format. Result: standalone server with optional TLS capability. Issue: #179 Acked-by: Lea Morschel Target: master --- pom.xml | 11 ++++ xrootd4j-standalone/pom.xml | 10 ++++ .../DataServerChannelInitializer.java | 59 ++++++++++++++++++- .../standalone/DataServerConfiguration.java | 9 ++- .../standalone/DataServerOptionParser.java | 16 ++++- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 3694c40f..87c83cef 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ UTF-8 + 8.2.0 @@ -196,6 +197,16 @@ archetype-packaging 2.4 + + io.github.hakky54 + sslcontext-kickstart + ${ssl-kickstart.version} + + + io.github.hakky54 + sslcontext-kickstart-for-pem + ${ssl-kickstart.version} + diff --git a/xrootd4j-standalone/pom.xml b/xrootd4j-standalone/pom.xml index f9e27353..5424dc57 100644 --- a/xrootd4j-standalone/pom.xml +++ b/xrootd4j-standalone/pom.xml @@ -60,6 +60,16 @@ org.dcache xrootd4j + + io.github.hakky54 + sslcontext-kickstart + + + + io.github.hakky54 + sslcontext-kickstart-for-pem + + diff --git a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerChannelInitializer.java b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerChannelInitializer.java index b08bc045..71afcddf 100644 --- a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerChannelInitializer.java +++ b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerChannelInitializer.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011-2023 dCache.org + * Copyright (C) 2011-2024 dCache.org * * This file is part of xrootd4j. * @@ -23,12 +23,16 @@ import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import nl.altindag.ssl.pem.util.PemUtils; import org.dcache.xrootd.core.XrootdAuthenticationHandler; import org.dcache.xrootd.core.XrootdDecoder; import org.dcache.xrootd.core.XrootdEncoder; import org.dcache.xrootd.core.XrootdHandshakeHandler; import org.dcache.xrootd.core.XrootdSessionHandler; import org.dcache.xrootd.plugins.ChannelHandlerFactory; +import org.dcache.xrootd.plugins.tls.SSLHandlerFactory; import org.dcache.xrootd.security.SigningPolicy; import org.dcache.xrootd.security.TLSSessionInfo; import org.dcache.xrootd.stream.ChunkedResponseWriteHandler; @@ -36,6 +40,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLException; +import javax.net.ssl.X509ExtendedKeyManager; +import java.nio.file.Paths; +import java.util.Properties; +import java.util.function.Supplier; + public class DataServerChannelInitializer extends ChannelInitializer { private static final Logger logger = LoggerFactory.getLogger( @@ -60,9 +70,25 @@ protected void initChannel(SocketChannel ch) throws Exception { /* * Placeholders, no Sigver and no TLS support yet. */ + SigningPolicy signingPolicy = new SigningPolicy(); ServerProtocolFlags flags = new ServerProtocolFlags(0); + + SSLHandlerFactory tlsFactory = null; + if (_options.withTls) { + tlsFactory = new LocalPemTlsHandler(_options.hostCert, _options.hostKey); + tlsFactory.initialize(new Properties(), true); + + flags.setMode(ServerProtocolFlags.TlsMode.OPTIONAL); + flags.setRequiresTLSForSession(true); + flags.setRequiresTLSForLogin(true); + flags.setRequiresTLSForData(true); + flags.setSupportsTLS(true); + } + + TLSSessionInfo tlsSessionInfo = new TLSSessionInfo(flags); + tlsSessionInfo.setServerSslHandlerFactory(tlsFactory); XrootdSessionHandler sessionHandler = new XrootdSessionHandler(); /* @@ -95,4 +121,35 @@ protected void initChannel(SocketChannel ch) throws Exception { signingPolicy); pipeline.addLast("data-server", dataServerHandler); } + + private static class LocalPemTlsHandler extends SSLHandlerFactory { + + /** + * Netty SSL context for the TLS handler. + */ + private final SslContext sslContext; + + /** + * Create a new instance of the TLS handler. + * @param hostcert Path to host certificate file. + * @param hostkey Path to host key file. + * @throws SSLException + */ + LocalPemTlsHandler(String hostcert, String hostkey) throws SSLException { + X509ExtendedKeyManager keyManager = + PemUtils.loadIdentityMaterial(Paths.get(hostcert), Paths.get(hostkey)); + sslContext = SslContextBuilder.forServer(keyManager).startTls(true).build(); + } + + @Override + protected Supplier buildContextSupplier(Properties properties) { + return () -> sslContext; + } + + @Override + public String getName() { + return SERVER_TLS; + } + } + } diff --git a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerConfiguration.java b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerConfiguration.java index fdfb8db6..63ffbf80 100644 --- a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerConfiguration.java +++ b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerConfiguration.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011-2023 dCache.org + * Copyright (C) 2011-2024 dCache.org * * This file is part of xrootd4j. * @@ -58,6 +58,10 @@ public class DataServerConfiguration { public final List channelHandlerPlugins; public final boolean useZeroCopy; + public final boolean withTls; + public final String hostCert; + public final String hostKey; + public final List channelHandlerFactories; public DataServerConfiguration(DataServerOptionParser parser, OptionSet options) @@ -67,6 +71,9 @@ public DataServerConfiguration(DataServerOptionParser parser, OptionSet options) pluginPath = options.valuesOf(parser.pluginPath); channelHandlerPlugins = options.valuesOf(parser.handlerPlugins); useZeroCopy = options.has(parser.zeroCopy); + withTls = options.has(parser.withTls); + hostCert = options.valueOf(parser.hostCert); + hostKey = options.valueOf(parser.hostKey); _pluginDefaults = loadDefaultProperties(pluginPath); diff --git a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerOptionParser.java b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerOptionParser.java index 4f870d96..f113c90f 100644 --- a/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerOptionParser.java +++ b/xrootd4j-standalone/src/main/java/org/dcache/xrootd/standalone/DataServerOptionParser.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2011-2023 dCache.org + * Copyright (C) 2011-2024 dCache.org * * This file is part of xrootd4j. * @@ -30,6 +30,9 @@ public class DataServerOptionParser extends OptionParser { public final OptionSpec handlerPlugins; public final OptionSpec pluginPath; public final OptionSpec zeroCopy; + public final OptionSpec withTls; + public final OptionSpec hostCert; + public final OptionSpec hostKey; { port = acceptsAll(asList("p", "port")) @@ -55,5 +58,16 @@ public class DataServerOptionParser extends OptionParser { .describedAs("url") .ofType(File.class); zeroCopy = acceptsAll(asList("z", "zerocopy"), "Use zero copy reads"); + withTls = acceptsAll(asList("tls"), "Enable TLS for session and data protection"); + hostCert = acceptsAll(asList("hostcert"), "Path to the host certificate file") + .withRequiredArg() + .describedAs("path") + .ofType(String.class) + .defaultsTo("hostcert.pem"); + hostKey = acceptsAll(asList("hostkey"), "Path to the host key file") + .withRequiredArg() + .describedAs("path") + .ofType(String.class) + .defaultsTo("hostkey.pem"); } }