Commons Net
  1. Commons Net
  2. NET-426

FTPS: Hook to customize _openDataConnection_ SSLSocket before startHandshake() is called

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.0.1
    • Fix Version/s: 3.1, 3.2
    • Component/s: FTP
    • Labels:
      None

      Description

      Currently in FTPSClient class, there is protected openDataConnection method, which create SSLSocket for data connection. But there is no hook to customize the SSLSocket before startHandshake is called.

      I need to know the remote host ip and port, which i can get for socket, and do custom setup to try to reuse SSL sessions from control connection socket. Since the socket factory uses createSocket() method, I can't just use custom socket factory since I don't know the host and port. I can't just override the openDataConnection() method in my class since that will call the startHandshake().

      So it would be nice if you can provide hook, much like connectAction(), but for data connection before handshake is started. You can pass the new data socket as argument to this hook method so one can get remote host and port information.

      1. FTPSClient.patch
        2 kB
        Ketan
      2. FTPSClient.patch
        0.8 kB
        Ketan

        Issue Links

          Activity

          Hide
          Ketan added a comment -

          patch which adds prepareDataSocket(Socket socket) method to FTPSClient.java

          Maybe this should be in FTPClient instead of FTPSClient.java

          Show
          Ketan added a comment - patch which adds prepareDataSocket (Socket socket) method to FTPSClient.java Maybe this should be in FTPClient instead of FTPSClient.java
          Hide
          David Kocher added a comment -

          Do you have a workaround for NET-408 with this?

          Show
          David Kocher added a comment - Do you have a workaround for NET-408 with this?
          Hide
          Ketan added a comment -

          Noting that can be used in production code...but for testing I am thinking of using reflection to add the SSLSession from control channel socket to JSSE provider's cache based on host and port. If the SSLSession is added before handshake then session is resumed.

          I did simple test based on Sun and IBM JSSE providers and it seems to work. Again not idea solution but gets around for my needs since I can't change the VSFTPD config which requires ssl resume on data channel.

          Show
          Ketan added a comment - Noting that can be used in production code...but for testing I am thinking of using reflection to add the SSLSession from control channel socket to JSSE provider's cache based on host and port. If the SSLSession is added before handshake then session is resumed. I did simple test based on Sun and IBM JSSE providers and it seems to work. Again not idea solution but gets around for my needs since I can't change the VSFTPD config which requires ssl resume on data channel.
          Hide
          David Kocher added a comment -

          I would be interested to see this workaround using reflection if you can share.

          Show
          David Kocher added a comment - I would be interested to see this workaround using reflection if you can share.
          Hide
          Ketan added a comment - - edited

          Here is code snippet I was playing with. I had this executed before data connection handshake starting. Note this is for SunJSSE provider since I had Sun's JVM installed:

          
          	SSLSocket sslControlSocket = (SSLSocket) controlConnectionSocket;
          	String host = "host.used.to.connect.to.data.socket";
          	int port = dataPort; // dataSocket.getPort();
          	try {
          		SSLSession sess = sslControlSocket.getSession();
          		SSLSessionContext sessions = sess.getSessionContext();
          		// SunJSSE 1.6 specific code
          		Field cache = sessions.getClass().getDeclaredField(
          			"sessionHostPortCache");
          		cache.setAccessible(true);
          		Object c = cache.get(sessions);
          		String key = (host + ":" + String.valueOf(port))
          			.toLowerCase();
          		// Class<?> cc = Class.forName("sun.security.util.Cache");
          		Class<?> cc = c.getClass();
          		cc.getDeclaredMethod("put", Object.class, Object.class).invoke(
          				c, key, sess);
          	} catch (Exception e) {
          		// TODO Auto-generated catch block
          		e.printStackTrace();
          	}
          
          Show
          Ketan added a comment - - edited Here is code snippet I was playing with. I had this executed before data connection handshake starting. Note this is for SunJSSE provider since I had Sun's JVM installed: SSLSocket sslControlSocket = (SSLSocket) controlConnectionSocket; String host = "host.used.to.connect.to.data.socket" ; int port = dataPort; // dataSocket.getPort(); try { SSLSession sess = sslControlSocket.getSession(); SSLSessionContext sessions = sess.getSessionContext(); // SunJSSE 1.6 specific code Field cache = sessions.getClass().getDeclaredField( "sessionHostPortCache" ); cache.setAccessible( true ); Object c = cache.get(sessions); String key = (host + ":" + String .valueOf(port)) .toLowerCase(); // Class <?> cc = Class .forName( "sun.security.util.Cache" ); Class <?> cc = c.getClass(); cc.getDeclaredMethod( "put" , Object .class, Object .class).invoke( c, key, sess); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
          Hide
          David Kocher added a comment -

          Thanks for the sample. Will give it a try as well. I suggest one could override #verifyRemote to do the injection in the cache.

          Show
          David Kocher added a comment - Thanks for the sample. Will give it a try as well. I suggest one could override #verifyRemote to do the injection in the cache.
          Hide
          Ketan added a comment -

          Yes, I am using verifyRemote right now as workaround.

          Show
          Ketan added a comment - Yes, I am using verifyRemote right now as workaround.
          Hide
          Ketan added a comment -

          the prepareDataSocket method doesn't work for retrieving and storing file since these methods call org.apache.commons.net.ftp.FTPClient.openDataConnection(String, String) method, which does not call prepareDataSocket method.

          Can we get this fixed? Without this you still get errors.

          Here are the methods that are calling org.apache.commons.net.ftp.FTPClient.openDataConnection(String, String)

          org.apache.commons.net.ftp - commons-net.jar
          openDataConnection(int, String)
          _retrieveFile(String, String, OutputStream)
          _retrieveFileStream(String, String)
          _storeFile(String, String, InputStream)
          _storeFileStream(String, String)

          Show
          Ketan added a comment - the prepareDataSocket method doesn't work for retrieving and storing file since these methods call org.apache.commons.net.ftp.FTPClient. openDataConnection (String, String) method, which does not call prepareDataSocket method. Can we get this fixed? Without this you still get errors. Here are the methods that are calling org.apache.commons.net.ftp.FTPClient. openDataConnection (String, String) org.apache.commons.net.ftp - commons-net.jar openDataConnection (int, String) _retrieveFile(String, String, OutputStream) _retrieveFileStream(String, String) _storeFile(String, String, InputStream) _storeFileStream(String, String)
          Hide
          Sebb added a comment -

          Can you provide a new patch?

          Show
          Sebb added a comment - Can you provide a new patch?
          Hide
          Ketan added a comment -

          New patch to make FTPSClient work with retrieve and send command.

          Show
          Ketan added a comment - New patch to make FTPSClient work with retrieve and send command.
          Hide
          Sebb added a comment -

          Thanks for the patch, implemented in:

          URL: http://svn.apache.org/viewvc?rev=1374495&view=rev
          Log:
          NET-426 FTPS: Hook to customize openDataConnection SSLSocket before startHandshake() is called
          Properly interface with FTPClient.openDataConnection(String, String)

          Modified:
          commons/proper/net/trunk/src/changes/changes.xml
          commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPSClient.java

          I changed the implementation of openDataConnection(int command, String arg) to directly call openDataConnection(String command, String arg) in the current class, as it seemed clearer than bouncing via the parent.

          Show
          Sebb added a comment - Thanks for the patch, implemented in: URL: http://svn.apache.org/viewvc?rev=1374495&view=rev Log: NET-426 FTPS: Hook to customize openDataConnection SSLSocket before startHandshake() is called Properly interface with FTPClient.openDataConnection(String, String) Modified: commons/proper/net/trunk/src/changes/changes.xml commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPSClient.java I changed the implementation of openDataConnection (int command, String arg) to directly call openDataConnection (String command, String arg) in the current class, as it seemed clearer than bouncing via the parent.

            People

            • Assignee:
              Unassigned
              Reporter:
              Ketan
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 1h
                1h
                Remaining:
                Remaining Estimate - 1h
                1h
                Logged:
                Time Spent - Not Specified
                Not Specified

                  Development