Мы хотим загрузить файл из SFTP, используя Apache Commons VFS за прокси-сервером. Наше Java-приложение должно подключаться к SFTP-серверу через прокси-сервер SOCKS5. Команда сети проверила настройки прокси на сервере sftp с помощью этой команды:
sftp -v -o ProxyCommand='nc -v -x proxyserver:1080 %h %p' the_sftp_host
Что касается этой команды, мы пытаемся использовать потоковый прокси, предоставляемый Apache Commons VFS, как указано в проблеме "[SFTP] Stream (например, netcat) прокси для файловой системы Sftp (также известной как ProxyCommand)" в https://issues.apache.org/jira/browse/VFS-440).
Использование только типа прокси SOCKS5 не работает.
Наш код основан на коде SftpProviderTestCase, предоставленном commons.apache.org в https://commons.apache.org/proper/commons-vfs/commons-vfs2/xref-test/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.html
Код ниже работает без прокси. Как только мы включаем потоковый прокси-сервер, он всегда генерирует исключение, например " Не удалось подключиться к SFTP-серверу " без каких-либо дополнительных подробностей.
Зависимости Java:
Для прокси-сервера commons-vfs Stream требуются имя пользователя и пароль для прокси. Использование того же пользователя и пароля с сервера sftp не работает.
Итак, что нам не хватает, чтобы заставить работать потоковый прокси?
Код
package es.application.test;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.apache.commons.vfs2.provider.sftp.TrustEveryoneUserInfo;
import es.application.common.util.Utils;
/**
*
* This code is based on https://commons.apache.org/proper/commons-vfs/commons-vfs2/xref-test/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.html
*
* Apache Commons VFS allows ProxyCommand as per https://issues.apache.org/jira/browse/VFS-440
*
*
*
*/
public class ReadFromSftp {
private String host = "sftp_host";
private String user = "sftp_user";
private String password = "sftp_password";
private String remoteDir = "/";
private String sftpileName = "the_file.xml";
private int proxyPort=1080;
private String proxyHost="localhost";
private String proxyCommand;
private boolean useProxy = true;
public String readFromSFTP() {
proxyPort=1080;
proxyHost="proxyserver";
useProxy = true;
proxyCommand ="nc -X 5 -x proxyserver:1080 "+this.host+ " 22";
String fileContent = StringUtils.EMPTY;
if (StringUtils.isNotBlank(host)) {
//FileSystemManager fsManager = null;
DefaultFileSystemManager fsManager = null;
FileSystemOptions opts = null;
FileObject[] remoteFiles = null;
String filePath = StringUtils.EMPTY;
try {
filePath = "sftp://" +host + remoteDir;
/**
* Not using fsManager = VFS.getManager();
*/
fsManager = new DefaultFileSystemManager();
fsManager.addProvider("sftp", new org.apache.commons.vfs2.provider.sftp.SftpFileProvider());
fsManager.init();
//Not using UserAuthenticator auth = new StaticUserAuthenticator(null, this.user, this.password);
opts = new FileSystemOptions();
/**
* Not using any of these configurations
*
DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth);
DefaultFileSystemConfigBuilder.getInstance().setRootURI(opts, filePath);
// FtpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
*/
final SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance();
builder.setStrictHostKeyChecking(opts, "no");
builder.setUserInfo(opts, new TrustEveryoneUserInfo());
builder.setTimeout(opts, 20000);
//TODO: Do we need this?
//builder.setIdentityRepositoryFactory(fileSystemOptions, new TestIdentityRepositoryFactory());
FileSystemOptions proxy_opts = (FileSystemOptions)opts.clone();
if (this.useProxy) {
System.out.println("PROXY enabled");
builder.setProxyHost(opts, this.proxyHost);
builder.setProxyPort(opts, this.proxyPort);
builder.setProxyType(opts, SftpFileSystemConfigBuilder.PROXY_STREAM);
builder.setProxyCommand(opts, this.proxyCommand);
//if this is not set, NullPointerException is thrown
builder.setProxyUser(opts, user);
//if this is not set, NullPointerException is thrown
builder.setProxyPassword(opts, password);
builder.setProxyOptions(opts, proxy_opts);
}
String uri = getSftpFileUri(remoteDir).toString();
System.out.println(("URI to resolve is:"+uri));
//
// TODO In Based on SftpProviderTestCase.html a new URI is set, but
//
// - is just for the test case?
// - Or is this rewrite really required?
// uri = String.format("sftp://%s@localhost:%d", initializeUserInfo("what_user_here", "what_password_here"), 22);
//
//System.out.println(("NEW URI to resolve is:"+uri));
FileObject fo = fsManager.resolveFile(uri, opts);
remoteFiles = fo.findFiles(Utils.getFileSelector(sftpileName));
if (remoteFiles != null && remoteFiles.length > 0) {
InputStream inputStream = remoteFiles[0].getContent().getInputStream();
fileContent = IOUtils.toString(inputStream, "UTF-8");
}
} catch (Exception ex) {
System.out.println("Exception.message: " + ex.getMessage());
String stacktrace = ExceptionUtils.getStackTrace(ex);
System.out.println("stacktrace.message: " + stacktrace);
} finally {
if (remoteFiles != null && remoteFiles.length > 0) {
fsManager.closeFileSystem(remoteFiles[0].getFileSystem());
}
}
}
return fileContent;
}
// Based on https://commons.apache.org/proper/commons-vfs/commons-vfs2/xref-test/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.html
private String initializeUserInfo(String user, String password)
{
String userInfo = user;
userInfo += ":" + password;
return userInfo;
}
//Based on https://commons.apache.org/proper/commons-vfs/commons-vfs2/xref-test/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.html
private URI getSftpFileUri(String remoteFilePath) throws Exception
{
try {
return new URI("sftp", initializeUserInfo(this.user, this.password), host, 22, remoteFilePath, null, null);
}
catch (URISyntaxException e) {
String message = String.format("URISyntaxException was thrown: Illegal character in sftp://%s:******@%s:%s%s", user, host, 22, remoteFilePath);
throw new Exception(message);
}
}
public static void main(String[] args) {
ReadFromSftp r = new ReadFromSftp();
String object = r.readFromSFTP();
System.out.println(object.length());
}
}