7

I need to be able to ssh from a Java program into a remote server, and from there SSH to another server. I have credentials for both servers on my client.

The commands will be passed automatically from within the app as regular strings (no user input). I need to be able to run those custom commands on the second server and be able to decide what commands to issue during runtime, based on the output and some simple logic.

Can I use JSch to do that and if yes, where should I start look into? (Examples, info)

=============================================================

ADDED:

Exception in thread "main" com.jcraft.jsch.JSchException: UnknownHostKey: host.net. RSA key fingerprint is 'blahblahblah'

as till now, I am solving this problem by modifying the known_hosts file and adding host manually in there. Can I bypass this little problem by settings an option somewhere telling the JSch to press YES automatically when this YES-NO question is asked?

Martin Klosi
  • 3,098
  • 4
  • 32
  • 39

3 Answers3

12

To connect to a second server behind a firewall, there are in principle two options.

The naive one would be to call ssh on the first server (from an exec channel), indicating the right server. This would need agent forwarding with JSch, and also doesn't provide the JSch API to access the second server, only the ssh command line.

The better one would be to use the connection to the first server to build up a TCP Tunnel, and use this tunnel to connect to the second server. The JSch Wiki contains a ProxySSH class (together with some example code) which allows to use a JSch session as a tunnel for a second JSch session. (Disclaimer: This class was written mainly by me, with some support from the JSch author.)

When you have your connection to the second server, use either a shell channel or a series of exec channels to execute your commands. (See Shell, Exec or Subsystem Channel in the JSch Wiki for an overview, and the Javadocs for details.)


For your unknown-host-key problem:

The secure version would be to collect all host keys (in a secure way) before and put them in the known_hosts file. (If you simply trust the key which is presented to you, you are vulnerable to a man-in-the-middle attack. If these are of no concern in your network, since it is physically secured, good for you.)

The convenient version is setting the configuration option StrictHostKeyChecking to no - this will add unknown host keys to the host keys file:

JSch.setConfig("StrictHostKeyChecking", "no");

(You can also set it individually on the sessions, if you only want to set it for the proxied sessions and not for the tunnel session. Or override it for the tunnel session with yesor ask - there the MITM danger might be greater.)

A middle way would be to enable actually asking the user (which then should compare the fingerprints to some list) - for this, implement the UserInfo interface and provide the object to the session. (The JSch Wiki contains an example implementation using Swing JOptionPanes, which you can simply use if your client program runs on a system with GUI.)

For the saving of accepted host keys to work, you must use the JSch.setKnownHosts method with a file name argument, not the one with an InputStream argument - else your accepting will have to be repeated for each restart of your client.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • works great!. can I use the same gateway to access two or more different SSH servers behind that gateway? – Martin Klosi Jul 21 '11 at 17:36
  • @Martin: Yes, I have used it this way (for accessing about 23 servers hidden behind a single gateway). – Paŭlo Ebermann Jul 21 '11 at 22:57
  • 1
    This was actually the reason to create this ProxySSH class :-) – Paŭlo Ebermann Jul 21 '11 at 22:58
  • ADDED: I saw that you mentioned the JSch ssh forwarding agent. how can I use that? I didnt see any examples on that. Although ProxySSH works great, I don't actually need it for my purpose, since the custom command I need to run on the second host, I can run it from the proxy host, but I need to be able to forward the ssh credentials to it. – Martin Klosi Jul 22 '11 at 22:54
  • I did never try it, but there is a `setAgentForwarding` method on `ChannelShell` (and `ChannelExec`/`ChannelSubsystem`). – Paŭlo Ebermann Jul 23 '11 at 09:30
  • When I try this it just hangs indefinitely for no reason. – Magic Octopus Urn Apr 11 '18 at 17:25
  • Also, your links are dead. – Magic Octopus Urn Apr 11 '18 at 17:26
  • @MagicOctopusUrn unfortunately the JSch wiki is gone, nothing I can do about this. The Javadoc links should be still there, though they are about a version of JSch from 7½ years ago. I don't know what exactly you tried, so I can't comment on your "hangs indefinitely for no reason" (other than likely it is not "no reason"). – Paŭlo Ebermann Apr 11 '18 at 19:43
  • Note that `StrictHostKeyChecking=no` won't *"add unknown host keys to the host keys file"*, on its own. You also need to set the path to the host keys file using `setKnownHosts`. – Martin Prikryl Mar 29 '19 at 05:31
2

Use an SSH tunnel, aka local port forwarding, to open an SSH/SFTP connection to B via A.

Session sessionA = jsch.getSession("usernameA", "hostA");
// ...
sessionA.connect();

int forwardedPort = sessionA.setPortForwardingL(0, "hostB", 22);

Session sessionB = jsch.getSession("usernameB", "localhost", forwardedPort);
// ...
sessionB.connect();

// Use sessionB here for shell/exec/sftp

You may need to deal with UnknownHostKey exception.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
0

This can help anyone. Works fine:

 public static void sesionA(){
     try {
        Session sessionA = jSch.getSession(username, hostA);  
        Properties config = new Properties(); 
        config.put("StrictHostKeyChecking", "no");
        sessionA.setConfig(config);
        sessionA.setPassword(passwordA);
        sessionA.connect();


        if(sessionA.isConnected()) {
            System.out.println("Connected host A!");
            forwardedPort = 2222;
            sessionA.setPortForwardingL(forwardedPort, hostB, 22);      
        }

    } catch (JSchException e) {
        e.printStackTrace();
    }
 }

 public static void sesionB(){


        try {
            Session sessionB = jSch.getSession(username, "localhost", forwardedPort);

            Properties config = new Properties(); 
            config.put("StrictHostKeyChecking", "no");
            sessionB.setConfig(config);
            sessionB.setPassword(passwordB);
            sessionB.connect();

          if(sessionB.isConnected()) {
             System.out.println("Connected host B!");
          }
     }
 }
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
  • 1
    That's just a bloated code the my answer. + Never ever suggest anyone to use `StrictHostKeyChecking` without explaining the security consequences. - You are losing a protection against [MITM attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) by doing do. – Martin Prikryl Jul 26 '18 at 03:48