We want to download a file from an SFTP using Apache Commons VFS behind a proxy. Our Java app should connect to the SFTP server through a SOCKS5 proxy. The network team has validate the proxy configuratoin to the sftp server using this command:
sftp -v -o ProxyCommand='nc -v -x proxyserver:1080 %h %p' the_sftp_host Regarding this command, we are trying to use a Stream proxy provided by Apache Commons VFS, as stated in the issue "[SFTP] Stream (e.g. netcat) proxy for Sftp file system (aka ProxyCommand)" in https://issues.apache.org/jira/browse/VFS-440). Using just a SOCKS5 proxy type does not work. Our code is based on SftpProviderTestCase code provided by commons.apache.org in https://commons.apache.org/proper/commons-vfs/commons-vfs2/xref-test/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.html The code below works without a proxy. Once we enable the stream proxy, it always throws an Exception like "Could not connect to SFTP server" without any further detail. Java dependencies: - commons-vfs-2.1 - jsch-0.1.53 The commons-vfs Stream proxy requires a user and password for the proxy. Using the same user and password from the sftp server does not work. Also, I don't unsderstand if the file URI shoud be rewritten (and how) like in the SftpProviderTestCase test code or it is just related to the test case itself. So, what are we missing to make the stream proxy work? *Sample Code:* 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()); } }
