From 57806b92c980c00341253c5227b5047cd70d47b8 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 22 Nov 2016 14:38:27 -0500 Subject: [PATCH] INT-4171: Document Solution for FTPS Shared SSL JIRA: https://jira.spring.io/browse/INT-4171 Since the solution requires reflection on `sun` classes, document only. Also fix some PDF text overflows in (S)FTP. --- .../session/AbstractFtpSessionFactory.java | 2 +- .../FtpServerOutboundTests-context.xml | 4 +- src/reference/asciidoc/ftp.adoc | 73 ++++++++++++++++++- src/reference/asciidoc/sftp.adoc | 3 +- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/AbstractFtpSessionFactory.java b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/AbstractFtpSessionFactory.java index 1e8ddf8c32..76343c9546 100644 --- a/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/AbstractFtpSessionFactory.java +++ b/spring-integration-ftp/src/main/java/org/springframework/integration/ftp/session/AbstractFtpSessionFactory.java @@ -40,7 +40,7 @@ import org.springframework.util.Assert; */ public abstract class AbstractFtpSessionFactory implements SessionFactory { - private final Log logger = LogFactory.getLog(this.getClass()); + protected final Log logger = LogFactory.getLog(this.getClass()); // NOSONAR protected FTPClientConfig config; diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml index da284492a5..ff2b41f008 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/outbound/FtpServerOutboundTests-context.xml @@ -52,12 +52,12 @@ command="mget" expression="payload" command-options="-R" - filter="startDotTxtFilter" + filter="starDotTxtFilter" local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory" local-filename-generator-expression="#remoteFileName.replaceFirst('ftpSource', 'localTarget')" reply-channel="output"/> - + diff --git a/src/reference/asciidoc/ftp.adoc b/src/reference/asciidoc/ftp.adoc index 4cd3864274..a9aa7a958d 100644 --- a/src/reference/asciidoc/ftp.adoc +++ b/src/reference/asciidoc/ftp.adoc @@ -27,6 +27,8 @@ xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp [[ftp-session-factory]] === FTP Session Factory +==== Default Factories + IMPORTANT: Starting with version 3.0, sessions are no longer cached by default. See <>. @@ -121,6 +123,74 @@ public class AdvancedFtpSessionFactory extends DefaultFtpSessionFactory { } ---- +==== FTPS and Shared SSLSession + +When using FTP over SSL/TLS, some servers require the same `SSLSession` to be used on the control and data connections; this is to prevent "stealing" data connections; see https://scarybeastsecurity.blogspot.cz/2009/02/vsftpd-210-released.html[here for more information]. + +Currently, the Apache FTPSClient does not support this feature - see https://issues.apache.org/jira/browse/NET-408[NET-408]. + +The following solution, courtesy of http://stackoverflow.com/questions/32398754/how-to-connect-to-ftps-server-with-data-connection-using-same-tls-session[Stack Overflow], uses reflection on the `sun.security.ssl.SSLSessionContextImpl` so may not work on other JVMs. +The stack overflow answer was submitted in 2015 and the solution has been tested by the Spring Integration team recently on JDK 1.8.0_112. + +[source, java] +---- +@Bean +public DefaultFtpsSessionFactory sf() { + DefaultFtpsSessionFactory sf = new DefaultFtpsSessionFactory() { + + @Override + protected FTPSClient createClientInstance() { + return new SharedSSLFTPSClient(); + } + + }; + sf.setHost("..."); + sf.setPort(21); + sf.setUsername("..."); + sf.setPassword("..."); + sf.setNeedClientAuth(true); + return sf; +} + +private static final class SharedSSLFTPSClient extends FTPSClient { + + @Override + protected void _prepareDataSocket_(final Socket socket) throws IOException { + if (socket instanceof SSLSocket) { + // Control socket is SSL + final SSLSession session = ((SSLSocket) _socket_).getSession(); + final SSLSessionContext context = session.getSessionContext(); + context.setSessionCacheSize(0); // you might want to limit the cache + try { + final Field sessionHostPortCache = context.getClass() + .getDeclaredField("sessionHostPortCache"); + sessionHostPortCache.setAccessible(true); + final Object cache = sessionHostPortCache.get(context); + final Method method = cache.getClass().getDeclaredMethod("put", Object.class, + Object.class); + method.setAccessible(true); + String key = String.format("%s:%s", socket.getInetAddress().getHostName(), + String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT); + method.invoke(cache, key, session); + key = String.format("%s:%s", socket.getInetAddress().getHostAddress(), + String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT); + method.invoke(cache, key, session); + } + catch (NoSuchFieldException e) { + // Not running in expected JRE + logger.warn("No field sessionHostPortCache in SSLSessionContext", e); + } + catch (Exception e) { + // Not running in expected JRE + logger.warn(e.getMessage()); + } + } + + } + +} +---- + [[ftp-dsf]] === Delegating Session Factory @@ -804,7 +874,8 @@ This allows recursion for a simple pattern; examples follow: [source, xml] ---- - + diff --git a/src/reference/asciidoc/sftp.adoc b/src/reference/asciidoc/sftp.adoc index 2508982699..39f6e0e0d6 100644 --- a/src/reference/asciidoc/sftp.adoc +++ b/src/reference/asciidoc/sftp.adoc @@ -893,7 +893,8 @@ This allows recursion for a simple pattern; examples follow: [source, xml] ---- - +