[VFS] SFTP + Stream Proxy + ProxyCommand
Jordi Rodriguez
2018-11-19 11:01:37 UTC
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

Using just a SOCKS5 proxy type does not work.

Our code is based on SftpProviderTestCase code provided by
commons.apache.org in

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
* Apache Commons VFS allows ProxyCommand as per
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() {

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

//Not using UserAuthenticator auth = new
StaticUserAuthenticator(null, this.user, this.password);
opts = new FileSystemOptions();

* Not using any of these configurations


DefaultFileSystemConfigBuilder.getInstance().setRootURI(opts, filePath);
FtpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);

final SftpFileSystemConfigBuilder builder =
builder.setStrictHostKeyChecking(opts, "no");
builder.setUserInfo(opts, new TrustEveryoneUserInfo());
builder.setTimeout(opts, 20000);
//TODO: Do we need this?
new TestIdentityRepositoryFactory());

FileSystemOptions proxy_opts =

if (this.useProxy) {
System.out.println("PROXY enabled");
builder.setProxyHost(opts, this.proxyHost);
builder.setProxyPort(opts, this.proxyPort);

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://%***@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 =

if (remoteFiles != null && remoteFiles.length > 0) {
InputStream inputStream =
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) {


return fileContent;

// Based on
private String initializeUserInfo(String user, String password)
String userInfo = user;

userInfo += ":" + password;

return userInfo;

//Based on
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,
throw new Exception(message);

public static void main(String[] args) {

ReadFromSftp r = new ReadFromSftp();
String object = r.readFromSFTP();