Skip to content

Instantly share code, notes, and snippets.

@riyaz-ali
Created February 20, 2018 05:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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);
}
}
}
}
@oliver108
Copy link

This patch made it work for me! Thank you.

@anthonyblanchettepotvin

I'm trying to implement this bit of code for an Android app in Android Studio, but I get this error : java.lang.NoSuchFieldException: No field sessionHostPortCache in class Lcom/android/org/conscrypt/ClientSessionContext; (declaration of 'com.android.org.conscrypt.ClientSessionContext' appears in /system/framework/conscrypt.jar) at java.lang.Class.getDeclaredField(Native Method). I've been searching all day to make it work, but I just can't. Thank you !

@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