Creating an SSH Client

Creating an SSH Client using the Maverick Synergy Java SSH API is relatively simple. The SshClient class provides a high-level implementation that enables you to authenticate in several ways. 

From version 3.1.0, the SshClient is now immutable and is created via the SshClientBuilder.

The most simple way is to connect a SshClient using a password. 

try(SshClient ssh = SshClientBuilder.create()
      .withHostname("localhost")
      .withPort(2222)
      .withUsername("root")
      .withPassword("xxxxx")
      .build()) {

}

Note that the SshClient is itself Closable, so you can wrap it within try/catch to ensure that resources are closed and the client disconnected when your operation is complete.

If you want to create a client that authenticates using a public key, try

try(SshClient ssh = SshClientBuilder.create()
      .withHostname("localhost")
      .withPort(2222)
      .withUsername("root")
      .withIdentities(SshKeyUtils.getPrivateKey(
          new File(".ssh/id_rsa"), "secure passphrase"))	      
      .build()) {

}

If you prefer, you can load several public key identities and pass these so any keys can be used for authentication.

try(SshClient ssh = SshClientBuilder.create()
      .withHostname("localhost")
      .withPort(2222)
      .withUsername("root")
      .withIdentities(SshKeyUtils.getPrivateKey(
          new File(".ssh/id_rsa"), "secure passphrase"),
                      SshKeyUtils.getPrivateKey(
          new File(".ssh/id_ed25519"), "different passphrase"))	      
      .build()) {

}

You may need to authenticate by password and public key. There is also a constructor to suit this.

try(SshClient ssh = SshClientBuilder.create()
      .withHostname("localhost")
      .withPort(2222)
      .withUsername("root")
      .withPassword("my password")
      .withIdentities(SshKeyUtils.getPrivateKey(
          new File(".ssh/id_rsa"), "secure passphrase"))	      
      .build()) {

}

There are times, however, when you may need to prompt the user for authentication. In this example, we prompt the user for the password in the console.

try(SshClient ssh = SshClientBuilder.create().withHostname("localhost")
      .withPort(2222)
      .withUsername("root")
      .withPasswordPrompt(()->{
             System.out.print("Enter Password: ");
	     return new String(System.console().readPassword());
       })
       .build()) {

}

We can do the same with a private key, prompting for the passphrase if needed. Here the lambda provides a string with the key information.

.withPrivateKeyFile(new File(".ssh/id_rsa"), (info)->{
      System.out.print("Key " + info);
      System.out.print("Enter Passphrase: ");
      return new String(System.console().readPassword());
})

You may be unable to determine what authentication type to support at compile time. So, you may have to implement authentication directly once the SshClient is connected. This also allows us to provide some resilience and retry if authentication fails.

try(SshClient ssh = SshClientBuilder.create()
      .withHostname("localhost")
      .withPort(2222)
      .withUsername("root")      
      .build()) {

    System.out.println(ssh.getAuthenticationMethods()); 
    ClientAuthenticator auth; 
    do { 
        System.out.print("Password: "); 
        auth = new PasswordAuthenticator(
              System.console.readPassword());
        if(ssh.authenticate(auth, 30000)) 
           break; 
    } while(ssh.isConnected());
}

Here, we have created a PasswordAuthenticator with the password read from System.console. We then pass it into the SshClient via the authenticate method; this returns a boolean to indicate whether the attempt was successful. Note that the return from authenticate is only the success of the individual authentication attempt. If the server requires additional authentication, you may need to perform a different authentication, for example, authenticating with a public key. The getAuthenticationMethods method of SshClient will provide you with a list of support authentication methods. This may change after you perform a successful authentication.

You can check the overall authentication state with the following code:

if(ssh.isAuthenticated()) { 
   System.out.println("Authenticated"); 
} else { 
   System.out.println("Authentication failed"); 
}