-- RyanBarrett - 06 Jan 2022 ---+

Using Jsch for SFTP in Java

SSH File Transfer Protocol (also known as Secure File Transfer Protocol or SFTP) is a network protocol to handle file access, file transfer, and file management that relies on SSH. It works by creating a secure connection with a server or file system which it then uses during its operations, providing a greater level of security. Although SFTP may not come up as frequently in testing scenarios compared to other components, the functionality provided by SFTP can often be valuable when working with and testing applications that involve a file system on a server.

Prerequisites

There are several libraries that handle performing SFTP operations in Java. This tutorial focuses on the Jsch library, which can be added to the project via Maven. You'll need to add the following dependency to the dependencies in your pom.xml file after setting up your project.

You will also want to have an IDE for java development.

<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
 <groupId>com.jcraft</groupId>
 <artifactId>jsch</artifactId>
 <version>0.1.55</version>
</dependency>

From there, you can begin exploring the different operations for SFTP offered by Jsch.

Operations

There are several different operations for Jsch; this tutorial will mostly focus on connections, uploads, and downloads, as these have typically proven the most relevant in testing that required use of SFTP. Look at the examples below for reference on how to perform different SFTP operations using Jsch.

Connecting to a File System

To connect to a file system, you will need to authenticate using either a username and password or a public key. The example below uses password authentication. You will also need known_hosts file, which can be generated with the command "ssh-keyscan -H -t rsa REMOTE_HOSTNAME >> known_hosts".
private ChannelSftp getJschSFTPConnection(String knownHostsPath, String username, String remoteHost, String password) throws JSchException { 
    JSch jsch = new JSch(); 
    jsch.setKnownHosts(knownHostsPath);  //The known hosts file is used as a reference to determine if the server can be trusted generated on command line with ssh-keyscan -H -t rsa REMOTE_HOSTNAME >> known_hosts
    Session session = jsch.getSession(username, remoteHost);  //Create session
    session.setConfig("PreferredAuthentications", "publickey,keyboard-interactive,password"); //Set session config ->used to avoid having to authenticate manually (Kerberos, etc.)
    session.setPassword(password); //Set the password
    session.connect();  //Connect and open SFTP channel
    return (ChannelSftp) session.openChannel("sftp"); 
}

Once you have an SFTP connection available via JSCH, you can begin performing different SFTP operations using Jsch. You'll be able to use the following command to generate a channel for SFTP commands. All later operations need to be done using an SFTP channel with an active connection.

ChannelSftp channelSftp = getJschSFTPConnection(String knownHostsPath, String username, String remoteHost, String password)
channelSftp.connect();

The connection can later be terminated via the following method.

channelSftp.exit();

Uploading a File

To upload a file, a user will need a path to the local file to upload and a path to a location on the directory to place the file in. Consider the example below:

String localFile = "src/test/resources/TC01.txt"; 
String remoteDir = "sftp_test/"; 
channelSftp.put(localFile, remoteDir + "test.txt"); //put() method used to upload files

Note that a new file name will need to be included in the remote directory path when the file is uploaded using the put method..

Downloading a File

To download a file, you will need a remote file path and a local file path as parameters. In this case, the file in the location given via the remote path will be downloaded to the given local file path.

String remoteFile = "sftp_test_results/data.txt"; 
String localDir = "src/main/resources/"; 
channelSftp.get(remoteFile, localDir + "result.txt"); //File is downloaded using the get() method

Note that a new file name will need to be included in the local directory path when the file is uploaded using the get method.

Moving a File

To move or rename a file on the server, you will need to include both the old and new file paths as parameters for the rename() method, which will be used to locate, move, and rename the file/directory.
String oldFilePath = "sftp_test_results/data.txt";
String newFilePath = "old_sftp_results/old_data.txt";
channelSftp.rename(oldFilePath, newFilePath);

Deleting a File

The rm() and rmdir() methods can be used to remove files and directories from a server respectively. See the examples below.
String file = "junk.txt";
String directory = "unused_directory";
channelSftp.rm(file); //Removes junk.txt
channelSftp.rmdir(directory); Removes directory named unused_directory

Checking for a File

Jsch does not come with a built in utility for directly checking whether or not a file exists, but certain methods, such as ls() and stat(), can be used in methods to determine whether or not a file exists. Consider the basic example below.

String psth = "test.txt"
SftpATTRS attrs=null; try { attrs = channelSftp.stat(path); //Try to get file attributes } catch (Exception e) { System.out.println(path+" not found"); //If it fails, catch exception and continue } if (attrs != null) { System.out.println("File exists"); //If attributes is not null, then file was successfully found
return true; } else { return false; //Otherwise, file was not found in expected location }

Resources

Here are some additional helpful resources for using Jsch.
Topic revision: r1 - 06 Jan 2022, RyanBarrett
© 2020 Ultranauts - 75 Broad Street, 2nd Floor, Suite 206, New York, NY 10004 - info@ultranauts.co