SSH with Java


Recently I needed to do some server manipulation over the SSH-2 protocol from a Java client program. There are quite a few choices of SSH libraries for Java out there. Usually I prefer BSD license whenever possible, so I thought I’ll give Ganymed SSH-2 for Java a try. It turned out to be pretty simple to use. Here’s a short example of how to connect to the server using the private key and execute some command.

import java.io.*;
import ch.ethz.ssh2.*;

public class Example {
  public static void main(String[] args) throws IOException {
    Connection conn = new Connection("hostname");
    conn.connect();
    File pemKeyFile = new File("privKey.pem");
    boolean isAuth = conn.authenticateWithPublicKey("user", pemKeyFile, "keyPwd");
    if (isAuth == false) {
      throw new IOException("Authentication failed.");
    }

    Session sess = conn.openSession();
    sess.execCommand("netstat -nl | egrep ':80' | wc -l");
    InputStream inp = sess.getStdout();
    InputStreamReader reader = new InputStreamReader(inp);
    BufferedReader br = new BufferedReader(reader);
    String line = br.readLine();

    sess.close();
    conn.close();
  }
}

If you’re unfamiliar with private/public key authentication over SSH, see the links below or just google for “passwordless ssh login”.

One thing that most tutorials don’t mention is that your home directory should have permissions 755. I found out through trial and error, that using some user’s home directory with permissions 777 just doesn’t let you login with a private key.

Another thing that I needed to do was copy a file over to the server. Now this gave me some unexpected problems. While the API seemed simple enough, the code below just didn’t work.

String data = "sample data";
SFTPv3Client client = new SFTPv3Client(conn);
SFTPv3FileHandle handle = client.createFile("test_file.txt");

byte []arr = data.getBytes();
client.write(handle, 0, arr, 0, arr.length);
client.closeFile(handle);
client.close();

Here, the conn object is the SSH connection which can be acquired as shown in the first code listing. This looks  pretty straightforward – create a file on the server, write some bytes to it, then close, but the outcome of it all – the file is created on the server, but it is  always 0 bytes in length.  It took me a while to figure out what’s wrong. Now is the time to mention that I was using the “latest version” of Ganymed that was available on their page – build210. And this screwed me good. After I got frustrated with the code not working the way I wanted it to, I started looking through the source of Ganymed and I found an unsatisfiable conditional statement in the write(…) method of the SFTPv3Client class. I fixed the problem, recompiled Ganymed library and voila it works. Then later I found out that Ganymed actually has a release build211, but they renamed the library to trilead. You can find it in this maven2 repository.

EDIT: 2011-10-17

I’ve created a Maven project with a very simple single class implementation of  executing shell commands over SSH using the Trilead library. Maven configuration contains the required repository and dependency tags to compile this class. Simply use mvn package inside the extracted directory or create project files for your IDE. If you need more help with Maven this Getting Started Guide is a good place to start.