From 76f13bf7a26b79b0f4a45ec7992c4bcd8eeb9ee6 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 17 Aug 2015 18:14:08 +0200 Subject: [server] Add TLS/SSL related classes and functionality (wip) --- .../src/main/java/org/openslx/bwlp/sat/App.java | 17 ++++- .../bwlp/sat/database/mappers/DbConfiguration.java | 83 ++++++++++++++++++++++ .../org/openslx/bwlp/sat/fileserv/FileServer.java | 15 +++- .../openslx/bwlp/sat/thrift/BinaryListener.java | 43 +++++++++-- 4 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbConfiguration.java (limited to 'dozentenmodulserver/src/main/java/org') diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java index 5ceb72cc..e7d0b9aa 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java @@ -1,5 +1,6 @@ package org.openslx.bwlp.sat; +import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; import java.util.ArrayList; @@ -16,6 +17,7 @@ import org.openslx.bwlp.sat.thrift.BinaryListener; import org.openslx.bwlp.sat.thrift.cache.OperatingSystemList; import org.openslx.bwlp.sat.thrift.cache.OrganizationList; import org.openslx.bwlp.sat.util.Configuration; +import org.openslx.bwlp.sat.util.Identity; import org.openslx.bwlp.sat.util.Json; import org.openslx.bwlp.thrift.iface.ImageSummaryRead; import org.openslx.bwlp.thrift.iface.NetDirection; @@ -34,7 +36,7 @@ public class App { public static boolean DEBUG = false; - public static void main(String[] args) throws TTransportException, NoSuchAlgorithmException { + public static void main(String[] args) throws TTransportException, NoSuchAlgorithmException, IOException { //get going and show basic information in log file BasicConfigurator.configure(); if (args.length != 0 && args[0].equals("debug")) { @@ -53,6 +55,11 @@ public class App { System.exit(1); } + if (Identity.loadCertificate() == null) { + LOGGER.error("Could not set up TLS/SSL requirements, exiting"); + System.exit(1); + } + ThriftManager.setErrorCallback(new ErrorCallback() { @Override @@ -81,11 +88,16 @@ public class App { LOGGER.error("Could not start internal file server."); return; } - // Start Server + // Start Thrift Server Thread t; + // Plain t = new Thread(new BinaryListener(9090, false)); servers.add(t); t.start(); + // SSL + t = new Thread(new BinaryListener(9091, true)); + servers.add(t); + t.start(); // DEBUG if (DEBUG) { Database.printCharsetInformation(); @@ -124,5 +136,4 @@ public class App { QuickTimer.cancel(); LOGGER.info(new Date() + " - all Servers shut down, exiting...\n"); } - } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbConfiguration.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbConfiguration.java new file mode 100644 index 00000000..27dc2b6e --- /dev/null +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbConfiguration.java @@ -0,0 +1,83 @@ +package org.openslx.bwlp.sat.database.mappers; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.openslx.bwlp.sat.database.Database; +import org.openslx.bwlp.sat.database.MysqlConnection; +import org.openslx.bwlp.sat.database.MysqlStatement; + +public class DbConfiguration { + + private static final Logger LOGGER = Logger.getLogger(DbConfiguration.class); + + private static final String KEY_CERTIFICATE = "certstore"; + + public static KeyStore loadKeyStore(String password) throws KeyStoreException, SQLException, + NoSuchAlgorithmException, CertificateException, IOException { + KeyStore keystore = KeyStore.getInstance("JKS"); + InputStream stream = retrieveStream(KEY_CERTIFICATE); + if (stream == null) + return null; + keystore.load(stream, password.toCharArray()); + return keystore; + } + + public static void saveKeyStore(File file) throws SQLException, FileNotFoundException, IOException { + store(KEY_CERTIFICATE, new FileInputStream(file)); + } + + private static void store(String configKey, InputStream stream) throws IOException, SQLException { + store(configKey, IOUtils.toByteArray(stream)); + } + + private static void store(String configKey, byte[] value) throws SQLException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("INSERT INTO configuration" + + " (parameter, value) VALUES (:parameter, :value)" + + " ON DUPLICATE KEY UPDATE value = VALUES(value)"); + stmt.setString("parameter", configKey); + stmt.setBinary("value", value); + stmt.executeUpdate(); + connection.commit(); + } catch (SQLException e) { + LOGGER.error("Query failed in DbConfiguration.store()", e); + throw e; + } + } + + private static InputStream retrieveStream(String configKey) throws SQLException { + byte[] data = retrieve(configKey); + if (data == null) + return null; + return new ByteArrayInputStream(data); + } + + private static byte[] retrieve(String configKey) throws SQLException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("SELECT value FROM configuration" + + " WHERE parameter = :parameter LIMIT 1"); + stmt.setString("parameter", configKey); + ResultSet rs = stmt.executeQuery(); + if (!rs.next()) + return null; + return rs.getBytes("value"); + } catch (SQLException e) { + LOGGER.error("Query failed in DbConfiguration.retrieve()", e); + throw e; + } + } + +} diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java index f1746697..3232374e 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java @@ -13,11 +13,14 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; + import org.apache.log4j.Logger; import org.openslx.bwlp.sat.database.models.LocalImageVersion; import org.openslx.bwlp.sat.util.Configuration; import org.openslx.bwlp.sat.util.Constants; import org.openslx.bwlp.sat.util.Formatter; +import org.openslx.bwlp.sat.util.Identity; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; import org.openslx.bwlp.thrift.iface.TTransferRejectedException; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -35,6 +38,8 @@ public class FileServer implements IncomingEvent { */ private final Listener plainListener = new Listener(this, null, 9092, Constants.TRANSFER_TIMEOUT); // TODO: Config + private final Listener sslListener; + private final ThreadPoolExecutor transferPool = new ThreadPoolExecutor(2, Constants.MAX_UPLOADS + Constants.MAX_DOWNLOADS, 1, TimeUnit.MINUTES, new ArrayBlockingQueue(1)); @@ -51,6 +56,8 @@ public class FileServer implements IncomingEvent { private static final FileServer globalInstance = new FileServer(); private FileServer() { + SSLContext ctx = Identity.getSSLContext(); + sslListener = ctx == null ? null : new Listener(this, ctx, 9093, Constants.TRANSFER_TIMEOUT); } public static FileServer instance() { @@ -59,7 +66,9 @@ public class FileServer implements IncomingEvent { public boolean start() { boolean ret = plainListener.start(); - // TODO: Start SSL listener too + if (sslListener != null) { + ret |= sslListener.start(); + } return ret; } @@ -146,7 +155,9 @@ public class FileServer implements IncomingEvent { } public int getSslPort() { - return 0; // TODO + if (sslListener == null) + return 0; + return sslListener.getPort(); } public ActiveDownload createNewUserDownload(LocalImageVersion localImageData) diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/BinaryListener.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/BinaryListener.java index 3e0159b6..b00a8bc3 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/BinaryListener.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/BinaryListener.java @@ -1,14 +1,26 @@ package org.openslx.bwlp.sat.thrift; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocketFactory; import org.apache.log4j.Logger; import org.apache.thrift.protocol.TProtocolFactory; import org.apache.thrift.server.THsHaServer; import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TNonblockingServerSocket; import org.apache.thrift.transport.TNonblockingServerTransport; +import org.apache.thrift.transport.TServerSocket; +import org.apache.thrift.transport.TServerTransport; import org.apache.thrift.transport.TTransportException; +import org.openslx.bwlp.sat.util.Identity; import org.openslx.bwlp.thrift.iface.SatelliteServer; import org.openslx.thrifthelper.TBinaryProtocolSafe; @@ -17,7 +29,7 @@ public class BinaryListener implements Runnable { private static final int MAX_MSG_LEN = 30 * 1000 * 1000; private static final int MINWORKERTHREADS = 2; - private static final int MAXWORKERTHREADS = 64; + private static final int MAXWORKERTHREADS = 96; private final SatelliteServer.Processor processor = new SatelliteServer.Processor( new ServerHandler()); @@ -25,7 +37,8 @@ public class BinaryListener implements Runnable { private final TServer server; - public BinaryListener(int port, boolean secure) throws TTransportException, NoSuchAlgorithmException { + public BinaryListener(int port, boolean secure) throws TTransportException, NoSuchAlgorithmException, + IOException { if (secure) server = initSecure(port); else @@ -40,9 +53,29 @@ public class BinaryListener implements Runnable { // TODO: Restart listener; if it fails, quit server so it will be restarted by the OS } - private TServer initSecure(int port) throws NoSuchAlgorithmException, TTransportException { - // TODO - return null; + private TServer initSecure(int port) throws NoSuchAlgorithmException, TTransportException, IOException { + SSLContext context = Identity.getSSLContext(); + if (context == null) + return null; + SSLServerSocketFactory sslServerSocketFactory = context.getServerSocketFactory(); + ServerSocket listenSocket = sslServerSocketFactory.createServerSocket(); + listenSocket.setReuseAddress(true); + listenSocket.bind(new InetSocketAddress(port)); + + TServerTransport serverTransport; + try { + serverTransport = new TServerSocket(listenSocket); + } catch (TTransportException e) { + log.fatal("Could not listen on port " + port); + throw e; + } + TThreadPoolServer.Args args = new TThreadPoolServer.Args(serverTransport); + args.protocolFactory(protFactory); + args.processor(processor); + args.minWorkerThreads(MINWORKERTHREADS).maxWorkerThreads(MAXWORKERTHREADS); + args.requestTimeout(2).requestTimeoutUnit(TimeUnit.MINUTES); + args.transportFactory(new TFramedTransport.Factory(MAX_MSG_LEN)); + return new TThreadPoolServer(args); } private TServer initNormal(int port) throws TTransportException { -- cgit v1.2.3-55-g7522