zio-ftp icon indicating copy to clipboard operation
zio-ftp copied to clipboard

Ability to plugin custom clients

Open lmlynik opened this issue 1 year ago • 1 comments

Using Implicit FTP over TLS sometimes requires various "hackery". i.e. apache-commons-net doesn't manage ssl session reuse which might be needed.

I had to create


import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Locale;

import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;

import org.apache.commons.net.ftp.FTPSClient;

public class SSLSessionReuseFTPSClient extends FTPSClient {

    public SSLSessionReuseFTPSClient(String protocol, boolean isImplicit) {
        super(protocol, isImplicit);
    }

    @Override
    protected void _prepareDataSocket_(Socket socket) throws IOException {
        if (socket instanceof SSLSocket) {
            // Control socket is SSL
            final SSLSession session = ((SSLSocket)_socket_).getSession();
            if (session.isValid()) {
                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);
                    Method getHostMethod;
                    try {
                        getHostMethod = socket.getClass().getMethod("getPeerHost");
                    }
                    catch (NoSuchMethodException e) {
                        // Running in IKVM
                        getHostMethod = socket.getClass().getDeclaredMethod("getHost");
                    }
                    getHostMethod.setAccessible(true);
                    Object peerHost = getHostMethod.invoke(socket);
                    InetAddress iAddr = socket.getInetAddress();
                    int port = socket.getPort();
                    putMethod.invoke(cache, String.format("%s:%s", peerHost, port).toLowerCase(Locale.ROOT), session);
                    putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostName(), port).toLowerCase(Locale.ROOT), session);
                    putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostAddress(), port).toLowerCase(Locale.ROOT), session);
                }
                catch (Exception e) {
                    throw new IOException(e);
                }
            }
            else {
                throw new IOException("Invalid SSL Session");
            }
        }
    }
}

To "plugin" the socket reuse. Currently zio-ftp doesn't allow custom clients, so library cannot be used in these situations.

Another issue, for my use-case I also had to

          System.setProperty("jdk.tls.client.enableSessionTicketExtension", "false")
          System.setProperty("jdk.tls.useExtendedMasterSecret", "false")

albeit not sure if this can be covered by library.

lmlynik avatar Aug 07 '23 16:08 lmlynik

@lmlynik please tell me if it helps the new constructor ?

https://github.com/zio/zio-ftp/pull/357

regis-leray avatar Aug 07 '23 20:08 regis-leray