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.
This commit is contained in:
committed by
Artem Bilan
parent
d96b8e0c85
commit
57806b92c9
@@ -40,7 +40,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>>.
|
||||
|
||||
@@ -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]
|
||||
----
|
||||
<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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user