I am writing a block of Java code that allows me to connect to a remote computer and execute a program on it. So far I am able to connect to the program and run it. I can see the program's output on my console. However, the program stops executing and my java code exists with exit code = 0. Here is my connect method. I call it in my main with the correct arguments.
public void listFolderStructure(String username,
String host, int port, String command) throws Exception {
Session session = null;
ChannelExec channel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(username, host, port);
session.setConfig("PreferredAuthentications", "publickey");
jsch.addIdentity("~/.ssh/id_rsa");
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
channel = (ChannelExec) session.openChannel("exec");
channel.setXForwarding(true);
channel.setCommand(command);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
channel.setOutputStream(responseStream);
channel.connect();
while (channel.isConnected()) {
Thread.sleep(100);
}
String responseString = new String(responseStream.toByteArray());
System.out.println(responseString);
} finally {
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
}
And this is part the output of the program on my console. Note: Connecting to the remote via ssh and running the program from a terminal gives the same output but the program's gui window displays on my computer and it runs as per usual
2021-04-03 20:36:42 [INFO]: Loaded plugin:
"/home/usr/adtf3.7/bin/adtf_kernel.adtfplugin" [runtime.cpp(1887)]
2021-04-03 20:36:42 [INFO]: Registered class "kernel.service.adtf.cid". ( 14 )
[runtime.cpp(2213)]
2021-04-03 20:36:42 [INFO]: Try to load
"/home/usr/adtf3.7/bin/adtf_playback.adtfplugin" [runtime.cpp(1784)]
2021-04-03 20:36:42 [INFO]: Loaded plugin:
"/home/usr/adtf3.7/bin/adtf_playback.adtfplugin" [runtime.cpp(1887)]
2021-04-03 20:36:42 [INFO]: Registered class "playback.service.adtf.cid". ( 15 ) [
Process finished with exit code 0
Is there a way to connect to the remote via Jsch and have the program's ui display as it normally would without it exiting? (code 0)
Any help would be greatly appreciated
EDIT: Thank you #Martin Prikryl; one of his suggestions helped out and I can now run the program on the remote. The only issue I'm facing now is getting the UI to display on my machine instead of the remote machine
Method that can run programs on the remote:
public void run_command(String command) throws JSchException {
String username = this.user;
String host = this.host;
int port = this.port;
JSch jsch = new JSch();
jsch.addIdentity("~/.ssh/id_rsa");
this.sshSession = jsch.getSession(username, host, port);
this.sshSession.setConfig("PreferredAuthentications", "publickey");
this.sshSession.setConfig("StrictHostKeyChecking", "no");
this.sshSession.connect();
this.sshChannel = this.sshSession.openChannel("shell");
this.sshChannel.setXForwarding(true);
ByteArrayInputStream reader = new ByteArrayInputStream(("export DISPLAY=:0; "+command + " \n").getBytes());
this.sshChannel.setInputStream(reader);
this.sshChannel.setOutputStream(System.out);
this.sshChannel.connect();
try {
Thread.sleep(1000); // give GUI time to come up
} catch (InterruptedException ex) {
// print message
}
this.sshChannel.disconnect();
}
alternatively this can be used to connect to a remote without Jsch. Extending to command however; i.e: ..this.host;gedit makes the terminal instantly dissapear.
public void open_remote_terminal() {
try {
String command ="gnome-terminal -x ssh -x "+this.user+"#"+this.host;
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}
So what I'm trying to do, is create unit test that checks if invoked command (on shell via ssh connection) has a proper response. The problem is that I can't read those responses. There are not many tutorials regarding Apache MINA, so I thought maybe some of you could help me out. Here's a code
#Before
public void setUpSSHd() {
sshd=SshServer.setUpDefaultServer();
sshd.setPort(22999);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
public boolean authenticate(String username, String password, ServerSession session) {
// TODO Auto-generated method stub
return true;
}
});
List<NamedFactory<KeyExchange>> keyExchangeFactories;
keyExchangeFactories = sshd.getKeyExchangeFactories();
sshd.setKeyExchangeFactories(keyExchangeFactories);
try {
sshd.start();
} catch (Exception e) {
e.printStackTrace();
}
}
#After
public void teardown() throws Exception { sshd.stop(); }
#Test
public void testCommands() throws Exception {
SshClient client = SshClient.setUpDefaultClient();
client.start();
ClientSession session = null;
try {
session = client.connect("localhost", 22999).await().getSession();
session.authPassword("none", "none").await().isSuccess();
System.out.println("Connection established");
final ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
ByteArrayOutputStream sent = new ByteArrayOutputStream();
PipedOutputStream pipedIn = new TeePipedOutputStream(sent);
channel.setIn(new PipedInputStream(pipedIn));
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
channel.setOut(out);
channel.setErr(err);
channel.open();
pipedIn.write("dir\r\n".getBytes());
pipedIn.flush();
channel.waitFor(ClientChannel.CLOSED, 0);
channel.close(false);
client.stop();
System.out.println(out.toString());
} catch (Exception e) {
e.printStackTrace();
fail("Cannot establish a connection");
} finally {
if (session != null)
session.close(true);
}
}
For now I simply try to print out collected response. However I get empty string everytime I try to do that. I assume there might be a problem with ssh server configuration (what shell is it supposed to use?). The best scenario would be if I could define my own commands and responses on server side and then, only check it on client side
EDIT: I've tried to manually connect to this mocked ssh server but I've got
Unable to negotiate with ::1 port 22999: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1
error message.
I would suggest you to update Apache SSH. Based the source repository the version 0.5.0 is 7 years old.
using your posted code with the default JCE provider and Apache SSH
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.5.0</version>
<dependency>
the connect with a ssh client fails with
Their offer: diffie-hellman-group1-sha1
using a more recent Apache SSH release
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>1.4.0</version>
<dependency>
the connect is successful
I am trying to execute a remote query over SSH using pubic key/private key based authentication. Following command works fine and gives me the required output as a string on a bash shell after sharing the public keys between local host and the remote server.
echo 123456 12#13:14 ABCD abc1234 | ssh -T user#abc.xyz.com
How do I achieve the same with JAVA using JSCH or SSHJ or any other similar library
This is what I have tried so far using SSHJ but it did not work for me (Connection was successful but no results)
public static void main(String... args)throws IOException {
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("abc.xyz.com");
try {
ssh.authPublickey("user");
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("123456 12#13:14 ABCD abc1234");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} finally {
session.close();
}
} finally {
ssh.disconnect();
ssh.close();
}
}
Below code uses JSCH Library and is working on my end :-
JSch jsch = new JSch();
String path = "PATH TO PRIVATE KEY";
jsch.addIdentity(path);
jsch.setConfig("StrictHostKeyChecking", "no");
Session session = jsch.getSession(userName, ipToConnect, portToConnect);
session.connect();
Channel channel = session.openChannel("exec");
((ChannelExec)channel).setCommand("COMMAND TO FIRE");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
//Read Response Here
channel.disconnect();
session.disconnect();
Note : You can use password based authentication also instead of key bases with JSCH
I am trying to establish an SSH connection through my Java code, but getting below exception .. I tested my connection through Putty/Winscp tools and it works fine. The problem is with my Java code...
SEVERE: The Transport Protocol thread failed
java.io.IOException: The socket is EOF
at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readBufferedData(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readMessage(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.readMessage(Unknown Source)
at com.sshtools.j2ssh.transport.kex.DhGroup1Sha1.performClientExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolClient.performKeyExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.onMsgKexInit(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Below is my piece of Java code to establish the connection
public class MySSHClient {
static SshClient ssh = null;
static SshConnectionProperties properties = null;
SessionChannelClient session = null;
private static void MySSHClient(String hostName, String userName, String passwd )
{
try
{
// Make a client connection
ssh = new SshClient();
properties = new SshConnectionProperties();
properties.setHost("192.168.1.175");
// Connect to the host
ssh.connect(properties, new IgnoreHostKeyVerification());
// Create a password authentication instance
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
pwd.setUsername("root");
pwd.setPassword("123456");
// Try the authentication
int result = ssh.authenticate(pwd);
// Evaluate the result
if (result==AuthenticationProtocolState.COMPLETE) {
System.out.println("Connection Authenticated");
}
}
catch(Exception e)
{
System.out.println("Exception : " + e.getMessage());
}
}//end of method.
public String execCmd(String cmd)
{
String theOutput = "";
try
{
// The connection is authenticated we can now do some real work!
session = ssh.openSessionChannel();
if ( session.executeCommand(cmd) )
{
IOStreamConnector output = new IOStreamConnector();
java.io.ByteArrayOutputStream bos = new
java.io.ByteArrayOutputStream();
output.connect(session.getInputStream(), bos );
session.getState().waitForState(ChannelState.CHANNEL_CLOSED);
theOutput = bos.toString();
}
//else
//throw Exception("Failed to execute command : " + cmd);
//System.out.println("Failed to execute command : " + cmd);
}
catch(Exception e)
{
System.out.println("Exception : " + e.getMessage());
}
return theOutput;
}
public static void main(String[] args){
MySSHClient(null, null, null);
}
Motivation
I stumbled across this question and answers while investigating the error in question java.io.IOException: The socket is EOF. Because changing the code to use some other SSH Java library is not immediately possible in my case and the stated explanation by #a3.14_Infinity was not detailed enough for me, I'd like to add my take on it.
java.io.IOException: The socket is EOF - Why?
Because this exception is not very helpful, I first tried Wireshark to see what's going on over the wire, but to no avail. So I configured the sshd_config (OpenSSH 6.9) to log on DEBUG3 level and got the answer in the /var/log/auth.log file of my test machine. It stated a fatal error while trying to negotiate the key exchange algorithm with the SSH client (the Java SSH library).
Because the SSH server and client could not agree on a mutual key exchange algorithm the OpenSSH server terminates the connection to the client. In consequence, the Java SSH library code throws the exception.
But why does it happen?
The sshtools.j2ssh (sshtools : j2ssh-core : 0.2.9) library code is pretty old and discontinued. Starting with OpenSSH 6.7 (released October, 2014) default ciphers and MAC have been altered to remove unsafe algorithms which includes the blowfish-cbc cipher. And with OpenSSH 6.9 (released June, 2015) the support for the 1024-bit diffie-hellman-group1-sha1 key exchange is disabled by default.
When you still use the prehistoric SSH Tools j2ssh library (God forbid) connecting to a newer OpenSSH server you will get the described error. The library code only offers the diffie-hellman-group1-sha1 key exchange algorithm to the OpenSSH server which it does not support by default. Thus, a secure connection cannot be established.
Cannot change the code?
If moving to another Java SSH library is not immediately possible (my case) then you can re-enable the disabled diffie-hellman-group1-sha1 key exchange algorithm in the OpenSSH's server config file sshd_config. For example like this.
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm#openssh.com,aes256-gcm#openssh.com,chacha20-poly1305#openssh.com,blowfish-cbc
KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1,curve25519-sha256#libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1
But let me be clear on this. The diffie-hellman-group1-sha1 key exchange algorithm as well as the blowfish-cbc cipher are turned off by default because they are insecure. Reenabling them should only be a temporary measure until you can replace this obsolete Java SSH library.
Finally, I like to point out that the suggested Java Secure Channel (JSch) library in other answers is discontinued. So, you might want to consider sshj or even ssh2j-maverick instead.
Edit: I was wrong, the Java Secure Channel JSch library is alive (JSCH 0.1.54 was released on 2016-09-03 on MavenCentral) and certainly worth your consideration. Alternatively, you may want to consider also sshj or ssh2j-maverick.
Addendum: Migration
To keep the migration effort for the sshtools.j2ssh (sshtools : j2ssh-core : 0.2.9) library minimal I looked at the commercial legacy SSH client library from SSHTOOLS (version 1.7.1). This allowed to keep the existing library integration code with few minor changes regarding library API and exception handling. Thus, if you do not want to restart from scratch then biting the bullet and sticking with SSHTOOLS is probably your best option. Finally, to gauge the migration effort I first replaced the library with SSHTOOLS' open source library ssh2j-maverick which almost has the same API as its latest commercial version (version 1.7.1).
This error ("The Transport Protocol thread failed. java.io.IOException: The socket is EOF”) occurs when j2ssh.jar file is not compatible with current SSH version of SFTP server.
You can try using Java Secure Channel (JSch) from here.
Courtesy: http://techydiary.com/the-transport-protocol-thread-failed-java-io-ioexception-the-socket-is-eof/
The following sample Code may help you,
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SSHClient {
/**
* Constant EXCUTE_CHANNEL
*/
public static final String EXCUTE_CHANNEL = "exec";
/**
* Constant STRICT_KEY_CHECKING
*/
public static final String STRICT_KEY_CHECKING = "StrictHostKeyChecking";
/** Name/ip of the remote machine/device **/
private String host;
private String userName;
private String password;
/**
* This method used to initilze user and host
*
* #param userName
* #param password
* #param host
*/
public SSHClient(String userName,String password, String host) {
super();
this.userName = userName;
this.password = password;
this.host = host;
}
/**
* This method used to execute commands remotly by using SSHV2
*
* #param host
* #param username
* #param password
* #param command
* #return
*/
public String executeCommand(String command) {
StringBuilder log = new StringBuilder();
String response = null;
Channel channel = null;
Session session = null;
try {
JSch jsch = new JSch();
JSch.setConfig(STRICT_KEY_CHECKING, Constants.NO);
session = jsch.getSession(userName, host, 22);
// If two machines have SSH passwordless logins setup, the following
// line is not needed:
session.setPassword(password);
session.connect();
channel = session.openChannel(EXCUTE_CHANNEL);
((ChannelExec) channel).setCommand(command);
// channel.setInputStream(System.in);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
response = IOUtils.toString(in);
} catch (Exception ex) {
//handle exception
} finally {
try {
if (session != null) {
session.disconnect();
}
} catch (Exception ex) {
//handle exception
}
try {
if (channel != null) {
channel.disconnect();
}
} catch (Exception ex) {
//handle exception
}
}
System.ou.println( "Response received :"+ response));
return response;
}
}
Here is the working code reused from some google source -
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.StreamGobbler;
Connection conn = new Connection(server);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user_id, password);
System.out.println("Is server - " + server + " Authenticated? " + isAuthenticated);
if (isAuthenticated == false)
throw new IOException("Authentication failed.");
ch.ethz.ssh2.Session sess = conn.openSession();
String new_commands = "";
for (int i = 0; i < commands.size(); i++) {
new_commands = new_commands + commands.get(i) + "\n";
}
System.out.println("The command executed is: " + new_commands);
sess.requestDumbPTY();
sess.execCommand(new_commands);
InputStream stdout = new StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
InputStream errStrm = new StreamGobbler(sess.getStderr());
BufferedReader stderrRdr = new BufferedReader(new InputStreamReader(errStrm));
sess.getStdin().write("EXIT\n".getBytes());
System.out.println("the output of the command is");
while (true) {
String line_out = br.readLine();
if (line_out == null) {
break;
} else {
System.out.println(line_out);
output_logs.add(line_out);
}
}
while (true) {
String line_error = stderrRdr.readLine();
if (line_error == null) {
break;
} else {
System.out.println(line_error);
output_logs.add(line_error);
}
}
output_logs.add("Exit Code:" + sess.getExitStatus());
System.out.println("ExitCode: " + sess.getExitSignal());
sess.close();
conn.close();
found a simple solution on the OS:
comment out the Cipher line in /etc/ssh/sshd_config
and run service sshd restart
What is the best method of performing an scp transfer via the Java programming language? It seems I may be able to perform this via JSSE, JSch or the bouncy castle java libraries. None of these solutions seem to have an easy answer.
I ended up using Jsch- it was pretty straightforward, and seemed to scale up pretty well (I was grabbing a few thousand files every few minutes).
plug: sshj is the only sane choice! See these examples to get started: download, upload.
Take a look here
That is the source code for Ants' SCP task. The code in the "execute" method is where the nuts and bolts of it are. This should give you a fair idea of what is required. It uses JSch i believe.
Alternatively you could also directly execute this Ant task from your java code.
I wrapped Jsch with some utility methods to make it a bit friendlier and called it
Jscp
Available here: https://github.com/willwarren/jscp
SCP utility to tar a folder, zip it, and scp it somewhere, then unzip it.
Usage:
// create secure context
SecureContext context = new SecureContext("userName", "localhost");
// set optional security configurations.
context.setTrustAllHosts(true);
context.setPrivateKeyFile(new File("private/key"));
// Console requires JDK 1.7
// System.out.println("enter password:");
// context.setPassword(System.console().readPassword());
Jscp.exec(context,
"src/dir",
"destination/path",
// regex ignore list
Arrays.asList("logs/log[0-9]*.txt",
"backups")
);
Also includes useful classes - Scp and Exec, and a TarAndGzip, which work in pretty much the same way.
This is high-level solution, no need to reinvent. Quick and dirty!
1) First, go to http://ant.apache.org/bindownload.cgi and download latest Apache Ant binary. (nowadays, apache-ant-1.9.4-bin.zip).
2) Extract the downloaded file and find the JAR ant-jsch.jar ("apache-ant-1.9.4/lib/ant-jsch.jar"). Add this JAR in your project. Also ant-launcher.jar and ant.jar.
3) Go to Jcraft jsch SouceForge Project and download the jar. Nowadays, jsch-0.1.52.jar. Also Add this JAR in your project.
Now, can you easyly use into java code the Ant Classes Scp for copy files over network or SSHExec for commands in SSH servers.
4) Code Example Scp:
// This make scp copy of
// one local file to remote dir
org.apache.tools.ant.taskdefs.optional.ssh.Scp scp = new Scp();
int portSSH = 22;
String srvrSSH = "ssh.your.domain";
String userSSH = "anyuser";
String pswdSSH = new String ( jPasswordField1.getPassword() );
String localFile = "C:\\localfile.txt";
String remoteDir = "/uploads/";
scp.setPort( portSSH );
scp.setLocalFile( localFile );
scp.setTodir( userSSH + ":" + pswdSSH + "#" + srvrSSH + ":" + remoteDir );
scp.setProject( new Project() );
scp.setTrust( true );
scp.execute();
Here is an example to upload a file using JSch:
ScpUploader.java:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import java.io.ByteArrayInputStream;
import java.util.Properties;
public final class ScpUploader
{
public static ScpUploader newInstance()
{
return new ScpUploader();
}
private volatile Session session;
private volatile ChannelSftp channel;
private ScpUploader(){}
public synchronized void connect(String host, int port, String username, String password) throws JSchException
{
JSch jsch = new JSch();
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session = jsch.getSession(username, host, port);
session.setPassword(password);
session.setConfig(config);
session.setInputStream(System.in);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
}
public synchronized void uploadFile(String directoryPath, String fileName, byte[] fileBytes, boolean overwrite) throws SftpException
{
if(session == null || channel == null)
{
System.err.println("No open session!");
return;
}
// a workaround to check if the directory exists. Otherwise, create it
channel.cd("/");
String[] directories = directoryPath.split("/");
for(String directory : directories)
{
if(directory.length() > 0)
{
try
{
channel.cd(directory);
}
catch(SftpException e)
{
// swallowed exception
System.out.println("The directory (" + directory + ") seems to be not exist. We will try to create it.");
try
{
channel.mkdir(directory);
channel.cd(directory);
System.out.println("The directory (" + directory + ") is created successfully!");
}
catch(SftpException e1)
{
System.err.println("The directory (" + directory + ") is failed to be created!");
e1.printStackTrace();
return;
}
}
}
}
channel.put(new ByteArrayInputStream(fileBytes), directoryPath + "/" + fileName, overwrite ? ChannelSftp.OVERWRITE : ChannelSftp.RESUME);
}
public synchronized void disconnect()
{
if(session == null || channel == null)
{
System.err.println("No open session!");
return;
}
channel.exit();
channel.disconnect();
session.disconnect();
channel = null;
session = null;
}
}
AppEntryPoint.java:
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public final class AppEntryPoint
{
private static final String HOST = "192.168.1.1";
private static final int PORT = 22;
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
public static void main(String[] args) throws IOException
{
ScpUploader scpUploader = ScpUploader.newInstance();
try
{
scpUploader.connect(HOST, PORT, USERNAME, PASSWORD);
}
catch(JSchException e)
{
System.err.println("Failed to connect the server!");
e.printStackTrace();
return;
}
System.out.println("Successfully connected to the server!");
byte[] fileBytes = Files.readAllBytes(Paths.get("C:/file.zip"));
try
{
scpUploader.uploadFile("/test/files", "file.zip", fileBytes, true); // if overwrite == false, it won't throw exception if the file exists
System.out.println("Successfully uploaded the file!");
}
catch(SftpException e)
{
System.err.println("Failed to upload the file!");
e.printStackTrace();
}
scpUploader.disconnect();
}
}
The openssh project lists several Java alternatives, Trilead SSH for Java seems to fit what you're asking for.
I use this SFTP API which has SCP called Zehon, it's great, so easy to use with a lot of sample code. Here is the site http://www.zehon.com
I looked at a lot of these solutions and didn't like many of them. Mostly because the annoying step of having to identify your known hosts. That and JSCH is at a ridiculously low level relative to the scp command.
I found a library that doesn't require this but it's bundled up and used as a command line tool. https://code.google.com/p/scp-java-client/
I looked through the source code and discovered how to use it without the command line. Here's an example of uploading:
uk.co.marcoratto.scp.SCP scp = new uk.co.marcoratto.scp.SCP(new uk.co.marcoratto.scp.listeners.SCPListenerPrintStream());
scp.setUsername("root");
scp.setPassword("blah");
scp.setTrust(true);
scp.setFromUri(file.getAbsolutePath());
scp.setToUri("root#host:/path/on/remote");
scp.execute();
The biggest downside is that it's not in a maven repo (that I could find). But, the ease of use is worth it to me.
jsCH has worked great for me. Below is an example of a method that will connect to sftp server and download files to specified directory. It is recommended to stay away from disabling StrictHostKeyChecking. Although a little bit more difficult to set up, for security reasons specifying the known hosts should be the norm.
jsch.setKnownHosts("C:\Users\test\known_hosts"); recommended
JSch.setConfig("StrictHostKeyChecking", "no"); - not recommended
import com.jcraft.jsch.*;
public void downloadFtp(String userName, String password, String host, int port, String path) {
Session session = null;
Channel channel = null;
try {
JSch ssh = new JSch();
JSch.setConfig("StrictHostKeyChecking", "no");
session = ssh.getSession(userName, host, port);
session.setPassword(password);
session.connect();
channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftp = (ChannelSftp) channel;
sftp.get(path, "specify path to where you want the files to be output");
} catch (JSchException e) {
System.out.println(userName);
e.printStackTrace();
} catch (SftpException e) {
System.out.println(userName);
e.printStackTrace();
} finally {
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
Like some here, I ended up writing a wrapper around the JSch library.
It's called way-secshell and it is hosted on GitHub:
https://github.com/objectos/way-secshell
// scp myfile.txt localhost:/tmp
File file = new File("myfile.txt");
Scp res = WaySSH.scp()
.file(file)
.toHost("localhost")
.at("/tmp")
.send();
JSch is a nice library to work with. It has quite an easy answer for your question.
JSch jsch=new JSch();
Session session=jsch.getSession(user, host, 22);
session.setPassword("password");
Properties config = new Properties();
config.put("StrictHostKeyChecking","no");
session.setConfig(config);
session.connect();
boolean ptimestamp = true;
// exec 'scp -t rfile' remotely
String command="scp " + (ptimestamp ? "-p" :"") +" -t "+rfile;
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
// get I/O streams for remote scp
OutputStream out=channel.getOutputStream();
InputStream in=channel.getInputStream();
channel.connect();
if(checkAck(in)!=0){
System.exit(0);
}
File _lfile = new File(lfile);
if(ptimestamp){
command="T "+(_lfile.lastModified()/1000)+" 0";
// The access time should be sent here,
// but it is not accessible with JavaAPI ;-<
command+=(" "+(_lfile.lastModified()/1000)+" 0\n");
out.write(command.getBytes()); out.flush();
if(checkAck(in)!=0){
System.exit(0);
}
}
You can find complete code at
http://faisalbhagat.blogspot.com/2013/09/java-uploading-file-remotely-via-scp.html
-: Refining Fernando's answer a little, if you use Maven for dependency management :-
pom.xml:
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>${ant-jsch.version}</version>
</dependency>
Add this dependency in your project. Latest version can be found here.
Java code:
public void scpUpload(String source, String destination) {
Scp scp = new Scp();
scp.setPort(port);
scp.setLocalFile(source);
scp.setTodir(username + ":" + password + "#" + host + ":" + destination);
scp.setProject(new Project());
scp.setTrust(true);
scp.execute();
}
I wrote an scp server which is much easier than others. I use Apache MINA project (Apache SSHD) to develop it. You can take a look here: https://github.com/boomz/JSCP
Also you can download the jar file from /jar directory.
How to use? Take a look on: https://github.com/boomz/JSCP/blob/master/src/Main.java
I need to copy folder recursively, after trying different solutions, finally end up by ProcessBuilder + expect/spawn
scpFile("192.168.1.1", "root","password","/tmp/1","/tmp");
public void scpFile(String host, String username, String password, String src, String dest) throws Exception {
String[] scpCmd = new String[]{"expect", "-c", String.format("spawn scp -r %s %s#%s:%s\n", src, username, host, dest) +
"expect \"?assword:\"\n" +
String.format("send \"%s\\r\"\n", password) +
"expect eof"};
ProcessBuilder pb = new ProcessBuilder(scpCmd);
System.out.println("Run shell command: " + Arrays.toString(scpCmd));
Process process = pb.start();
int errCode = process.waitFor();
System.out.println("Echo command executed, any errors? " + (errCode == 0 ? "No" : "Yes"));
System.out.println("Echo Output:\n" + output(process.getInputStream()));
if(errCode != 0) throw new Exception();
}