mercoledì 4 aprile 2012

Jsch pure ssh2 java implementation library sample






A great ssh 2 java library JSCH


Here you can find one of the most cleaner implementation I found, to realize ssh sftp tools in java.

Here a breaf usage example class:

public class SSHConnectionCore {

    Logger LOG = Logger.getLogger(SSHConnectionCore.class);


    private class JonnyUserInfo implements UserInfo {

        private String password;
        private String passphrase;
        private String userName;

        public JonnyUserInfo(String username) {
            this.userName = username;
        }

        @Override
        public String getPassphrase() {
            return passphrase;
        }

        @Override
        public String getPassword() {
            return password;
        }

        @Override
        public boolean promptPassphrase(String message) {
            passphrase = null;
            LOG.debug(message);
            passphrase = readOneLine();

            if (passphrase != null && passphrase.length() > 0) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public boolean promptPassword(String message) {
            password = null;
            // stampo il messaggio ricevuto dall'host
            LOG.debug(message);
            // richiedo la password.. questo step deve venire saltato nel caso
            // di host riconosciuti con chiave
            password = readOneLine();

            if (password != null && password.length() > 0) {
                return true;
            } else {
                return false;
            }
        }

        /**
         * Chiedo all'utente di dare l'autorizzazione per la connessione ad un
         * host non verificato, questo metodo dovrebbe essere richiamato quando
         * non viene verificato l'host tramite chiave oppure l'host non è
         * registrato tra gli known host TODO verificare!
         */
        @Override
        public boolean promptYesNo(String message) {
            // stampa il messaggio ricevuto dall'host
            LOG.debug(message);
            // richiedo la conferma dell'utente
            String s = readOneLine();
            if ("yes".equalsIgnoreCase(s)) {
                return true;
            }
            return false;
        }

        /**
         * Stampo un messaggio del framework
         */
        @Override
        public void showMessage(String message) {
            LOG.debug(message);
        }

        private String readOneLine() {
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    System.in));
            try {
                return in.readLine();
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    }



    /**
     * open an exec channel to execute command
     *
     * @param userName
     * @param hostIp
     * @param Port
     * @param command
     * @throws Exception
     */
    public File execCommandInSession(String userName,String hostIp,int   Port,String command,int timeOut,
            String privateKeyPath,String knownHosts) throws Exception,SSHConnectionException {

        File tmp = null;
        JSch jsch = new JSch();
        // in questo caso utilizzo rsa per accesso diretto
        // senza digitare ogni volta la passwd
        LOG.debug("Identity added:"+privateKeyPath);
        // utilizzo una passphrase nulla per l'rsa
        jsch.addIdentity(privateKeyPath,"");
        // setto i known hosts
        jsch.setKnownHosts(knownHosts);
       
        JonnyUserInfo cui1 = new JonnyUserInfo(userName);
        Session session = jsch.getSession(userName,hostIp);
       
        LOG.debug("Working with session :" + session);

        session.setUserInfo(cui1);
        session.connect();


        ChannelExec channel = null;
        try {
            channel = (ChannelExec) session.openChannel("exec");
            if (channel == null)
                System.exit(0);

            LOG.debug("Execute command :"+command);
           
            channel.setCommand(command);
            channel.setErrStream(System.err);
           
            FileOutputStream fos = null;
            try {
                tmp = File.createTempFile("command_output","txt");
                fos = new FileOutputStream(tmp);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            // use System.out if you want more output or fos if file
            channel.setOutputStream(fos);
            channel.connect(9000);

        } catch (JSchException e) {
            e.printStackTrace();
            throw new SSHConnectionException();
        }

        while (true) {
            // rimango in attesa fino alla chiusura del channel
            if (channel.isClosed()) {
                LOG.debug("- il canale è stato chiuso con stato: "
                        + channel.getExitStatus());
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee) {
                ee.printStackTrace();
            }
        }

        channel.disconnect();
        session.disconnect();
        return (tmp);
    }

}


One of the most difficult thing I found was the authentication activities to obtain access directly via rsa asymmetric key exchange.

This is exactly what I did.
On a windows developer machine I've installed a Lubuntu virtual machine, to test the pure ssh connection.
This lighting me the right way.


Creating A Key 


Protocol version 1 key generation

To create the most simple key, with the default encryption, open up a console, and enter the following command :

$ ssh-keygen

Will output the following :

Generating public/private rsa1 key pair.
Enter file in which to save the key (/home/dave/.ssh/identity): /home/dave/.ssh/identity
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/dave/.ssh/identity.
Your public key has been saved in /home/dave/.ssh/identity.pub.
The key fingerprint is:
22:bc:0b:fe:f5:06:1d:c0:05:ea:59:09:e3:07:8a:8c dave@caprice

When asked for a "passphrase", we won't enter one. Just press enter twice. 

The ssh-keygen program will now generate both your public and your private key. For the sake of this first simple tutorial I will call these files by their default names "identity" and the public key "identity.pub".

Your keys are stored in the .ssh/ of the client linux box for instance, directory in your home directory, but you can store them where ever you'd like. 

Good practice is to backup your keys on a floppy. If you do so, guard this floppy with your life!

* Note: specifying a key type may be mandatory on your system. In that case, skip to the version 2 key geneation process.
Lets have a look at your keys.

cd ~.ssh; ls -l
-rw-------    1 dave     dave          526 Nov  2 01:33 identity
-rw-r--r--    1 dave     dave          330 Nov  2 01:33 identity.pub

The file identity contains your private key. YOU SHOULD GUARD THIS KEY WITH YOUR LIFE! This key is used to gain access on systems which have your private key listed in their authorized keys file. 

I cannot stress this enough, dont have your keys drifting around. Also, make sure your private key always is chmod 600, so other users on the system won't have access to it.

The file identity.pub contains your public key, which can be added to other system's authorized keys files. We will get to adding keys later.

Protocol version 2 key generation 

Exactly the same but with a different public key name (identity.pub VS id_dsa.pub)

Creating a version 2 keypair is much like creating a version 1 keypair. 

Except for the fact that the SSH protocol version 2 uses different encryption algorithms for its encryption. 

In this case we can even choos it ourselves! Huray! To find out which versions are available on your system I'd advise you to have a look in the ssh-keygen manpage.

In our example we wil create a keypair using dsa encryption. This can be done by passing the key encryption method type to ssh-keygen. This is done in the following way :

$ ssh-keygen -t dsa

Which will output the following :

$ ssh-keygen -t dsa

 
Generating public/private dsa key pair.
 
Enter file in which to save the key (/home/test/.ssh/id_dsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/test/.ssh/id_dsa.
Your public key has been saved in /home/test/.ssh/id_dsa.pub.
The key fingerprint is:
7b:ab:75:32:9e:b6:6c:4b:29:dc:2a:2b:8c:2f:4e:37 dave@caprice


Again, we will retain the default locations, and we will not use a 
passphrase either.

Your keys are stored in the .ssh/ directory in your home directory.
Lets have a look at your keys.


cd ~.ssh; ls -l
-rw-------    1 dave     dave          526 Nov  3 01:21 id_dsa
-rw-r--r--    1 dave     dave          330 Nov  3 01:21 id_dsa.pub


The file id_dsa contains your version 2 private key.

The file id_dsa.pub contains your version 2 public key, which can be added to other system's authorized keys file.

Again, I have listed a full ls -l with permissions, make sure you have the permissions set up correctly, otherwise other users may be able to snatch it from you. It is also a good idea to give your keys a non-standard name, since it makes guessing the name of your keypair files more easy.

Placing the public key on the remote server 

To be able to log in to remote systems using your pair of keys, 
you will first have to add your public key on the remote server to the authorized_keys (for version 1) file, and the authorized_keys2 (for version2) file in the .ssh/ directory in your home directory on the remote machine.

In our example we will assume you don't have any keys in the authorized_keys files on the remote server. 

(Hint: If you do not have a remote shell, you can always use your own useraccount on your local machine as a remote shell (ssh localhost))

First we will upload the public keys to the remote server :

$ cd .ssh/ 

$ scp identity.pub dave@192.168.1.3:./identity.pub identity.pub

100% |*****************************************************| 526

$ scp id_dsa.pub dave@192.168.1.3:./id_dsa.pub identity.pub 

100%|*****************************************************| 614


This will place your keys in your home directory on the remote server. After that we will login on the remote server using ssh or telnet the conventional way... with a password.
When you are logged in you should create a .ssh directory, and inside the .ssh/ directory create an authorized_keys and an authorized_keys2 file and add the keys to the files. 

Make sure the files are not readable for other users/groups. 
chmod 600 authorized_keys* does the trick.

Adding the public key for version 1 works like this:

$ ssh 192.168.1.3 -v [I edited out the verbose output, and entered the password] [Remember kids, always use -v so dont try this at home :) ] 
$ mkdir .ssh 
$ chmod 700 .ssh 
$ cd .ssh [dave@julia .ssh]$ touch authorized_keys 
$ chmod 600 authorized_keys 
$ cat ../identity.pub >> authorized_keys 
$ rm ../identity.pub

Placing the key for version 2 works about the same :

$ cd .ssh
$ touch authorized_keys2 
$ chmod 600 authorized_keys2 
$ cat ../id_dsa.pub >> authorized_keys2 
$ rm ../id_dsa.pub


Log in using your key
 
To log in using your key use the ssh command. We will add -1 to make sure we are using SSH Protocol version 1.

ssh -1 -v test@192.168.1.3

This logs you into a system using your version 1 key.
Try it again, now for version 2

ssh -2 -v test@192.168.1.3

Have a look in the output of both ssh logins and you will be able to see some differences between version 1 and 2.

Naturalli under eclipse I put the private key id_dsa, and the known_hosts file to allows the library to connect properly in the way posted before.
 


Nessun commento:

Posta un commento