Ошибка Trusted Cert при подключении к серверу Linux FTPS с использованием API Apache Commons - PullRequest
0 голосов
/ 23 марта 2019

Я пытаюсь подключиться к нескольким серверам Linux FTPS (один - Red Hat 5.11, а другой - Red Hat 6.8) и загружать файлы с сервера Linux FTPS на мой локальный сервер Windows с помощью org.apache.commons .net.ftp.FTPSClient.

Я пытаюсь подключиться с помощью Apache Commons API двумя разными способами.

1. Используя первый способ, я могу подключиться к обоим хостам Linux и успешно загрузить тестовый файл testftps.txt с обоих удаленных серверов Linux на мой локальный сервер Windows. Мой метод подключения для первого - connectToFtp(), как показано в приведенном ниже коде. Он использует файл certificate.jks, который находится в пути, заданном в моем пути сборки проекта Eclipse Java. Файл имеет пароль шифрования, который используется для защиты закрытого ключа в JKS, и идентификатор учетной записи также связан с JKS.

Я создал /tmp/testftps.txt файлов на обоих хостах Linux hostname1 и hostname2. Я просто изменил переменную host, чтобы она указала либо на hostname1, либо hostname2, и он успешно загружает файл testftps.txt с соответствующего хоста на мой локальный сервер Windows, используя код функции downloadFiles (), показанный ниже.

Код:

private void connectToFtp() throws Exception {
    try {
        ftpClient = new FTPSClient("SSL");
        String host = "hostname1";
        String user = "accountid";
        String password = "";
        String jksFileName = "certificate.jks";
        String jksFilePassword = "encryptionpassword";

        File jksFile = new File(ClassLoader.getSystemResource(jksFileName).toURI());
        String jksFilename = jksFile.getName();
        ftpClient.setKeyManager(KeyManagerUtils.createClientKeyManager(jksFile, jksFilePassword));
        ftpClient.connect(host, 2121);
        ftpClient.enterLocalPassiveMode();
        ftpClient.login(user, password);
        ftpClient.execPBSZ(0);
        ftpClient.execPROT("P");
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    } catch(Exception e) {
        System.out.println("Failed to connect: Exception=" + e);
        throw e;
    }
}

public void downloadFiles() throws Exception {
    try {
        String specifiedRemoteFileName = "testftps.txt";
        File localFile = new File(localFilePath + "/" + specifiedRemoteFileName);
        OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localFile));
        String remoteFile = remoteFilePath + "/" + specifiedRemoteFileName;
        boolean downloaded = ftpClient.retrieveFile(remoteFile, outputStream);
        if (downloaded) {
            System.out.println("File has been downloaded successfully to local destination " + localFile.getAbsolutePath());
        } else {
            System.out.println("File " + remoteFile + " was not downloaded from remote server.");
        }
        outputStream.close();
    }
    catch(Exception e) {
        System.out.println("Error during download...");
        throw e;
    }
}

2. Для второй программы я использую тот же файл certificate.jks, accountid и пароль шифрования, тот же API Apache Commons и пытаюсь получить тот же файл testftps.txt из hostname1 и hostname2 в мою локальную виртуальную машину Windows. Для второго метода мой механизм подключения connectToFtpUsing_TrustStoreKeystore() немного отличается, как показано ниже. Хотя он использует тот же Certificate.jks, он получает Truststore, Keystore, использует keyManagetFactory, TrustManagerFactory SSLContext и т. Д. Я все еще использую объект org.apache.commons.net.ftp.FTPSClient, однако с этим методом соединение работает нормально для Удаленный сервер Linux FTPS hostname1, и я могу загрузить нормально, но для удаленного сервера Linux FTPS hostname2 и нескольких других хостов программа выдает Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found, как показано ниже.

Буду признателен, если вы посмотрите на метод подключения ниже и сравните его с предыдущим методом, дайте мне знать, почему вышеуказанный метод connectToFtp() успешно загружает файлы со всех серверов Linux FTPS, тогда как ниже connectToFtpUsing_TrustStoreKeystore() подключается к только несколько серверов FTPS успешно и не удается подключиться ко многим серверам с No trusted certificate found ERROR, хотя обе программы используют один и тот же файл CERTIFICATE.JKS и один и тот же API-интерфейс Apache Commons FTPSClient. Как это можно исправить?

    try {
        ftpClient = new FTPSClient("TLS", Boolean.FALSE);
        KeyStore keyStore = getKeyStore();
        KeyStore trustStore = getTrustStore(keyStore);
        keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(keyStore, "encryptionpassword".toCharArray());
        trustManagerFactory.init(trustStore);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
        FTPSSocketFactory socketFactory = getSocketFactory(sslContext);
        ftpClient.setRemoteVerificationEnabled(false);
        ftpClient.setSocketFactory(socketFactory);
        ftpClient.setNeedClientAuth(false);
        ftpClient.setBufferSize(0);
        ftpClient.setControlEncoding("UTF-8");
        ftpClient.setKeyManager(keyManagerFactory.getKeyManagers()[0]);
        ftpClient.setTrustManager(trustManagerFactory.getTrustManagers()[0]);
        ftpClient.connect("hostname", Integer.parseInt("2121"));
        ftpClient.execPBSZ(0);
        ftpClient.execPROT("P");
        ftpClient.login("accountid", "encryptionpassword");
        ftpClient.enterLocalPassiveMode();
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    } catch(Exception e) {
        System.out.println("Failed to connect using Trustore keystore" + e);
        throw e;
    }
}

private static KeyStore getKeyStore() throws Exception {
    KeyStore keyStore = KeyStore.getInstance("JKS");
    InputStream inputStream = new FileInputStream(new File("C:\\blah\\blah\\certificate.jks"));
    keyStore.load(inputStream, "encryptionpassword".toCharArray());
    return keyStore;
}

private static KeyStore getTrustStore(KeyStore keyStore) throws Exception {
    KeyStore trustStore = KeyStore.getInstance("JKS");
    trustStore.load(null);
    for (Enumeration < String > t = keyStore.aliases(); t.hasMoreElements();) {
        String alias = t.nextElement();
        if (keyStore.isKeyEntry(alias)) {
            Certificate[] keyStore_certificate = keyStore.getCertificateChain(alias);
            X509Certificate x5091 = (X509Certificate) keyStore_certificate[1];
            trustStore.setCertificateEntry(x5091.getSubjectDN().toString(), x5091);
        }
    }
    return trustStore;
}

private static FTPSSocketFactory getSocketFactory(SSLContext sslContext) throws Exception {
    FTPSSocketFactory socketFactory = new FTPSSocketFactory(sslContext) {@Override
        public Socket createSocket() throws IOException {
            return new Socket();
        }
    };
    return socketFactory;
}

Стековая трассировка ошибки, которую я получаю вторым способом:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)Failed to connect using Trustore keystorejavax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found

    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
    at org.apache.commons.net.ftp.FTPSClient.sslNegotiation(FTPSClient.java:259)
    at org.apache.commons.net.ftp.FTPSClient._connectAction_(FTPSClient.java:205)
    at org.apache.commons.net.SocketClient.connect(SocketClient.java:169)
    at org.apache.commons.net.SocketClient.connect(SocketClient.java:189)
    at ftps.apache.FTPSUsingApacheComm.connectToFtpUsing_TrustStoreKeystore(FTPSUsingApacheComm.java:160)
    at ftps.apache.FTPSUsingApacheComm.<init>(FTPSUsingApacheComm.java:132)
    at ftps.apache.FTPSUsingApacheCommMain.main(FTPSUsingApacheCommMain.java:27)
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
    at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:330)
    at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:110)
    at sun.security.validator.Validator.validate(Validator.java:218)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
    ... 14 more
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...