Я пытаюсь подключиться к нескольким серверам 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