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”.
- http://ariadne.mse.uiuc.edu/Cluster/ssh_log_through.html
- http://www.debian-administration.org/articles/152
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.