Java - Perform a FTP command through a SSH tunnel with JSch - java

I am developing a Java tool which uploads a file from one remote server to another.
The program will run on a laptop. The software needs to connect to serverA with SSH protocol then once it is connected to serverA, it has to transfer files to serverB through FTP.
Files to be transfered are hosted on serverA.
I cannot directly connect to serverB because of a firewall.
Here is a summary:
Is it possible to do that with JSch? Something like the following:
JSch client = new JSch();
Session session = client.getSession("login", "serverA", 22);
// test purpose
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword("password");
session.connect();
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("ftp -i ftp://username:password#serverB; put file.txt; close; quit;");
EDIT
What about writing a script and upload it on the serverA?
#!/bin/sh
ftp -n -i <<ENDOFINPUT
open serverB
user root password
cd /home/root
put xxx
close
bye
ENDOFINPUT

Related

How to copy file from one Channel to another using Jsch? [duplicate]

I need to program a file transfer using JSch library. I have a simple directory with two folders -
In the SFTP_1 folder, I have a bitmap image. And the SFTP_2 folder is just an empty folder. My goal is to transfer the image using SFTP from SFTP_1 to SFTP_2 .
Here is my code thus far :
FileTransfer fileTransfer = new FileTransfer();
JSch jsch = new JSch();
String host = "127.0.0.1";
int port = 22;
String user = "user";
Session session = jsch.getSession(user, host, port);
session = jsch.getSession("username", "127.0.0.1", 22);
session.connect();
ChannelSftp sftp = null;
sftp = (ChannelSftp)session.openChannel("sftp") ; //channel;
sftp.rename(
"C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_1\\house.bmp",
"C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_2\\house.bmp");
session.disconnect();
What I would like to do is to simply transfer a file from one directory in my machine, to another directory. any tips appreciated, thanks !
Note that to copy between two folders, one doesn't need to use SFTP. One can copy from one folder to another without involving the SFTP protocol which is primarly used to copy files remotely, either from the local machine to a remote machine, or from a remote machine to (the same or a different) remote machine, or from the remote machine to the local machine.
That's because the FTP is a network based protocol. So using it (or any of it's related protocols) is going to use the network (or a simulated network).
The security that JSch provides is security designed to protect from certain kinds of attacks that occur on networks. It will not provide any extra security within the machine.
To copy files between folders on a single machine, the simplest way to do so is not to use JSch, like so
private static void copyFileUsingJava7Files(File source, File dest)
throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
There are other techniques, and if you really want to use JSch, you need to realize that JSch must be provided a lot of "extra" information to connect to the machine you are on, because it will try to connect to this machine as if it were connecting from across the network
Session sessionRead = jsch.getSession("username", "127.0.0.1", 22);
sessionRead.connect();
Session sessionWrite = jsch.getSession("username", "127.0.0.1", 22);
sessionWrite.connect();
ChannelSftp channelRead = (ChannelSftp)sessionRead.openChannel("sftp");
channelRead.connect();
ChannelSftp channelWrite = (ChannelSftp)sessionWrite.openChannel("sftp");
channelWrite.connect();
PipedInputStream pin = new PipedInputStream(2048);
PipedOutputStream pout = new PipedOutputStream(pin);
channelRead.get("/path/to/your/file/including/filename.txt", pout);
channelWrite.put(pin, "/path/to/your/file/destination/including/filename.txt");
channelRead.disconnect();
channelWrite.disconnect();
sessionRead.disconnect();
sessionWrite.disconnect();
The above code lacks error checking, exception handling, and fall back routines for if files are missing, networks are not up, etc. But you should get the main idea.
It should also be obvious that using a network protocol where no network protocol needs to exist opens the door to a lot more failure scenarios. Only use the SFTP method if your program is soon meant to copy files that are not both located on your machine.
Actually JSch is designed for remote work, and file system modification is one of the type such work. #Edwin Buck answer uses network for coping between local folders on remote host. There is better approach:
session.connect();
ChannelExec exec = (ChannelExec) session.openChannel("exec");
exec.setCommand("cp a.out b.out");
exec.connect();
I have no windows on the hand, as result my sample is for unix. But the idea is simple: execute copy command on the remote host.
If the original poster is actually looking for a working example of JSch in action between two distinct FTP sites, here goes:
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
...
JSch jsch = new JSch();
JSch session = null;
try {
session = jsch.getSession(userid, sourceservername, sourceserverport);
session.setPassword(sourceserverpassword);
Properties props = new Properties();
props.put("StrictHostKeyChecking", "no");
session.setConfig(props);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChanelSftp channelsftp = (ChannelSftp) channel;
channelsftp.cd(sourcefilepath);
channelsftp.lcd(localfilepath);
FileOutputStream fos = new FileOutputStream(new File(localfilepath + "/" + localfilename));
channelsftp.get(sourcefilename, fos);
fos.flush();
fos.close();
channelsftp.disconnect()
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
In practice you might break up these actions into separate try{}catch(){} blocked statements so as to introduce more granular error reporting, as well as add any informational output lines to inform the user of status, etc. But this'll get you there. Admittedly while the JSch examples are better than most such examples from freeware libraries, even good ones like this one, there can be some omissions among them around details that can make or break your attempt to get the things to work. Hope this helps if not the original poster, then someone else looking for a working JSch example. Once you have it working, it does go like a charm, so it's worth the trouble.
A core SFTP protocol does not support duplicating remote files.
There's a draft of copy-file extension to the protocol, but that's supported by only few SFTP servers (ProFTPD mod_sftp and Bitvise SFTP server for example).
In the most widespread OpenSSH SFTP server it is supported only by very recent version 9.0.
And it's also not supported by the JSch library.
See also my answer to How can I copy/duplicate a file to another directory using SFTP?
So actually using the cp shell command over an "exec" channel (ChannelExec) is unfortunately the best available approach (assuming you connect to a *nix server and you have a shell access).
If you do not have a shell access, then your only option is indeed to download the file to a local temporary folder and upload it back to the new location (or use streams, to avoid a temporary file). This is what the accepted answer by #Edwin Buck shows.

JSch create a embed ssh connection but ServerAliveInterval not works

I want use JSch as a common shell interactive tool, it's really useful.
I want create a ssh which is inner JSch channel shell and the shell's InputStream and OutStream is maintained by myself.
The problem is when I send a command string, ssh -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o StrictHostKeyChecking=no -o ConnectTimeout=10 -T root#xxx.xxx.xxx.xxx -p 22, to OutputStream to setting a keep-live by ServerAliveInterval but it not works at all.the new channel will hold 1 min when I close network.This time is more over my config ServerAliveInterval=5 ServerAliveCountMax=2.
Is JSch support inner ssh connection setting to handle keep-alive check, such as ServerAliveInterval?
UPDATE
some step to describe the question:
1. create a shell channel use JSch to login host1
2. use the channel jump to host2 by send a command ssh -o ServerAliveInterval=5 -o ServerAliveCountMax=2 root#xxx.xxx.xxx.xxx -p 22 which is a byte stream. The new ssh is config with ServerAliveInterval to check ssh network status of host2.
JSch can recognize host1 is disconnect if I'm use Session.setServerAliveInterval method and test it with Session.isConnected.
The problem is host2 can't be checked if only host2 network is break even through I'm use ServerAliveInterval config when jump to host2.It will hold a long time (more then 1min on my test) until get a packet_write_wait: Connection to xxx.xxx.xxx.xxx port 22: Broken pipe. But I'm expect some error message arrived less then 10 seconds as the ServerAliveInterval=5 ServerAliveCountMax=2 was set.
The shell is a black box for JSCh.
JSch is not aware of anything that you do there.
If you want to emulate, what OpenSSH ServerAliveInterval directive does, use Session.setServerAliveInterval.
See also JSch: How to keep the session alive and up.

Using JSch to create a SOCKS proxy tunneled through SSH

As far as I heave read, it is possible to create a SSH tunnel using JSch, and then put the settings in Firefox as a SOCKS5 proxy and all the traffic would go through the machine JSch is connected to. I have found the the following code but there is somethings I don't understand about it.
String host = "my ssh server ip";
String user = "root";
String password = "mypass";
int port = 22;
int tunnelLocalPort = 9080;
String tunnelRemoteHost = "YYY.YYY.YYY.YYY";
int tunnelRemotePort = 80;
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
localUserInfo lui = new localUserInfo();
session.setUserInfo(lui);
session.connect();
session.setPortForwardingL(tunnelLocalPort, tunnelRemoteHost, tunnelRemotePort);
System.out.println("Connected");
tunnelLocalPort would be the port that my java program would be listening on? this is the port I put the Firefox SOCKS5 proxy settings?
I don't understand what tunnelRemoteHost is for, I want this to act like a SOCKS5 proxy, just like PuTTY does when tunneling is setup on it.
JSch indeed allows creating an SSH tunnel. But the "dynamic" port forwarding feature of PuTTY (which, I assume, you are referring to) is a lot more than an SSH tunnel. It particularly implements the SOCKS proxy (what you are after). That's something that JSch does not implement.
For a plain SSH tunnel/port forwarding, you have to specify the target address, to connect the other end of the tunnel to (tunnelRemoteHost). That's obviously not necessary in the PuTTY "dynamic" mode, as there a proxy protocol (SOCKS) takes case of that.

Using JSch to SFTP when one must also switch user

I am using JSch in a Java client to connect to a remote server and get some files using SFTP. The following code has been working fine for me: -
JSch ssh = new JSch();
JSch.setConfig(FileTransferConstants.STRICT_HOST_KEY_CHECKING, FileTransferConstants.NO);
Session session = ssh.getSession(userName, host, port);
session.setPassword(password);
session.connect();
Channel channel = session.openChannel(FileTransferConstants.SFTP);
channel.connect();
ChannelSftp sftp = (ChannelSftp) channel;
sftp.cd(remoteDirectoryPath);
sftp.lcd(localDirectoryPath);
sftp.get(remoteDirectoryPath + remoteFileName, remoteFileName);
The problem is that there has now been a change of site policy. I am no longer permitted to log on directly as this user (userName above). I must first log on as my personal user and then su into the user that has access to the files I want to SFTP.
I don't think there is anyway I can refactor the above code to achieve this and so I have started looking at using a shell or exec channel instead. I have had little success so far and cannot seem to find any examples on the web, so I would be very grateful for any advice or pointers in the right direction. Many thanks.
I do not think you can do this directly with JSch. But with some modification of its code, it's probably doable.
Note that my answer assumes that the server is *nix-based (what is backed by your reference to su) and uses OpenSSH SFTP server.
You have to open SSH "exec" channel, to execute something like:
sudo /bin/sftp-server
But on top of that channel, you need to build the ChannelSftp instance, not ChannelExec.
So you will need to implement Session.openChannel-like method, that will open exec channel, but create ChannelSftp for it.
For some background, see how it's possible to do sudo with WinSCP SFTP client.
Note that while the FAQ claims, that you won't be able to use password for the sudo, that's true for WinSCP. But as you have a full control of the session with JSch, you may be able to feed the password to sudo.
For that you might override the ChannelSftp.start() to write the password to the channel input, before starting the actual SFTP session.
You still need the requiretty option be off, as the SFTP cannot work with TTY.
For general considerations when automating operations using a different/root account, see:
Allowing automatic command execution as root on Linux using SSH

operation time connecting openshift in java

I want to connect to my mysql database cartridge in openshift through java.
So I create a ssl connection using jsch in my java file. When I run it, give me error operation timed out. Can any one help me out with this. My java code is :
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsc = new JSch();
jsc.addIdentity("/Users/Adhirajchoudhary/.ssh/id_rsa1");
session=jsc.getSession(sshUserName, sshHostName, 3306);
session.setPassword(sshPassword);
session.setConfig(config);
session.connect();
System.out.println("Connected");
It looks like we are missing some key information in the code you provided, and it also looks like you are trying to ssh to port 3306? That's not going to work. You would have to ssh to port 22, then try to create a tunnel over that connection. You could also try using the OpenShift Java Client and have it setup a port forward for you to use.

Categories