Skip to content

Instantly share code, notes, and snippets.

@riyaz-ali
Created February 20, 2018 05:09
Show Gist options
  • Save riyaz-ali/48fb486f51c258b4e92c2d2be30c35c4 to your computer and use it in GitHub Desktop.
Save riyaz-ali/48fb486f51c258b4e92c2d2be30c35c4 to your computer and use it in GitHub Desktop.
Patching TLS session resumption on Apache Commons Net FTPSClient
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPSClient;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
/**
* FTPUploadTest class to test FTPS upload using Apache commons net library
*/
public class FTPUploadTest {
public static void main(String[] args) throws IOException {
// file to upload
// create a test.jpeg file in your current directory
Path path = FileSystems.getDefault().getPath("test.jpeg").toAbsolutePath();
// we will be using https://dlptest.com/ftp-test/ FTP-server to test uploads
// thanks guys :D
FTPSClient client = new PatchedFTPSClient();
try {
// to debug
client.addProtocolCommandListener(new PrintCommandListener(System.out));
// connect to the server
client.connect("ftp.dlptest.com", 21);
// then login
client.login("dlpuser@dlptest.com", "eiTqR7EMZD5zy7M");
// exec PROT P
client.execPBSZ(0);
client.execPROT("P");
// enter passive mode
client.enterLocalPassiveMode();
// upload
client.setFileType(FTP.BINARY_FILE_TYPE);
if (client.storeUniqueFile(new FileInputStream(path.toFile()))) {
System.out.println("File Saved!");
} else {
System.out.println("Failed to save file");
}
// list
for (FTPFile file : client.listFiles("/")) {
System.out.println(file.toFormattedString());
}
} finally {
client.disconnect();
}
}
}
import org.apache.commons.net.ftp.FTPSClient;
import javax.net.ssl.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Locale;
/**
* FTPSClient to patch TLS session resumption support in Apache FTPSClient
* see also: http://eng.wealthfront.com/2016/06/10/connecting-to-an-ftps-server-with-ssl-session-reuse-in-java-7-and-8/
* see also: https://gist.github.com/lukehansen/cd1931426d1e432d0993005f9976e6fb
*/
public class PatchedFTPSClient extends FTPSClient {
@Override protected void _prepareDataSocket_(Socket socket) throws IOException {
if (socket instanceof SSLSocket) {
final SSLSession session = ((SSLSocket) _socket_).getSession();
final SSLSessionContext context = session.getSessionContext();
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
final Method getHostMethod = socket.getClass().getDeclaredMethod("getHost");
getHostMethod.setAccessible(true);
Object host = getHostMethod.invoke(socket);
final String key = String.format("%s:%s", host, String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
putMethod.invoke(cache, key, session);
} catch (Exception e) {
throw new IOException(e);
}
}
}
}
@lolo9121993
Copy link

Hi riyaz-ali,

After tearing my hair out during hours to solve this problem with my filezilla server and my Java Apache commons FTPSClient that was every time resulting with the "TLS session of data connection not resumed." when trying to call ftpsClient.listFiles (login was working fine),
Your PatchedFTPSClient class definitely solved the problem !!!

Thanks a lot for your help.
Regards,
Lolo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment