1. Overview

Interacting with a remote server is a common task in modern software development and system administration. Programmatic interaction with a remote server using an SSH client allows for deploying applications, managing configurations, transferring files, etc. The JSch, Apache Mina SSHD, and SSHJ libraries are popular SSH clients in Java.

In this tutorial, we’ll learn how to interact with a remote server using the JSch, Apache Mina SSHD, and SSHJ libraries. Also, we’ll see how to establish a connection to a remote server using a private key and list all folders in a specific directory from the server.

2. Using the JSch Library

JSch (Java Secure Channel) library provides classes to establish a connection to an SSH server. It’s a Java implementation of SSH2.

First, let’s add the JSch dependency to the pom.xml:

<dependency>
    <groupId>com.github.mwiede</groupId>
    <artifactId>jsch</artifactId>
    <version>0.2.18</version>
</dependency>

Next, let’s define our connection details to establish a connection to the remote server:

private static final String HOST = "HOST_NAME";
private static final String USER = "USERNAME";
private static final String PRIVATE_KEY = "PRIVATE_KEY";
private static final int PORT = 22;
private static final String REMOTE_DIR = "REMOTE_DIR";

Here, we define the host, the user, and the path to the authentication key. Also, we define the port and the remote directory we intend to list its folders.

Next, let’s create a JSch object and add the PRIVATE_KEY for authentication:

JSch jsch = new JSch();
jsch.addIdentity(PRIVATE_KEY);

Then, let’s create a session and connect to the remote server:

Session session = jsch.getSession(USER, HOST, PORT);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();

The Session object allows us to create a new SSH session. For simplicity, we disable strict host key checking.

Furthermore, let’s open an SFTP channel over the established SSH connection:

ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();

Here, we create a secure file transfer protocol over the established session. The ChannelSftp object allows us to upload, download, list, etc. from the remote server.

2.1. Detailed File Listing

Now that we have an open SFTP channel, let’s retrieve the list of files in the specified remote directory:

Vector<ChannelSftp.LsEntry> files = channelSftp.ls(REMOTE_DIR);
for (ChannelSftp.LsEntry entry : files) {
    LOGGER.info(entry.getLongname());
}

In the code above, we invoke the ls() method on the ChannelSftp object which returns a Vector of ChannelSftp.LsEntry object, each representing a file or directory. Then, we loop over the list of files and directories and log the long name of each file or directory. The getLongname() method includes additional details like permissions, owner, group, and size.

2.2. File Name Only

If we are interested only in the filename, we can invoke the getFilename() method on ChannelSftp.LsEntry object:

Vector<ChannelSftp.LsEntry> files = channelSftp.ls(REMOTE_DIR);
for (ChannelSftp.LsEntry entry : files) {
    LOGGER.info(entry.getFilename());
}

Notably, we must close the SSH session and SFTP channel after successful operations:

channelSftp.disconnect();
session.disconnect();

Essentially, closing connections helps free resources.

3. Using the Apache Mina SSHD Library

The Apache Mina SSHD library aims to support Java applications that intend to provide SSH protocols for both the client and server side.

We can perform several SSH operations like file transfer, deployment, etc. To use the library, let’s add sshd-core and  sshd-sftp dependencies to the pom.xml:

<dependency>
    <groupId>org.apache.sshd</groupId>
    <artifactId>sshd-core</artifactId>
    <version>2.13.1</version>
</dependency>

<dependency>
    <groupId>org.apache.sshd</groupId>
    <artifactId>sshd-sftp</artifactId>
    <version>2.13.1</version>
</dependency>

Let’s maintain the connection details used in the previous section. First, let’s start the SSH client:

try (SshClient client = SshClient.setUpDefaultClient()) {
    client.start();
    client.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE);
    // ...  
}

Next, let’s connect to the SSH server:

try (ClientSession session = client.connect(USER, HOST, PORT).verify(10000).getSession()) {
    FileKeyPairProvider fileKeyPairProvider = new FileKeyPairProvider(Paths.get(privateKey));
    Iterable<KeyPair> keyPairs = fileKeyPairProvider.loadKeys(null);
    for (KeyPair keyPair : keyPairs) {
        session.addPublicKeyIdentity(keyPair);
    }

    session.auth().verify(10000);
}

In the code above, we create a client session with our authentication credentials. Also, we use the FileKeyPairProvider object to load the private, and since our private key doesn’t require a passphrase, we pass null to the loadKeys() method.

3.1. Detailed File Listing

To list the folders on the remoter server, let’s create an SftpClientFactory object to open the SFTP channel over an already established SSH session:

SftpClientFactory factory = SftpClientFactory.instance();

Next, let’s read the remote directory and get an iterable of directory entries:

try (SftpClient sftp = factory.createSftpClient(session)) {
    Iterable<SftpClient.DirEntry> entriesIterable = sftp.readDir(REMOTE_DIR);
    List<SftpClient.DirEntry> entries = StreamSupport.stream(entriesIterable.spliterator(), false)
      .collect(Collectors.toList());
    for (SftpClient.DirEntry entry : entries) {
        LOGGER.info(entry.getLongFilename());
    }
}

Here, we read the remote directory and get an Iterable of directory entries which is converted to List. Then we log the long filename to the console. Since we use the try-with-resources block, we don’t need to close the session explicitly.

3.2. File Name Only

However, to get only the file name, we can use the getFilename() method on the directory entries instead of getLongFileName():

for (SftpClient.DirEntry entry : entries) {
    LOGGER.info(entry.getFilename());
}

The getFilename() eliminates other file information and only logs the filename.

4. Using the SSHJ Library

The SSHJ library is also a Java library that provides classes to connect and interact with a remote server. To use the library, let’s add its dependency to the pom.xml:

<dependency>
    <groupId>com.hierynomus</groupId>
    <artifactId>sshj</artifactId>
    <version>0.38.0</version>
</dependency>

Also, let’s maintain the connection details used in the previous sections.

Let’s create an SSHClient object to establish a connection to a remote server:

try (SSHClient sshClient = new SSHClient()) {
    sshClient.addHostKeyVerifier(new PromiscuousVerifier());
    sshClient.connect(HOST);
    sshClient.authPublickey(USER, PRIVATE_KEY);
    // ...
}

Then, let’s establish an SFTP channel on the established SSH session:

try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
    List<RemoteResourceInfo> files = sftpClient.ls(REMOTE_DIR);
    for (RemoteResourceInfo file : files) {
        LOGGER.info("Filename: " + file.getName());
    }
}

In the code above, we invoke the ls() which accepts the remote directory on sftpClient and stores it as RemoteResourseInfo type. Then we loop through the file entries and log the file name to the console.

Finally, we can get more details about files by using the getAttributes() method:

LOGGER.info("Permissions: " + file.getAttributes().getPermissions());
LOGGER.info("Last Modification Time: " + file.getAttributes().getMtime());

Here, we further log the file permission and modification time by invoking the getPermissions() and getMtime() methods on the getAttributes() method.

5. Conclusion

In this article, we learned how to interact with remote servers using the JSch, Apache SSHD Mina, and SSHJ libraries. Also, we saw how to establish secure connections, authenticate with private keys, and perform basic file operations.

As always, the complete source code for the examples is available over on GitHub.