From 6da706e459eeab05e19f06d9633404d01d1e0c67 Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Mon, 5 Dec 2011 15:47:10 +0000 Subject: [PATCH] LMS-2575 KeystoreBasedKeyPairProvider introduced SVN: 23880 --- .../dss/generic/server/ftp/FtpServer.java | 120 ++++++++++++++++-- .../generic/server/ftp/FtpServerConfig.java | 32 +++-- 2 files changed, 132 insertions(+), 20 deletions(-) diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java index b920d3eaa24..82c4bb10e83 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java @@ -16,15 +16,27 @@ package ch.systemsx.cisd.openbis.dss.generic.server.ftp; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Enumeration; import java.util.List; import java.util.Properties; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; + import org.apache.commons.io.IOUtils; import org.apache.ftpserver.ConnectionConfigFactory; import org.apache.ftpserver.DataConnectionConfigurationFactory; @@ -47,17 +59,19 @@ import org.apache.ftpserver.ssl.SslConfigurationFactory; import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication; import org.apache.log4j.Logger; import org.apache.sshd.SshServer; +import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.Session; import org.apache.sshd.common.Session.AttributeKey; +import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider; import org.apache.sshd.server.Command; import org.apache.sshd.server.PasswordAuthenticator; import org.apache.sshd.server.SshFile; -import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import org.apache.sshd.server.session.ServerSession; import org.apache.sshd.server.sftp.SftpSubsystem; import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; +import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; @@ -116,13 +130,11 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File operationLog.info(String.format(startingMessage, "S")); sshServer.start(); operationLog.info("SFTP server started."); - } else - { - server = creatFtpServer(); - operationLog.info(String.format(startingMessage, "")); - server.start(); - operationLog.info("FTP server started."); } + server = creatFtpServer(); + operationLog.info(String.format(startingMessage, "")); + server.start(); + operationLog.info("FTP server started."); } private org.apache.ftpserver.FtpServer creatFtpServer() @@ -187,9 +199,9 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File private SshServer createSftpServer() { SshServer s = SshServer.setUpDefaultServer(); - // TODO keystore based provider needed - s.setKeyPairProvider(new SimpleGeneratorHostKeyProvider()); - s.setPort(config.getPort()); + KeyPairProvider keyPairProvider = new KeystoreBasedKeyPairProvider(config, operationLog); + s.setKeyPairProvider(keyPairProvider); + s.setPort(config.getSftpPort()); s.setSubsystemFactories(creatSubsystemFactories()); s.setFileSystemFactory(this); s.setPasswordAuthenticator(new PasswordAuthenticator() @@ -423,4 +435,92 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File inputStreams.clear(); } } + + private static final class KeystoreBasedKeyPairProvider extends AbstractKeyPairProvider + { + private final KeyPair[] keyPairs; + + private KeystoreBasedKeyPairProvider(FtpServerConfig config, Logger operationLog) + { + File keyStoreFile = config.getKeyStore(); + String keyStorePassword = config.getKeyStorePassword(); + String keyPassword = config.getKeyPassword(); + KeyStore keystore = loadKeystore(keyStoreFile, keyStorePassword); + X509ExtendedKeyManager keyManager = getKeyManager(keystore, keyStorePassword, keyPassword); + List<KeyPair> list = new ArrayList<KeyPair>(); + try + { + Enumeration<String> aliases = keystore.aliases(); + while (aliases.hasMoreElements()) + { + String alias = aliases.nextElement(); + if (keystore.isKeyEntry(alias)) + { + Certificate certificate = keystore.getCertificate(alias); + PublicKey publicKey = certificate.getPublicKey(); + PrivateKey privateKey = keyManager.getPrivateKey(alias); + list.add(new KeyPair(publicKey, privateKey)); + } + } + keyPairs = list.toArray(new KeyPair[list.size()]); + operationLog.info(keyPairs.length + " key pairs loaded from keystore " + keyStoreFile); + } catch (Exception ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + + @Override + protected KeyPair[] loadKeys() + { + return keyPairs; + } + + private KeyStore loadKeystore(File keyStoreFile, String keyStorePassword) + { + InputStream stream = null; + try + { + KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); + stream = new FileInputStream(keyStoreFile); + keystore.load(stream, keyStorePassword.toCharArray()); + return keystore; + } catch (Exception e) + { + throw CheckedExceptionTunnel.wrapIfNecessary(e); + }finally{ + IOUtils.closeQuietly(stream); + } + } + + private X509ExtendedKeyManager getKeyManager(KeyStore keystore, String keyStorePassword, + String keyPassword) + { + try + { + String defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); + KeyManagerFactory factory = KeyManagerFactory.getInstance(defaultAlgorithm); + char[] password = (keyPassword == null ? keyStorePassword : keyPassword).toCharArray(); + factory.init(keystore, password); + KeyManager[] keyManagers = factory.getKeyManagers(); + if (keyManagers.length != 1) + { + throw new ConfigurationFailureException( + "Only one key manager expected instead of " + keyManagers.length + "."); + } + KeyManager keyManager = keyManagers[0]; + if (keyManager instanceof X509ExtendedKeyManager == false) + { + throw new ConfigurationFailureException("Key manager is not of type " + + X509ExtendedKeyManager.class.getSimpleName() + ": " + + keyManager.getClass().getName()); + } + return (X509ExtendedKeyManager) keyManager; + } catch (Exception ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + + } + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServerConfig.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServerConfig.java index 86a9a58015c..a89d6aa03c7 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServerConfig.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServerConfig.java @@ -43,7 +43,7 @@ public class FtpServerConfig final static String ENABLE_KEY = PREFIX + "enable"; - final static String SFTP_KEY = PREFIX + "sftp"; + final static String SFTP_PORT_KEY = PREFIX + "sftp-port"; final static String PORT_KEY = PREFIX + "port"; @@ -115,6 +115,8 @@ public class FtpServerConfig private boolean sftpMode; + private int sftpPort; + public FtpServerConfig(Properties props) { this.startServer = PropertyUtils.getBoolean(props, ENABLE_KEY, false); if (startServer) @@ -125,7 +127,8 @@ public class FtpServerConfig private void initializeProperties(Properties props) { - sftpMode = PropertyUtils.getBoolean(props, SFTP_KEY, false); + sftpPort = PropertyUtils.getInt(props, SFTP_PORT_KEY, 0); + sftpMode = sftpPort > 0; port = PropertyUtils.getPosInt(props, PORT_KEY, DEFAULT_PORT); useSSL = PropertyUtils.getBoolean(props, USE_SSL_KEY, DEFAULT_USE_SSL); if (useSSL) @@ -181,6 +184,11 @@ public class FtpServerConfig return sftpMode; } + public int getSftpPort() + { + return sftpPort; + } + public boolean isStartServer() { return startServer; @@ -246,20 +254,24 @@ public class FtpServerConfig */ public void logStartupInfo() { - operationLog.info("Ftp Server port: " + port); - operationLog.info("Ftp Server using SSL: " + useSSL); - operationLog.info("Ftp Server data set display template : " + dataSetDisplayTemplate); - operationLog.info("Ftp Server passive ports: " + passivePortsRange); - operationLog.info("Ftp Server enable active mode: " + activeModeEnabled); + operationLog.info("FTP Server port: " + port); + operationLog.info("FTP Server using SSL: " + useSSL); + operationLog.info("FTP Server passive ports: " + passivePortsRange); + operationLog.info("FTP Server enable active mode: " + activeModeEnabled); if (activeModeEnabled) { - operationLog.info("Ftp Server active mode port: " + activePort); + operationLog.info("FTP Server active mode port: " + activePort); + } + if (sftpMode) + { + operationLog.info("SFTP Server port: " + sftpPort); } + operationLog.info("SFTP/FTP Server data set display template : " + dataSetDisplayTemplate); for (Entry<String, String> subpathEntry : fileListSubPaths.entrySet()) { String message = - String.format("Ftp Server subpath configuration for data " + String.format("SFTP/FTP Server subpath configuration for data " + "set type '%s' : '%s'", subpathEntry.getKey(), subpathEntry.getValue()); operationLog.info(message); @@ -267,7 +279,7 @@ public class FtpServerConfig for (Entry<String, String> filterEntry : fileListFilters.entrySet()) { String message = - String.format("Ftp Server file filter configuration for data " + String.format("SFTP/FTP Server file filter configuration for data " + "set type '%s' : '%s'", filterEntry.getKey(), filterEntry.getValue()); operationLog.info(message); } -- GitLab