无法使用jcraft JSch连接到SFTP

问题描述:

我想通过使用jcraft版本0.1.52的ssh跳转主机代理连接到SFTP位置。但得到“连接关闭外国主机”在我的代码异常。我花了好足够的时间在看文档,但无法弄清楚的问题是什么无法使用jcraft JSch连接到SFTP

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) 

,因为我能够连接通过unix命令到SFTP服务器没有与私钥没有问题。

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. 下面是我运行
  2. 代码代码:

    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(); 
         } 
        } 
    } 
    

    真的很感激,如果有人可以帮助。谢谢!

开始=>
+0

通知connect()方法,而不是'调用Runtime.getRuntime()EXEC(命令);'它应该是'调用Runtime.getRuntime()EXEC(CMD);'太 –

+0

塞吉本纳2,那是我现在编辑的帖子中的一个错字。虽然很漂亮! – Techji

这里的方法对我来说工作得很好。

基本上它是一个隧道到 您的sftp主机。它通过jumphost或隧道主机创建一个到你的sftp主机的隧道,并通过sftpChannel从这个隧道“本地主机”端口(2222)抓取文件。 我已经通过两个ssh主机测试过它。它工作正常。

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); 
     } 
    } 
} 
+0

谢谢谢尔盖。我可以看到你删除了跳转主机代理配置。更新后的代码不适用于我的用例,因为sftp连接是通过跳转主机。 – Techji

+0

如果您想要创建一个与原始代码有点不同的隧道。稍后我会更新代码。 –

+0

@Techji我已经更新了答案。你可以通过隧道实现,就像我之前说过的那样。它工作正常。 –