Tuesday, March 11, 2014

SSH Agent Forwarding using Java

SSH Agent forwarding is a really useful way to use a chain of ssh commands without configuring public keys for each and every machine in the chain.
You just have to add your public key to all the nodes in the chain and it allows you to make ssh calls to any node while in a another node.
Here's a very good illustration of how it works ... [1]

First you should test it using the terminal.
You can do this by editing the config file inside the .ssh directory if you don't have one, create one

vi ~/.ssh/config

Example config file:
Host beast
   HostName 196.96.179.220
   User swithana
   IdentityFile ~/.ssh/id_rsa
   ForwardAgent yes

Host iu10
   HostName xx.xxx.xsede.org
   User swithana
   ForwardAgent yes
   IdentityFile ~/.ssh/id_rsa

With this file configured, you can ssh to the beast host machine and then do a ssh from inside the beast host machine to the iu10 without having to include the beast machine's public key in the iu10 machine. It can also be done the other way around ( through iu10 to beast)

Example commands
$swithana:~ ssh beast
$swithana@beast:~ ssh iu10

This would work because you've set the SSH Agent Forwarding to true.

Here's the Java code to copy a file from one host to another using SSH Agent Forwarding.( uses scp)
I have used the JCraft library [2]

public class SSHCommandExecutor {
    public static void main() {

        String host = "196.36.199.10";
        String user = "swithana";

        //your paraphrase here
        String paraphrase = "***********";

        String command = "scp test.txt swithana@xx.xx.xsede.org:/home/swithana/test_2.txt";

        //private key location
        String privateKey = "/Users/swithana/.ssh/id_rsa";

        JSch jsch = new JSch();
        jsch.setLogger(new MyLogger());


        try {
            jsch.addIdentity(privateKey, paraphrase);

            Session session = jsch.getSession(user, host, 22);
            Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            config.put("PreferredAuthentications",
                    "publickey");

            session.setConfig(config);
            session.connect(20000);

            Channel channel = session.openChannel("exec");

            ((ChannelExec) channel).setCommand(command);

            // this is the key line that sets AgentForwading to true
            ((ChannelExec) channel).setAgentForwarding(true);

            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);

            channel.connect();
            Thread.sleep(1000);

            channel.disconnect();
            session.disconnect();
            System.out.println("DONE");

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

    public static class MyLogger implements com.jcraft.jsch.Logger {
        static java.util.Hashtable name = new java.util.Hashtable();

        static {
            name.put(new Integer(DEBUG), "DEBUG: ");
            name.put(new Integer(INFO), "INFO: ");
            name.put(new Integer(WARN), "WARN: ");
            name.put(new Integer(ERROR), "ERROR: ");
            name.put(new Integer(FATAL), "FATAL: ");
        }

        public boolean isEnabled(int level) {
            return true;
        }

        public void log(int level, String message) {
            System.err.print(name.get(new Integer(level)));
            System.err.println(message);
        }
    }
}



[1] http://www.unixwiz.net/techtips/ssh-agent-forwarding.html
[2] http://www.jcraft.com/