Getting started with J2SSH

The first thing you will probably want to do is to connect to an SSH server using J2SSH. This is a fairly
straightforward procedure using the SshClient class. This class provides access for connecting, authenticating
and starting a session channel, which enables you to execute commands or start the users shell.

import com.sshtools.j2ssh.SshClient;

First of all prepare your application, in this section we will guide you through the basics so for now just a simple
try/catch inside the static main method.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;



public class SshExample() {
  // A buffered reader so we can request information from the user
  private static BufferedReader reader =
        new BufferedReader(new InputStreamReader(System.in));
  
  public static void main(String args[]) {
    try {
      // Further code will be added here
    
	} catch(Exception e) {
      e.printStackTrace();
    }
  }
}

The next few sections will guide you through making the initial connection, authenticating the user and executing
a command or starting the users shell for a simple console based SSH application.


Making the initial connection

To create an SshClient instance import the class into your implementation class file and use the following code
to connect to an SSH server on the standard port 22.

SshClient ssh 
  = new SshClient();


System.out.print("Host to connect: ");

String hostname = reader.readLine();

ssh.connect(hostname);

When the client connects to the server, the server supplies its public key for the client to verify. You will see
that calling the connect method prompts the user within the console to verify the key:

The host firestar is currently unknown to the system
The host key fingerprint is: 1028: 69 54 9c 49 e5 92 59 40 5 66 c5 2e 9d 86 af ed
Do you want to allow this host key? [Yes|No|Always]:

In the default implementation of the connect method, J2SSH reads the $HOME/.ssh/known_hosts file to determines to which hosts connections
may be allowed. This is provided by the class ConsoleKnownHostsKeyVerification and the
default behavior can be emulated by the following code:

 
import com.sshtools.j2ssh.transport.ConsoleKnownHostsKeyVerification;


ssh.connect("firestar", new ConsoleKnownHostsKeyVerification());

When the connect method returns, the protocol has been negotiated and key exchange has taken place, leaving the connection ready for authenticating the user.

Authenticating the user

Once the connection has been completed the user is required to provide a set of credentials for authentication.
All client side authentication methods are implemented using the abstract class:

import com.sshtools.j2ssh.authentication.SshAuthenticationClient.

To perform authentication, the SshClient class provides the following method:

public int authenticate(SshAuthenticationClient auth);

There are currently five authentication methods implemented by J2SSH, 'password', 'publickey', 'keyboard-interactive' and 'hostbased'. With an extra agent authentication method that performs public key authentication using the J2SSH key agent.

Password Authentication

Password authentication is ideal for first time users as it requires no additional configuration within the SSH
client or server. The user simply supplies his username and password to the client which is then transmitted over
the encrypted connection to the server. The server then checks that the given password is acceptable to the native
password-authentication mechanism of the host operating system and returns the result to the client.

J2SSH implements the 'password' authentication method with the following class:

import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient

Using the password authentication method is straight forward; create an instance of the PasswordAuthentication
class, set the username and password and pass to the SshClient to complete the authentication.

 /** 
  * Create a PasswordAuthenticationClient instance, set the properties
  * and pass to the SessionClient to authenticate
  */
  PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
  
  System.out.print("Username: ");
  String username = reader.readLine();
  auth.setUsername(username);
  
  System.out.print("Password: ");
  String password = reader.readLine();
  auth.setPassword(password);
  
  int result = ssh.authenticate(pwd);
  

The Authentication Result

When the authentication method completes it returns the result of the authentication. This integer value can be any
of the following three values defined in the class:

import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
  ..
  ..
  if(result==AuthenticationProtocolState.FAILED)
     System.out.println("The authentication failed");

  if(result==AuthenticationProtocolState.PARTIAL)
     System.out.println("The authentication succeeded but another"
	                   + "authentication is required");

  if(result==AuthenticationProtocolState.COMPLETE)
     System.out.println("The authentication is complete");

Retrieving the available authentication Methods

It is possible at any time after the connection has been established and before authentication has been completed to request a list of authentication methods that can be used. The getAvailableAuthMethods method returns a list of authentication method names.

public List getAvailableAuthMethods(String username);

It should be noted that the SSH specification allows the server to return authentication methods that are not valid
for the user.

Prompting the User for Authentication Details?

Each SshAuthenticationClient implementation can optionally be set a prompt interface which allows the user to
be prompted for the information once the authenticate method has been invoked.

public interface SshAuthenticationPrompt {
  public boolean showPrompt(SshAuthenticationClient instance) 
                              throws AuthenticationProtocolException;
  }
}

The showPrompt method is called if the authentication instance is not ready to authenticate. The methods is called and the developer should verify the instance of the SshAuthenticationClient to make sure that it is compatible with the prompt (for example you cannot perform public key authentication
with a password prompt!). The user should then be duly prompted for the information and the instance set with the user's information. Once
complete, the prompt returns true to indicate that the user successfully entered correct information.

There are several prompts provided in the J2SSH common packages that provide useful Swing based dialogs to
prompt the user.

 
import com.sshtools.common.authentication.PasswordAuthenticationDialog;
  
/***
* Create a PasswordAuthenticationDialog instance and call the
* showAuthenticationMethod so the user can graphically
* enter their username and password
*/


PasswordAuthenticationClient pwd = 
            new PasswordAuthenticationClient();
			
PasswordAuthenticationDialog dialog = 
            new PasswordAuthenticationDialog(parent);
			
pwd.setAuthenticationPrompt(dialog);

int result;
result = ssh.authenticate(pwd);
  

Using a session channel to execute a command or start the users shell

Once the user is authenticated you will probably want to do something such as execute a command or start the users shell. The SSH protocol provides multiplexed channels over a single connection and the session channel is one of the channels defined by the SSH protocol. The session channel allows the client to execute a single command on the remote host and to communicate with the process by sending and receiving data. The J2SSH SessionChannelClient implements this channel and we will use this to execute a basic "ls" command.

The session channel provides an inputstream and outputstream for reading/writing, but before we can do this we need to setup the channel for our command. First we open the channel itself by calling the SshClient method:

 
SessionChannelClient session = ssh.openSessionChannel();

Now that we have a session instance we need to configure it for our command, there are several options that can be set before we invoke one of the methods that will start the session.

Setting Environment Variables
The SSH protocol provides a method to set an environment variable for the processes environment, the protocol also leaves the actual implementation of this down the server implementation, and in our experience most servers do not allow for this for security reasons. However the method is available since its defined in the protocol specification, so your free to try to use it, but beware the variable may not be set!

public boolean setEnvironmentVariable(String name, String value);

Requesting a Pseudo Terminal
A pseudo terminal is a device that imitates a terminal. Rather than being connected to an actual terminal, a pseudo-terminal (or pty) is connected to a process. If the command you are executing is expecting a terminal (such as a shell command) you can request that a pseudo terminal be attached to the process by calling the requestPseudoTerminal method.

public boolean requestPseudoTerminal(String term, int cols, int rows, int width, int height, String modes);

Invoking a command
After the above operations have been performed you can then request that the session either start the user's shell, execute a specific command or start an SSH subsystem (such as SFTP). You should not invoke a subsystem unless you are able to read/write the subsystem protocol, there are many additional utilities within J2SSH that provide for the available subsystems.

To start the users default shell use:

public boolean startShell();

Or to execute a specific command use:

public boolean executeCommand(String command);

An important note to remember is that this does not execute a shell command. You cannot for instance issue the command executeCommand("dir")" on the Windows Operating system as this is a shell command, instead use "cmd.exe /C dir". This method executes a binary executable and so should be used to execute any program other than the users shell.

Handling Session Data
Once the session has been configured and a command or shell has been started, you can begin to
transfer data to and from the remote computer using the sessions IO streams. These streams provide you with a
standardized interface for reading and writing the data.

The Session Channel's OutputStream
The format of writing data varies according to how you configured the session, for example if you executed the
users shell then the data should be written as if the user had entered the commands interactively.

 
/** Writing to the session OutputStream */
OutputStream out = session.getOutputStream();
String cmd = "ls\n";
out.write(cmd.getBytes());

The Session Channel's InputStream

/**
* Reading from the session InputStream
*/
InputStream in = session.getInputStream();
byte buffer[] = new byte[255];
int read;
while((read = in.read(buffer)) > 0) {
   String out = new String(buffer, 0, read);
   System.out.println(out);
}

Reading from stderr
The session also provides the stderr data provided by the remote session. Again an InputStream is provided.

public InputStream session.getStderrInputStream();

Closing the Session

The session can be closed using the following method:

public void close();

Disconnecting

The connection can be terminated by either side. To terminate the connection call the SshClient method:

public void disconnect();

A word on executing multiple commands

So we can now execute a single command on the remote server, but what's that I hear you say? I want to execute more than one command? Well if you cast your mind back I told you that the SSH protocol provides multiplexed channels over a single connection, so executing another command is as simple as executing the first, just create a new instance of the SessionChannelClient for every command you want to execute. You can execute them simultaneously or one after another, but always create a new session (since the session is closed when the command finishes and the protocol does not allow for re-using of a session to execute another command).

There is a drawback to this in that the process environment is not passed on from one session to another, so you cannot for example execute a command to change directory and then another to execute a script in that directory, since the change directory is lost when the session closes and the new command starts back in the default working directory. Of course you could always put the cd command into the script? Or use the shell to execute both commands. This subject is certainly a bit more advanced so I will leave it for another day and pencil in a new article to discuss all the alternatives for executing multiple commands.

This concludes our getting started tutorial, you should now have a basic working knowledge of how to connect, authenticate and execute commands using J2SSH.