Skip to content

Commit

Permalink
INT-4171: Document Solution for FTPS Shared SSL
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
garyrussell authored and artembilan committed Nov 26, 2016
1 parent d96b8e0 commit 57806b9
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
*/
public abstract class AbstractFtpSessionFactory<T extends FTPClient> implements SessionFactory<FTPFile> {

private final Log logger = LogFactory.getLog(this.getClass());
protected final Log logger = LogFactory.getLog(this.getClass()); // NOSONAR

protected FTPClientConfig config;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"/>

<bean id="startDotTxtFilter" class="org.springframework.integration.ftp.filters.FtpSimplePatternFileListFilter">
<bean id="starDotTxtFilter" class="org.springframework.integration.ftp.filters.FtpSimplePatternFileListFilter">
<constructor-arg value="*.txt" />
<property name="alwaysAcceptDirectories" value="true" />
</bean>
Expand Down
73 changes: 72 additions & 1 deletion src/reference/asciidoc/ftp.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<ftp-session-caching>>.

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -804,7 +874,8 @@ This allows recursion for a simple pattern; examples follow:

[source, xml]
----
<bean id="startDotTxtFilter" class="org.springframework.integration.ftp.filters.FtpSimplePatternFileListFilter">
<bean id="starDotTxtFilter"
class="org.springframework.integration.ftp.filters.FtpSimplePatternFileListFilter">
<constructor-arg value="*.txt" />
<property name="alwaysAcceptDirectories" value="true" />
</bean>
Expand Down
3 changes: 2 additions & 1 deletion src/reference/asciidoc/sftp.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,8 @@ This allows recursion for a simple pattern; examples follow:

[source, xml]
----
<bean id="startDotTxtFilter" class="org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter">
<bean id="starDotTxtFilter"
class="org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter">
<constructor-arg value="*.txt" />
<property name="alwaysAcceptDirectories" value="true" />
</bean>
Expand Down

0 comments on commit 57806b9

Please sign in to comment.