Передача файлов Android по явному TLS

Я пишу этот вопрос после того, как снова и снова пытался заставить его работать, но безуспешно. Я пытаюсь реализовать передачу файлов FTP в Android, используя библиотеку Apache Commons. Связь должна осуществляться через явную аутентификацию TLS. Я могу успешно войти в систему, подключиться к серверу и вывести список файлов, но всякий раз, когда я пытаюсь получить или сохранить файл, я всегда получаю исключение тайм-аута, также с очень большим значением тайм-аута, даже для текстового файла 2Kb. Это мой код:

 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 );

Я не могу найти ни одного примера этой конкретной ситуации, все примеры там о нормальном FTP-соединении, которое я могу достичь без проблем. У кого-нибудь из вас была похожая проблема? Мне действительно нужно решение, я должен доставить проект как можно скорее.

Благодарю.

3 ответа

Решение

Я наконец-то нашел решение, решение состояло в том, чтобы настроить диспетчер доверия на прием всех сертификатов. Вот код для тех, кто испытывает подобные проблемы, возможно, он может быть улучшен и / или оптимизирован, но он работает:

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) {
    }
}

getAcceptAllTrustManager() означает, что никакие проверки не сделаны относительно действительности сертификатов. Может быть хорошо, если у вас есть полный контроль над вовлеченными сайтами. См.: Доверие всем сертификатам с использованием HttpClient через HTTPS

Вы можете добавить доверенный менеджер библиотеки, который принимает все сертификаты, а не создает их.

FTPSClient mFtps = new FTPSClient();
mFtps.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
Другие вопросы по тегам