我正在尝试连接到几个Linux FTPS服务器(一个是Red Hat 5.11,另一个是Red Hat 6.8),并使用org.apache.commons将文件从Linux FTPS服务器下载到我的本地Windows Server。 .net.ftp.FTPSClient。
我正尝试以两种不同的方式使用Apache Commons API进行连接。
1。使用第一种方法,我可以连接到两个Linux主机,然后将测试文件testftps.txt从两个远程Linux服务器成功下载到我的本地Windows服务器。我的第一个连接方法是connectToFtp()
,如下面的代码所示。它使用位于我的Eclipse Java项目构建路径中定义的路径中的certificate.jks。该文件具有一个加密密码,用于保护JKS中的私钥,并且帐户ID也与JKS相关联。
我在Linux主机hostname1和hostname2上都创建了/tmp/testftps.txt
文件。我只是将host变量更改为指向hostname1或hostname2,它使用下面显示的downloadFiles()函数代码将文件testftps.txt成功地从相应的主机下载到了本地Windows服务器。
代码:
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和加密密码,相同的Apache Commons API,并且试图将相同的testftps.txt从hostname1和hostname2提取到本地Windows VM。对于第二种方法,我的连接机制connectToFtpUsing_TrustStoreKeystore()
稍有不同,如下所示。尽管它使用相同的certificate.jks,但它获取Truststore,Keystore,使用keyManagetFactory,TrustManagerFactory SSLContext等。我仍在使用org.apache.commons.net.ftp.FTPSClient对象,但是使用此方法,连接对于远程Linux FTPS服务器主机名1,我可以下载很好,但是对于远程Linux FTPS服务器主机名2和其他一些主机,程序给出了Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
,如下所示。
如果您能查看下面的连接方法并将其与以前的方法进行比较,我将不胜感激,请让我知道为什么上面的方法connectToFtp()
可以从所有Linux FTPS Server成功下载文件,而下面的{{1 }}仅成功连接到少数FTPS服务器,并且即使两个程序使用相同的CERTIFICATE.JKS文件和相同的Apache Commons FTPSClient API,也无法通过connectToFtpUsing_TrustStoreKeystore()
连接到许多服务器。如何解决?
No trusted certificate found ERROR
使用第二种方法得到的错误的堆栈跟踪:
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;
}