But muCommander didn't use public key authentication, and I have disabled password-based authentication on my home SSH server. So there was the opportunity to play around with J2SSH (which muCommander was using) and both implement key-based authentication in my current file manager and explore one of the libraries for my next project. OK, maybe not applicable for my work project, because J2SSH is GPL, but I can get to play, OK?
With license questions out of the way, we can get down to business. And it is not difficult at all, as the j2ssh/examples directory contains a PublicKeyConnect.java. You just need to instantiate a
com.sshtools.j2ssh.SshClient
, call connect
, passing the hostname as a String and authenticate using the method... which was it... ah yes authenticate
, passing a com.sshtools.j2ssh.authentication.SshAuthenticationClient
.Now getting this
SshAuthenticationClient
is the fun part. In our case, we are using the com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient
and we need several more steps to prep it up. After instantiating it, we need to call setUsername
with a String (can't tell you what it stands for). Then we need to set the private key itself using the setKey
method and we're What?
setKey
expects a parameter? Well yes it does, and it's another of those j2ssh classes: com.sshtools.j2ssh.transport.publickey.SshPrivateKey
. But we seem to be stuck here, as you can't instantiate SshPrivateKey
- it's abstract. What does this mean? Argh, never mind, you can't instantiate it. Try it. See? Told ya so.So then we see there's this similarly named
com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile
. Might it have something to do with our SshPrivateKey
? Yes, as it turns out, it has a method toPrivateKey
(takes a passphrase as a String- you do use passphrases, don't you?), and returns our most wanted SshPrivateKey
. What's that you're saying? You can't instantiate SshPrivateKeyFile
either? Fear not, because it has a static method parse
, which overloaded to accept both a File and a byte array with the actual private key file or data.If you couldn't follow this convoluted line of thought (I couldn't), here's the code, as taken from the patch of muCommander:
PublicKeyAuthenticationClient pk = new PublicKeyAuthenticationClient();
pk.setUsername(credentials.getLogin());
SshPrivateKey key = null;
// Throw an AuthException if problems with private key file
try {
SshPrivateKeyFile file = SshPrivateKeyFile.parse(new File(privateKeyPath));
key = file.toPrivateKey(credentials.getPassword());
} catch (InvalidSshKeyException iske) {
throw new AuthException(realm, "Invalid private key file or passphrase"); // Todo: localize this entry
} catch (IOException ioe) {
throw new AuthException(realm, "Error reading private key file"); // Todo: localize this entry
}
pk.setKey(key);
Now if
sshClient.authenticate
returns AuthenticationProtocolState.COMPLETE
, you're ready to go. You can open a shell or an SftpClient
. Mission accomplished.If you had the urge to download the muCommander source code and apply this patch, no need to: it's already implemented in CVS.