'Not able to connect to SFTP using jcraft JSch

I am trying to connect to SFTP location via ssh jump-host proxy using jcraft version 0.1.52. But getting "connection is closed by foreign host" exception in my code. I have spent a good enough time looking at documentation but not able to figure out what the problem is

2016-11-18 14:53:14,091 44977 [main] ERROR c.w.v.r.ftp.JschSftpConnect -
    - com.jcraft.jsch.JSchException: connection is closed by foreign host
        at com.jcraft.jsch.Session.connect(Session.java:269)
        at com.jcraft.jsch.Session.connect(Session.java:183)
        at com.x.y.ftp.JschSftpConnect.connect(JschSftpConnect.java:77)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

There is no problem with private keys as I am able to connect to sftp server via unix command.

 sftp -o UserKnownHostsFile=/dev/null 
  -o StrictHostKeyChecking=no 
  -i /path/to/host/private-key-file 
    -o 'ProxyCommand=ssh 
        -o UserKnownHostsFile=/dev/null 
        -o StrictHostKeyChecking=no 
        -i /path/to/jumphost/private-key-file
        -l jumphostuser jump.host.com nc sftp.host.com 22' 
  1. Here is the code that I am running

The code:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;

import org.apache.commons.lang3.exception.ExceptionUtils;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;

public class JschSftpConnect {


    public static void main(String args[]) {
        String sftpHostKeyFilePath = "/path/to/host/private-key-file";
        String sftpHost="sftp.host.com";
        String sftpUser="user";
        String proxyHostName="jump.host.com";
        String proxyKeyPath ="/path/to/jumphost/private-key-file";
        String proxyUserName="jumphostuser";

        log.debug("Executing JSCH code.....");
        try {

            JSch jsch = new JSch();

            Path path = FileSystems.getDefault().getPath(sftpHostKeyFilePath);
            byte[] filearray = Files.readAllBytes(path);

            jsch.addIdentity("ID", filearray, null, null);
            Session session = jsch.getSession(sftpUser, sftpHost, 22);
            Properties props = new Properties();
            props.put("StrictHostKeyChecking", "no");
            session.setConfig(props);

            String command = "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "
                + localKeyFileDirectoryName + proxyKey + " -l " + proxyUserName + " " + proxyHostName
                + " nc %h %p";

            session.setProxy(new JumpHostProxyCommand(command));
            log.debug("Connecting session .......................");
            session.connect();
            log.debug("Session openend .......................");

            Channel ch = session.openChannel("sftp");
            ch.connect();
            log.debug("SFTP channel connected .......................");
            ChannelSftp channelSftp = (ChannelSftp) ch;
            channelSftp.cd("/");

            log.debug("Working directory is / .......................");

            byte[] buffer = new byte[1024];
            BufferedInputStream bis = new BufferedInputStream(channelSftp.get("/some_file_.psv"));
            File newFile = new File("some_file_.psv");
            OutputStream os = new FileOutputStream(newFile);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            int readCount;
            // System.out.println("Getting: " + theLine);
            while ((readCount = bis.read(buffer)) > 0) {
                // System.out.println("Writing: ");
                bos.write(buffer, 0, readCount);
            }
            log.debug("File should have been written / .......................");

            while (session != null) {
                System.out.println("Killing the session");
                session.disconnect();
                bis.close();
                bos.close();
                System.exit(0);
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
        }
    }
}



class JumpHostProxyCommand implements Proxy {

    String command;
    Process p = null;
    InputStream in = null;
    OutputStream out = null;

    public JumpHostProxyCommand(String command) {
        this.command = command;
    }

    public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception {


        String cmd = command.replace("%h", host);
        cmd = cmd.replace("%p", new Integer(port).toString());

        p = Runtime.getRuntime().exec(cmd);
        log.debug("Process returned by proxy command {} , {}", command,  p);
        in = p.getInputStream();
        log.debug("Input stream returned by proxy {}", in);
        out = p.getOutputStream();
        log.debug("Output stream returned by proxy {}", out);
    }

    public Socket getSocket() {
        return null;
    }

    public InputStream getInputStream() {
        return in;
    }

    public OutputStream getOutputStream() {
        return out;
    }

    public void close() {
        try {
            if (p != null) {
                p.getErrorStream().close();
                p.getOutputStream().close();
                p.getInputStream().close();
                p.destroy();
                p = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Would really appreciate if someone could help. Thanks!



Solution 1:[1]

Here's the approach which had worked fine for me.

Basically it's a tunnel to your sftp host. It creates a tunnel to your sftp host via jumphost or tunnel host and grabs the files via sftpChannel from this tunneled "localhost" port (2222). I've tested it via two ssh hosts. It's working fine.

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class JschSftpConnect {

    public static final Logger log = LoggerFactory.getLogger(JschSftpConnect.class);
    public static final com.jcraft.jsch.Logger sshLogger = new com.jcraft.jsch.Logger() {
        public boolean isEnabled(int level) {
            return true;
        }

        public void log(int level, String message) {
            switch (level) {
                case 0:
                    log.debug(message);
                    break;
                case 1:
                    log.info(message);
                    break;
                case 2:
                    log.warn(message);
                    break;
                case 3:
                    log.error(message);
                    break;
                case 4:
                    log.error(message);
                    break;
                default:
                    break;

            }
        }
    };

    public static void main(final String args[]) {
        final String tunnelHostKey = "keyfile";
        final String tunnelHost = "sshTunnelHost";
        final String tunnelHostUser = "tunnelsshuser";

        final String sftpKey = "sftpKey";
        final String sftpHost = "sftpHost";
        final String sftpUser = "sftpuser";

        if (args.length >= 2) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Session tunnelSesssion =
                                createSession(tunnelHostKey, tunnelHost, tunnelHostUser,22);

                        tunnelSesssion.setPortForwardingL
                                (2222,sftpHost,22);

                        Session sftpSession =
                                createSession(sftpKey, "localhost", sftpUser,2222);

                        ChannelSftp sftpChannel =
                                getChannel(sftpSession);

                        if (args.length >= 2) {
                            sftpChannel.cd(args[0]);

                            log.debug("Working directory is " + sftpChannel.pwd());
                            getFileFromSftp(sftpChannel, args[1], args.length == 3 ? args[2] : args[1]);
                        }
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }).start();
        } else {
            log.info("usage: java JschSftpConnect -cp ... <sftp dir> <sftp infile> <optional out file>");
            System.exit(-1);
        }
    }

    private static Session createSession(
            String keyFile, String host, String user,int port
            ) throws IOException, JSchException {
        JSch jsch = new JSch();
        JSch.setLogger(sshLogger);
        Path path = FileSystems.getDefault().getPath(keyFile);
        byte[] filearray = Files.readAllBytes(path);

        jsch.addIdentity("ID", filearray, null, null);
        Session session = jsch.getSession(user, host, port);
        Properties props = new Properties();
        props.put("StrictHostKeyChecking", "no");
        session.setConfig(props);

        session.setTimeout(1000);
        session.connect();
        if (!session.isConnected()) {
            throw new IOException("Session not connected");
        }
        return session;
    }

    private static ChannelSftp getChannel(Session session)throws IOException, JSchException{
        Channel ch = session.openChannel("sftp");
        log.debug("SFTP channel connected .......................");
        ChannelSftp channelSftp = (ChannelSftp) ch;
        channelSftp.connect(1000);
        return channelSftp;
    }

    private static void getFileFromSftp(ChannelSftp channelSftp, String filename, String outFile) throws SftpException, IOException {
        Path p = Paths.get(outFile != null ? outFile : "output");
        try {
            Files.copy(channelSftp.get(filename), p, REPLACE_EXISTING);
            log.debug("File '" + filename + "' is written");
            System.exit(0);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1