0

I am trying to connect to FTP that requires 'Explicit FTP over TLS' and upload a file.

I am trying to do it from my local machine which uses Java version 8 and commons net FTP version 3.6

Below is the code which I use

          try {

              FTPSClient ftpClient = new FTPSClient();


              ftpClient.setDataTimeout(300); 
              ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
              ftpClient.setAuthValue("TLS");
              ftpClient.connect(server, port);
              int reply = ftpClient.getReplyCode();


              if (FTPReply.isPositiveCompletion(reply)) {
                  ftpClient.execAUTH("TLS"); //SSL


                // Login
                if (ftpClient.login(user, pass)) {

                  // Set protection buffer size
                  ftpClient.execPBSZ(0);
                  // Set data channel protection to private
                  ftpClient.execPROT("P");
                  // Enter local passive mode
                  ftpClient.enterLocalPassiveMode();
                  ftpClient.changeWorkingDirectory("/");
                  ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
              File firstLocalFile = new File(outputFileNameCSV);
                              String firstRemoteFile = csvFileNameOut;
                  InputStream inputStream = new FileInputStream(firstLocalFile);

                  // Store file on host
                  boolean done = ftpClient.storeFile(firstRemoteFile, inputStream);
              inputStream.close();
              if (done) 
              {
                System.out.println("The file is uploaded successfully.");
              }

              // Logout
              ftpClient.logout();

                } else {
                  System.out.println("FTP login failed");
                }

                // Disconnect
                ftpClient.disconnect();

              } else {
                System.out.println("FTP connect to host failed");
              }
            } catch (IOException ioe) {
              System.out.println("FTP client received network error "+ioe);
            }

Below is the log I get from Java CommandListener

220-FileZilla Server 0.9.60 beta
220-written by Tim Kosse (tim.kosse@filezilla-project.org)
220 Please visit https://filezilla-project.org/
AUTH TLS
234 Using authentication type TLS
AUTH TLS
534 Authentication type already set to TLS
FTP login screen
USER test
331 Password required for test
PASS pass
230 Logged on
PBSZ 0
200 PBSZ=0
PROT P
200 Protection level set to P
CWD /
250 CWD successful. "/" is current directory.
TYPE I
200 Type set to I
PASV
227 Entering Passive Mode ()
STOR file.csv
150 Opening data channel for file upload to server of "/file.csv"
FTP client received network error javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Below is the log when I try to connect using FileZilla. It is connecting fine and I can transfer the files.

But when I try using Java, it isn't transferring

Response:   220-FileZilla Server 0.9.60 beta
Response:   220-written by Tim Kosse (tim.kosse@filezilla-project.org)
Response:   220 Please visit https://filezilla-project.org/
Command:    AUTH TLS
Response:   234 Using authentication type TLS
Status: Initializing TLS...
Status: Verifying certificate...
Command:    USER test
Status: TLS/SSL connection established.
Response:   331 Password required for test
Command:    PASS pass
Response:   230 Logged on
Command:    PBSZ 0
Response:   200 PBSZ=0
Command:    PROT P
Response:   200 Protection level set to P
Status: Connected
Status: Starting upload of file.csv
Command:    CWD /
Response:   250 CWD successful. "/" is current directory.
Command:    TYPE I
Response:   200 Type set to I
Command:    PASV
Response:   227 Entering Passive Mode ()
Command:    STOR file.csv
Response:   150 Opening data channel for file upload to server of "/file.csv"
Response:   226 Successfully transferred "/file.csv"
Status: File transfer successful, transferred 12,252 bytes in 1 second

Could you all please help?

Kind regards Jon

Louie
  • 1
  • 1
  • 8
  • Put the upload process into its own try/catch-block, in order to continue with the session with logout, etc. Maybe the `PrintCommandListener` can provide more informations coming from the server. I assume that SSL session resume is not happening so there should be some message from the server. Of course it depends on the server if an actual message is returned but it should be worth a try. – Lothar Feb 27 '18 at 17:01
  • @Lothar Yes it looks like resume is not happening. I am getting 450 TLS session of data connection has not resumed or the session does not match the control connection. Do you know how to resolve this please? – Louie Apr 03 '18 at 12:22
  • I'll post an answer concerning this – Lothar Apr 03 '18 at 15:17

1 Answers1

0

Modern FTP servers expect the data channel to be opened by using TLS session resume. Java is capable of doing this but only for connections to the same IP and port. Because the data channel of an FTP session uses a different port the mechanism fails, so you need to force the JVM to do that and includes quite heavy fiddling with the interns of java classes using reflection.

You're using the Apache FTPSClient, so you might check if a more recent version of it already does that for you but if it's still not done, you might do it yourself as it is described in a Blog post on Wealthfront.

The hack (I still fail it to call it differently) works well with clients but there is some significant additional work to be done if you want to do this on a server side (i.e. if you want to implement you own FTP server). Your question doesn't look like it, so I spare this part in this answer.

Lothar
  • 5,323
  • 1
  • 11
  • 27