Remote Session is a small collection of utility classes for interacting with remote systems via Secure Shell (SSH) protocol. Built around the JSch library from JCraft, available functions include:
- Secure file transfer
- Remote interactive shell
- Remote command execution
Remote Session wraps the capabilities of JSch in a simplified API that handles many of the details related to setting up and managing remote sessions. Originated by Mykhaylo Adamovych, the implementation was copied verbatim from a post on Stack Overflow. JavaDoc has been added for completeness and comprehensibility.
The last release of the JSch library from the original SourceForge project was published 2018-NOV-26. Continuing development of this project has been taken up by Matthias Wiedemann here, with new releases published at these artifact coordinates:
Maven |
---|
<dependency> |
Gradle |
---|
dependencies { |
This new incarnation of the JSch project is a drop-in replacement for artifacts published from the original project. However, support for older or deprecated algorithms is disabled by default. Information on compatibility and configuration can be found on the project's README page.
Remote Session enables clients to upload and download files via secure file transfer protocol (SFTP).
SshUtils.sftp("file:/C:/home/file.txt", "ssh://user:pass@host/home");
SshUtils.sftp("ssh://user:pass@host/home/file.txt", "file:/C:/home");
NOTE: The transferred file retains its original name. If specified, the name component of toUrl
will be ignored.
NOTE: As indicated by the examples, source and target URIs must refer to opposing locations: file
for local file system and ssh
for remote file system.
- For upload: fromUri =
file
; toUri =ssh
- For download: fromUri =
ssh
; toUri =file
Remote Session supports interacting with remote systems via a secure shell
channel, in which input and output are streamed between local and remote systems. Each of the three methods provided for secure shell interaction exhibit different operational characteristics.
import com.nordstrom.remote.SshUtils;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
...
public void example() {
InputStream is = System.in;
OutputStream os = System.out;
SshUtils.shell("ssh://user:pass@host", is, os);
PrintStream ps = new PrintStream(is, true);
ps.println("ls -la");
ps.println("exit");
System.out.println(IOUtils.toString(os, Charset.defaultCharset()));
}
With unbounded stream I/O, the channel remains open until the input stream is closed or an exit
command is submitted.
String remoteOutput = SshUtils.shell("ssh://user:pass@host/work/dir/path", "ls");
From the client perspective, this is effectively equivalent to exec(String, String)
. The primary difference is the channel used for communication (shell
instead of exec
).
import com.nordstrom.remote.SshUtils;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
...
public void example() {
OutputStream os = System.out;
SshUtils.shell("ssh://user:pass@host", "ls -la", os);
System.out.println(IOUtils.toString(os, Charset.defaultCharset()));
}
This is essentially a hybrid of the previous two secure-shell methods, well-suited for long-running commands that you'd like to leave running while you handle other tasks.
Remote Session enables you to submit commands to remote systems atomically. Instead of submitting commands through an input stream, you specify each command as a property of the channel and execute it.
System.out.println(SshUtils.exec("ssh://user:pass@host/work/dir/path", "ls -t | head -n1"));
import java.net.URI;
import com.nordstrom.remote.SshUtils.SessionHolder;
import com.nordstrom.remote.SshUtils.ChannelType;
import com.jcraft.jsch.ChannelExec;
...
public void example() {
String connectUri = "ssh://user:pass@host/work/dir/path";
String command = "ls -t | head -n1";
try (SessionHolder<ChannelExec> session = new SessionHolder<>(ChannelType.EXEC, URI.create(connectUri))) {
String workDir = session.getWorkDir();
if (workDir != null) command = "cd " + workDir + " && " + command;
System.out.println(session, command);
}
}
BatchUtils is a reference implementation of a JSch client. It enables you to execute the specified command, optionally executing an initial command to switch to an alternate user first.
String userName = "user";
String password = "password";
String hostName = "host";
String sudoCmd = "sudo su - admin";
String batchDir = "/work/dir/path";
String batchCmd = "./script.ksh parm1 parm2";
String output = BatchUtils.executeBatch(userName, password, hostName, sudoCmd, batchDir, batchCmd);
System.out.println(output);
The implementation of BatchUtils
demonstrates how to use a couple of important Remote Session classes:
SessionHolder
- This is a wrapper class for objects that extend theChannel
class. The wrapper implements theCloseable
interface, andBatchUtils
uses a "try-with-resources" block to ensure that the channel is always closed regardless of the outcome of command execution.SessionHolder
includes these methods (among others):getChannel
- Get the channel to the remote session created for thisSessionHolder
.getChannelStream
- Get a new channel stream object for this session.disconnect
- Disconnect channel and session.assertExitStatus
- Verifies that the remote task completed normally.
ChannelStreams
- This class encapsulates input/output operation for the channel attached to this session. It includes these methods:waitForInput
- Wait for input to be available.writeln
- Write the specified string to the remote host, followed by a carriage return.waitForPrompt
- Wait for the specified prompt to be received from the remote host.readChannel
- Read the input from the channel.
Remote Session provides a number of important settings that can be configured through system properties or a corresponding properties
file (remote.properties). The library provides default values for all settings in the RemoteConfig class.
Setting | Property Name | Default |
---|---|---|
SSH_KEY_NAME |
remote.ssh.key.name |
id_rsa |
SSH_KEY_PASS |
remote.ssh.key.pass |
(none) |
IGNORE_KNOWN_HOSTS |
remote.ignore.known.hosts |
false |
SESSION_CONNECT_TIMEOUT |
remote.session.connect.timeout |
5000 |
SSH_PORT_NUMBER |
remote.ssh.port.number |
22 |
TERMINAL_HEIGHT |
remote.terminal.height |
24 |
TERMINAL_WIDTH |
remote.terminal.width |
132 |
TERMINAL_H_RESOLUTION |
remote.terminal.h.resolution |
924 |
TERMINAL_V_RESOLUTION |
remote.terminal.v.resolution |
216 |
COMPLETION_CHECK_INTERVAL |
remote.completion.check.interval |
100 |
DISCONNECT_CHECK_ATTEMPTS |
remote.disconnect.check.attempts |
600 |
DISCONNECT_CHECK_INTERVAL |
remote.disconnect.check.interval |
100 |
CHANNEL_CHECK_INTERVAL |
remote.channel.check.interval |
100 |
CHANNEL_BUFFER_SIZE |
remote.channel.buffer.size |
102400 |
The SSH_KEY_NAME
setting specifies the path to an SSH key file for authentication to the remote host. If the key file is specified by full path, this is used as-is. Otherwise, the key file must be located in the .ssh folder of the active user's HOME directory. If the key file is encrypted, you must provide the decryption passphrase in the SSH_KEY_PASS
setting. This also implies the presence of a corresponding pub
file in the same folder as the key file.
If a known_hosts file is stored in the same folder as the SSH key file(s), this known_hosts file will be supplied to JSch as your personal Certificate Authority. The IGNORE_KNOWN_HOSTS
setting specifies that this known_hosts file should be ignored.
NOTE: If credentials are specified in the remote host URL, the
SSH_KEY_NAME
andSSH_KEY_PASS
settings are ignored. Also, no attempt is made to locate a known_hosts file for JSch.
The SESSION_CONNECT_TIMEOUT
setting is the interval in milliseconds that JSch will wait for socket connection operations to complete. If this value is set to 0
, no timeout will be established.
The COMPLETION_CHECK_INTERVAL
setting is the interval in milliseconds between END-OF-FILE checks for remote command execution.
The DISCONNECT_CHECK_INTERVAL
setting in the interval in milliseconds between checks for the closure of the remote session channel.
The CHANNEL_CHECK_INTERVAL
setting is the interval in millisecinds between checks for available input from the remote session channel.