Skip to content

Commit

Permalink
standalone: update server to support tls
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kofemann committed Jun 26, 2024
1 parent eabf215 commit 6bfd013
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 3 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ssl-kickstart.version>8.2.0</ssl-kickstart.version>
</properties>

<scm>
Expand Down Expand Up @@ -196,6 +197,16 @@
<artifactId>archetype-packaging</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart</artifactId>
<version>${ssl-kickstart.version}</version>
</dependency>
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-pem</artifactId>
<version>${ssl-kickstart.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
10 changes: 10 additions & 0 deletions xrootd4j-standalone/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@
<groupId>org.dcache</groupId>
<artifactId>xrootd4j</artifactId>
</dependency>
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart</artifactId>
</dependency>

<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-pem</artifactId>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (C) 2011-2023 dCache.org <support@dcache.org>
* Copyright (C) 2011-2024 dCache.org <support@dcache.org>
*
* This file is part of xrootd4j.
*
Expand All @@ -23,19 +23,29 @@
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;
import org.dcache.xrootd.util.ServerProtocolFlags;
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<SocketChannel> {

private static final Logger logger = LoggerFactory.getLogger(
Expand All @@ -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();
/*
Expand Down Expand Up @@ -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<SslContext> buildContextSupplier(Properties properties) {
return () -> sslContext;
}

@Override
public String getName() {
return SERVER_TLS;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (C) 2011-2023 dCache.org <support@dcache.org>
* Copyright (C) 2011-2024 dCache.org <support@dcache.org>
*
* This file is part of xrootd4j.
*
Expand Down Expand Up @@ -58,6 +58,10 @@ public class DataServerConfiguration {
public final List<String> channelHandlerPlugins;
public final boolean useZeroCopy;

public final boolean withTls;
public final String hostCert;
public final String hostKey;

public final List<ChannelHandlerFactory> channelHandlerFactories;

public DataServerConfiguration(DataServerOptionParser parser, OptionSet options)
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (C) 2011-2023 dCache.org <support@dcache.org>
* Copyright (C) 2011-2024 dCache.org <support@dcache.org>
*
* This file is part of xrootd4j.
*
Expand Down Expand Up @@ -30,6 +30,9 @@ public class DataServerOptionParser extends OptionParser {
public final OptionSpec<String> handlerPlugins;
public final OptionSpec<File> pluginPath;
public final OptionSpec<Void> zeroCopy;
public final OptionSpec<Void> withTls;
public final OptionSpec<String> hostCert;
public final OptionSpec<String> hostKey;

{
port = acceptsAll(asList("p", "port"))
Expand All @@ -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");
}
}

0 comments on commit 6bfd013

Please sign in to comment.