androidftpftp-clientapache-commons-netftps

android ftp file tranfer over explicit TLS


I'm posting this question after have tried over and over again to get it working, with no success. I trying to implement a FTP file transfer in android, using apache commons library. The communication must be done through explicit TLS authentication. I can successfully login, connect to the server and list files, but whenever i try to get or store a file, I always get a timeout exception, also with very large timeout value, even for a 2Kb txt file. This is my code:

 FTPSClient ftpClient = new FTPSClient("TLS", false);
    ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
KeyManagerFactory kmf = getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(null, null);
KeyManager km = kmf.getKeyManagers()[0];
ftpClient.setKeyManager(km);
ftpClient.setBufferSize(1024 * 1024);
ftpClient.setConnectTimeout(900000);
ftpClient.connect(InetAddress.getByName("server ip address"), 990);
// Set protection buffer size
ftpClient.execPBSZ(0);
// // Set data channel protection to private
ftpClient.execPROT("P");
ftpClient.login("user", "password");
ftpClient.changeWorkingDirectory("/");
ftpClient.setSoTimeout(900000);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
buffIn = new BufferedInputStream(new FileInputStream(file.getAbsolutePath()));

//this works
FTPFile[] files = ftpClient.listFiles();
final OutputStream os = new FileOutputStream(finalStoragePath + "/OK.txt");
//this returns immediatly with false result
boolean getResult=ftpClient.retrieveFile("OK.txt", os);
//this always fail for timeout
boolean result = ftpClient.storeFile( picture.getName(), buffIn );

I can't find any example of this specific situation, all examples out there, are about normal FTP connection, which I can achieve with no problems. Did any of you had a similar problem? I really need a solution, I have to deliver the project ASAP.

thanks.


Solution

  • I have finally found a solution, the solution was to set the trust manager to accept all certificates. here is the code for those who are experiencing similar problems, maby it can be improved and/or optimized, but it works:

    FTPSClient ftpClient = new FTPSClient("TLS", false);
    try {
        TrustManager[] trustManager = new TrustManager[] { new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
    
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
    
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        } };
    
        ftpClient.setTrustManager(trustManager[0]);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(null, null);
        KeyManager km = kmf.getKeyManagers()[0];
        ftpClient.setKeyManager(km);
        ftpClient.setBufferSize(1024 * 1024);
        ftpClient.setConnectTimeout(100000);
        ftpClient.connect(InetAddress.getByName("ipaddress"), 990);
        ftpClient.setSoTimeout(100000);
    
        if (ftpClient.login("user", "password")) {
            ftpClient.execPBSZ(0);
            ftpClient.execPROT("P");
            ftpClient.changeWorkingDirectory("/");
            // 250 = directory succesfully changed
            if (ftpClient.getReplyString().contains("250")) {
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                ftpClient.enterLocalPassiveMode();
                BufferedInputStream buffIn = null;
    
                for (File picture : pictures) {
                    buffIn = new BufferedInputStream(new FileInputStream(picture.getAbsolutePath()));
                    boolean result = ftpClient.storeFile(picture.getName(), buffIn);
                    try {
                        buffIn.close();
                    } catch (Exception e) {
                    }
                    if (result)
                        picture.delete();
                }
            }
        }
    
    } catch (SocketException e) {
        Log.e("APPTAG", e.getStackTrace().toString());
    } catch (UnknownHostException e) {
        Log.e("APPTAG", e.getStackTrace().toString());
    } catch (IOException e) {
        Log.e("APPTAG", e.getStackTrace().toString());
    } catch (Exception e) {
        Log.e("APPTAG", e.getStackTrace().toString());
    } finally {
        try {
            ftpClient.logout();
        } catch (Exception e2) {
        }
        try {
            ftpClient.disconnect();
        } catch (Exception e2) {
        }
    }