I am using jsch to download files from server, my code below.
public static void downloadFile(TpcCredentialsDTO dto) {
logger.trace("Entering downloadFile() method");
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
boolean success = false;
try {
JSch jsch = new JSch();
session = jsch.getSession(dto.getUsername(), dto.getHost(),
dto.getPort());
session.setPassword(dto.getPassword());
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
logger.info("Connected to " + dto.getHost() + ".");
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp) channel;
List<String> filesToDownload = getFilesToDownload(dto,channelSftp);
if (!filesToDownload.isEmpty()) {
for (String fileDownloadName : filesToDownload) {
success = false;
OutputStream output = new FileOutputStream(
"C:\Download\BLT_03112012");
channelSftp.get("BLT_03112012",output);
success = true;
if (success)
logger.info(ServerConstants.DOWNLOAD_SUCCESS_MSG
+ fileDownloadName);
output.close();
}
}else {
logger.info(ServerConstants.NO_FILES_TO_DOWNLOAD
+ ServerUtils.getDateTime());
success = true;
}
} catch (JSchException ex) {
logger.error( ServerConstants.SFTP_REFUSED_CONNECTION, ex);
} catch (SftpException ex) {
logger.error(ServerConstants.FILE_DOWNLOAD_FAILED, ex);
} catch (IOException ex) {
logger.error(ServerConstants.FILE_NOT_FOUND, ex);
}catch (Exception ex) {
logger.error(ServerConstants.ERROR, ex);
}finally {
if (channelSftp.isConnected()) {
try {
session.disconnect();
channel.disconnect();
channelSftp.quit();
logger.info( ServerConstants.FTP_DISCONNECT);
} catch (Exception ioe) {
logger.error(ServerConstants.FTP_NOT_DISCONNECT, ioe);
}
}
}
logger.trace("Exiting downloadFile() method");
}
sftpChannel.get(filename, outputstream) is throwing an error.
2: File not found
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2629)
at com.jcraft.jsch.ChannelSftp._get(ChannelSftp.java:977)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:946)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:924)
at za.co.tpc.sftpserver.SftpConnection.downloadFile(SftpConnection.java:72)
at za.co.tpc.server.execute.FtpMtn.main(FtpMtn.java:44)
The same code does download Text Document file types but fails for 'File' filetype
Try using paths instead of stream:
String destPath = "filename.txt";
if (!filesToDownload.isEmpty()) {
for (String fileDownloadName : filesToDownload) {
success = false;
sftpChannel.get(fileDownloadName , destPath);
If you wanna use file and streams check this example:
http://kodehelp.com/java-program-for-downloading-file-from-sftp-server/
Please find in the below code sample comprising the file upload and download functionalities. Please pull the relevant details from properties files where ever string marked in lt;sftp.user.namegt;. I am deleting the file once the file is downloaded you can have it as per your requirement.
The event and locale parameters what I have added as part of download functionality is to filter the file(s); you can pass parameters as par you need.
Have placed a check to set proxy which can be used on need basis.
package com.util;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;
/**
*
* #author Dinesh.Lomte
*/
public class SftpUtil {
/**
*
* #param fileName
* #throws Exception
*/
public static void upload(String fileName)
throws Exception {
String method = "upload(String fileName)";
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
// Creating and instantiating the jsch specific instance
JSch jsch = new JSch();
// Fetching and setting the parameters like: user name, host and port
// from the properties file
session = jsch.getSession("<sftp.user.name>",
"<sftp.host>",
Integer.valueOf("<sftp.port>"));
// Fetching and setting the password as configured in properties files
session.setPassword("<sftp.user.password>");
// Setting the configuration specific properties
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// Validating if proxy is enabled to access the sftp
isSftpProxyEnabled(session);
// Execution start time
long lStartTime = new Date().getTime();
System.out.println("Connecting to the sftp...");
// Connecting to the sftp
session.connect();
System.out.println("Connected to the sftp.");
// Execution end time
long lEndTime = new Date().getTime();
System.out.println("---------------------------------------------");
System.out.println("Connected to SFTP in : " + (lEndTime - lStartTime));
// Setting the channel type as sftp
channel = session.openChannel("sftp");
// Establishing the connection
channel.connect();
channelSftp = (ChannelSftp) channel;
// Setting the folder location of the external system as configured
channelSftp.cd("<sftp.output.folder.url>");
// Creating the file instance
File file = new File(fileName);
// Creating an fileInputStream instance
FileInputStream fileInputStream = new FileInputStream(file);
// Transfering the file from it source to destination location via sftp
channelSftp.put(fileInputStream, file.getName());
// Closing the fileInputStream instance
fileInputStream.close();
// De-allocating the fileInputStream instance memory by assigning null
fileInputStream = null;
} catch (Exception exception) {
throw exception;
} finally {
// Validating if channel sftp is not null to exit
if (channelSftp != null) {
channelSftp.exit();
}
// Validating if channel is not null to disconnect
if (channel != null) {
channel.disconnect();
}
// Validating if session instance is not null to disconnect
if (session != null) {
session.disconnect();
}
}
}
/**
*
* #param session
*/
private static void isSftpProxyEnabled(Session session) {
// Fetching the sftp proxy flag set as part of the properties file
boolean isSftpProxyEnabled = Boolean.valueOf("<sftp.proxy.enable>");
// Validating if proxy is enabled to access the sftp
if (isSftpProxyEnabled) {
// Setting host and port of the proxy to access the SFTP
session.setProxy(new ProxyHTTP("<sftp.proxy.host>",
Integer.valueOf("<sftp.proxy.port>");
}
System.out.println("Proxy status: " + isSftpProxyEnabled);
}
/**
*
* #param folder
* #param event
* #param locale
*/
public static void download(String folder, String event, String locale) {
String method = "download(String folder, String event, String locale)";
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
// Creating and instantiating the jsch specific instance
JSch jsch = new JSch();
// Fetching and setting the parameters like: user name, host and port
// from the properties file
session = jsch.getSession("<sftp.user.name>",
"<sftp.host>",
Integer.valueOf("<sftp.port>"));
// Fetching and setting the password as configured in properties files
session.setPassword("<sftp.user.password>");
// Setting the configuration specific properties
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// Validating if proxy is enabled to access the sftp
isSftpProxyEnabled(session);
// Execution start time
long lStartTime = new Date().getTime();
System.out.println("Connecting to the sftp...");
// Connecting to the sftp
session.connect();
System.out.println("Connected to the sftp.");
// Execution end time
long lEndTime = new Date().getTime();
System.out.println("---------------------------------------------");
System.out.println("Connected to SFTP in : " + (lEndTime - lStartTime));
// Setting the channel type as sftp
channel = session.openChannel(SFTP);
// Establishing the connection
channel.connect();
channelSftp = (ChannelSftp) channel;
try {
// Setting the folder location of the external system as configured
// to download the file from
channelSftp.cd("<sftp.input.folder.url>");
} catch (SftpException sftpException) {
System.out.println("Failed to change the directory in sftp.");
}
// Listing all the .csv file(s) specific to the source system, event type (download) and locale code
Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(
new StringBuilder("*").append("<sys.code>").append("*").append(event)
.append("*").append(locale).append("*").append(".csv").toString());
// Validating if files exist to process the request further
if (lsEntries.isEmpty()) {
System.out.println("No file exist in the specified sftp folder location.");
}
// Iterating the list of entries to download the file(s) from the sftp
for (ChannelSftp.LsEntry entry : lsEntries) {
try {
// Downloading the specified file from the sftp to the specified folder path
channelSftp.get(entry.getFilename(), new StringBuilder(folder)
.append(File.separator).append(entry.getFilename()).toString());
} catch (SftpException sftpException) {
System.out.println("Failed to download the file the sftp folder location.");
}
}
// Iterating the list of entries to delete the file(s) from the sftp
for (ChannelSftp.LsEntry entry : lsEntries) {
try {
// Deleting the specified file from the sftp
channelSftp.rm(entry.getFilename());
} catch (SftpException sftpException) {
System.out.println("Failed to delete the file from the sftp folder location.");
}
}
} catch (Exception exception) {
System.out.println("Failed to download the file(s) from SFTP.");
} finally {
// Validating if channel sftp is not null to exit
if (channelSftp != null) {
channelSftp.exit();
}
// Validating if channel is not null to disconnect
if (channel != null) {
channel.disconnect();
}
// Validating if session instance is not null to disconnect
if (session != null) {
session.disconnect();
}
}
}
}
I fixed in this way:
Vector<ChannelSftp.LsEntry> files = sftp.ls(remotePath);
String remotePath = properties.getFtpPath();
Vector<ChannelSftp.LsEntry> files = sftp.ls(remotePath);
for (ChannelSftp.LsEntry entry : files) {
InputStream stream = sftp.get(remotePath + "/" + entry.getFilename());
// Your business code here
}
Where remotePath is the remote SFTP folder name.
Related
I am trying to rename the file in vsftpd server using apache commons vfs, moveTo function is working fine in local system OS (Kubuntu 19.04) and VSFTPD server but when I try to rename the file in a test environment which has ubuntu 18.04 I am not able to rename the file I am getting exception.
With this code:
public static boolean move(String hostName, String username, String password, String remoteSrcFilePath,
String remoteDestFilePath, byte [] data) {
FileObject remoteFile = null;
FileObject remoteDestFile = null;
boolean result = false;
try (StandardFileSystemManager manager = new StandardFileSystemManager()){
manager.init();
// Create remote object
remoteFile = manager.resolveFile(
createConnectionString(hostName, username, password, remoteSrcFilePath), createDefaultOptions());
remoteDestFile = manager.resolveFile(
createConnectionString(hostName, username, password, remoteDestFilePath), createDefaultOptions());
if (!remoteDestFile.exists() && remoteFile.exists()) {
remoteFile.moveTo(remoteDestFile);
if(null != data)
writeData(remoteDestFile, data);
result = true;
}else {
throw new DataIntegrityViolationException("Destination path already exists");
}
} catch (IOException e) {
logger.error("Error while renaming/moving file",e);
} finally {
try {
if(null != remoteDestFile)
remoteDestFile.close();
if(null != remoteFile)
remoteFile.close();
} catch (FileSystemException e) {
logger.warn("error while closing fileobject "+e.getMessage());
}
}
return result;
}
public static FileSystemOptions createDefaultOptions() throws FileSystemException {
// Create SFTP options
FileSystemOptions opts = new FileSystemOptions();
// SSH Key checking
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
/*
* Using the following line will cause VFS to choose File System's Root as VFS's
* root. If I wanted to use User's home as VFS's root then set 2nd method
* parameter to "true"
*/
// Root directory set to user home
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
// Timeout is count by Milliseconds
SftpFileSystemConfigBuilder.getInstance().setConnectTimeoutMillis(opts, 10000);
return opts;
}
}
I have this exception
org.apache.commons.vfs2.FileSystemException: Could not determine if file "sftp://ftpuser:***#ip_address/home/ftpuser/ftp/1/Documents/test1/test2" is writeable
Please note the above code is working very well local.
If you follow the source code for apache commons vfs for moveTo() you will find:
if (canRenameTo(destFile)) { //src and dest have the same FS
if (!getParent().isWriteable()) { // <-- it could throw the same exception here
throw new FileSystemException("vfs.provider/rename-parent-read-only.error", getName(),
getParent().getName());
}
} else {
if (!isWriteable()) { // <---- it throws inside here (IMO) rather than returning false
throw new FileSystemException("vfs.provider/rename-read-only.error", getName());
}
}
..., you will find that moveTo() will throw the exception that you see, if the destination file is not writeable but in a catastrophic sort of way as in isWriteable(file) throws exception inside its body rather than returning false.
My first call would be to verify that the both the sftpd process and the ftp user can write to the directory where you want your file to be moved to.
HTH!
#diginoise I tried all the way using apache commons vfs but that didn't work and only for rename I switch to Jsch below is the working code for local as well as remote server
private static ChannelSftp setupJsch(String hostName, String username, String password) throws JSchException {
JSch jsch = new JSch();
JSch.setConfig("StrictHostKeyChecking", "no");
jsch.setKnownHosts("/home/"+username+"/.ssh/known_hosts");
Session jschSession = jsch.getSession(username, hostName);
jschSession.setPassword(password);
jschSession.connect();
return (ChannelSftp) jschSession.openChannel("sftp");
}
public static boolean renameFile(String hostName, String username, String password, String remoteSrcFilePath,
String remoteDestFilePath) {
boolean result = false;
ChannelSftp channelSftp = null;
try {
channelSftp = setupJsch(hostName,username,password);
channelSftp.connect();
channelSftp.rename(remoteSrcFilePath, remoteDestFilePath);
result = true;
}catch(JSchException | SftpException e) {
logger.error("Error while renaming file sftp ",e);
}finally {
sftpCleanUp(channelSftp);
}
return result;
}
private static void sftpCleanUp(ChannelSftp channelSftp) {
if(null != channelSftp) {
channelSftp.disconnect();
channelSftp.exit();
}
}
I am using Jsch to create a file in the server and execute some commands. For the file creation, it's working fine, however, for the command execution, doesn't. It keeps the status -1 (still working on it) and keep there forever. This happen for shell execution or when I try to became root. Follow the method used below:
public void upload(String localPath) throws IOException {
Session session = connectToServer();
System.out.println("In upload");
ChannelSftp channelSftp = getChannelToSftpServer(session);
//Creating file in temporary location
File f = new File(localPath);
FileInputStream fi = new FileInputStream(f);
// Creating file on server and setting the permissions to the user (chmod 777)
if (channelSftp != null) {
try {
System.out.println("Change working in temp directory");
changeWorkingDirectory(channelSftp, TEMP_PATH);
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
//THE PROBLEM ALSO HAPPENS WHEN EXECUTING A SHELL WITH THIS COMMAND INSIDE
channelExec.setCommand(
"root command (using pbrun) <command is here, confidential> ");
InputStream commandOutput = channelExec.getInputStream();
channelExec.connect();
StringBuilder outputBuffer = new StringBuilder();
int readByte = commandOutput.read();
while(readByte != 0xffffffff)
{
outputBuffer.append((char)readByte);
readByte = commandOutput.read();
System.out.println(outputBuffer);
}
System.out.println("Root connected.");
channelExec.disconnect();
channelSftp.put(fi, f.getName());
channelSftp.chmod(0777, localPath);
channelSftp.chown(123, localPath);
channelSftp.chgrp(123, localPath);
System.out.println("File configurations changed.");
//Copying to the official path
channelExec = (ChannelExec) session.openChannel("exec");
channelExec.setCommand("mv /tmp/"+f.getName()+" "+path);
channelExec.connect();
System.out.println("File is completed and ready!");
while (channelExec.getExitStatus() == -1) {
Thread.sleep(1000);
}
channelExec.disconnect();
} catch (SftpException e) {
e.printStackTrace();
throw new IOException(e.getStackTrace() + "");
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
disconnectChanneltoSftpServer(channelSftp);
session.disconnect();
fi.close();
// Deletes the local File.
f.delete();
}
}
}
What am I doing wrong? Thank you in advance.
You have to call getInputStream() before calling connect().
And you actually better read both stderr and stdout to get the errors.
For that, see my answer to How to read JSch command output?
When the code below has finished running, netstat -a|grep sftp shows an open SFTP connection. It also shows up as an open connection in JProfiler.
channel.isConnected() in the finally block prints false. Any ideas why the connections is not being closed as I'm at a loss?
public static void clean() {
com.jcraft.jsch.ChannelSftp channel = null;
try {
channel = Helper.openNewTLSftpChannel();
channel.connect();
channel.cd(remoteFileDirectory);
List<ChannelSftp.LsEntry> list = channel.ls("*." + fileType);
for (ChannelSftp.LsEntry file : list) {
String fileName = file.getFilename();
DateTime fileDate = new DateTime(parseDateFromFileName(fileName));
//if this file is older than the cutoff date, delete from the SFTP share
if (fileDate.compareTo(cleanupCutoffdate) < 0) {
channel.rm(fileName);
}
}
} catch (Exception exception) {
exception.printStackTrace();
} finally {
if (channel != null) {
channel.disconnect();
System.out.println(channel.isConnected());
}
}
}
Adding openNewTLSftpChannel() below:
public static ChannelSftp openNewSftpChannel(String privateKeyFileName, String password, String username, String host, int port)
throws ConfigurationErrorException {
JSch jsch = new JSch();
File sftpPrivateFile = new File(privateKeyFileName);
Channel channel;
try {
if (!sftpPrivateFile.canRead()) {
throw new ConfigurationErrorException("File access error: " + sftpPrivateFile.getAbsolutePath());
}
jsch.addIdentity(sftpPrivateFile.getAbsolutePath(), password);
Session session = jsch.getSession(username, host, port);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("sftp");
} catch (JSchException jschException) {
throw new ConfigurationErrorException("File access error: " + sftpPrivateFile.getAbsolutePath());
}
return (ChannelSftp) channel;
}
If you take a look at the JSCH examples for SFTP you'll see how the session is terminated:
//setup Session here
...
session.connect();
...
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
...run sftp logic...
//close sessions here
sftpChannel.exit();
session.disconnect();
You'll notice that there are two parts to the connection and disconnection; the Session object and the Channel object.
In my code I use the Session object to set my authentication information, and the Channel object to execute the sftp commands I need.
In your instance, you're creating the Session object in your openNewSftpChannel method, but it is never closed, hence your session stays alive.
For further context, check out the examples.
Robert H is correct, you need to exit your channel and disconnect your session. I wanted to add that the session exists even when the channel has been closed. Since you create your session within a try block inside a method, it seems you have lost your session, but you can get it back using 'getSession' on your sftpChannel channel.
You can change your finally block to this:
} finally {
if (channel != null) {
Session session = channel.getSession();
channel.disconnect();
session.disconnect();
System.out.println(channel.isConnected());
}
}
Recently a client of our unexpectedly shifted some important files we collect from an ftp to sftp server. Initially I was under the impression that it would be simple to write or find a java utility that can handle sftp, this has definitely not proven to be the case. What has also compounded this problem is that we are trying to connect to the sftp server from a windows platform (so the definition of where SSH_HOME is on the client gets very confused).
I have been using the apache-commons-vfs library and have managed to get a solution that reliably works for username/password authentication, but as of yet nothing that can reliably handle private/public key authentication.
The following example works for username/password authentication, but I want to adjust it for private/public key authentication.
public static void sftpGetFile(String server, String userName,String password,
String remoteDir, String localDir, String fileNameRegex)
{
File localDirFile = new File(localDir);
FileSystemManager fsManager = null;
if (!localDirFile.exists()) {
localDirFile.mkdirs();
}
try {
fsManager = VFS.getManager();
} catch (FileSystemException ex) {
LOGGER.error("Failed to get fsManager from VFS",ex);
throw new RuntimeException("Failed to get fsManager from VFS", ex);
}
UserAuthenticator auth = new StaticUserAuthenticator(null, userName,password);
FileSystemOptions opts = new FileSystemOptions();
try {
DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts,
auth);
} catch (FileSystemException ex) {
LOGGER.error("setUserAuthenticator failed", ex);
throw new RuntimeException("setUserAuthenticator failed", ex);
}
Pattern filePattern = Pattern.compile(fileNameRegex);
String startPath = "sftp://" + server + remoteDir;
FileObject[] children;
// Set starting path on remote SFTP server.
FileObject sftpFile;
try {
sftpFile = fsManager.resolveFile(startPath, opts);
LOGGER.info("SFTP connection successfully established to " +
startPath);
} catch (FileSystemException ex) {
LOGGER.error("SFTP error parsing path " +
remoteDir,
ex);
throw new RuntimeException("SFTP error parsing path " +
remoteDir,
ex);
}
// Get a directory listing
try {
children = sftpFile.getChildren();
} catch (FileSystemException ex) {
throw new RuntimeException("Error collecting directory listing of " +
startPath, ex);
}
search:
for (FileObject f : children) {
try {
String relativePath =
File.separatorChar + f.getName().getBaseName();
if (f.getType() == FileType.FILE) {
System.out.println("Examining remote file " + f.getName());
if (!filePattern.matcher(f.getName().getPath()).matches()) {
LOGGER.info(" Filename does not match, skipping file ." +
relativePath);
continue search;
}
String localUrl = "file://" + localDir + relativePath;
String standardPath = localDir + relativePath;
System.out.println(" Standard local path is " + standardPath);
LocalFile localFile =
(LocalFile) fsManager.resolveFile(localUrl);
System.out.println(" Resolved local file name: " +
localFile.getName());
if (!localFile.getParent().exists()) {
localFile.getParent().createFolder();
}
System.out.println(" ### Retrieving file ###");
localFile.copyFrom(f,
new AllFileSelector());
} else {
System.out.println("Ignoring non-file " + f.getName());
}
} catch (FileSystemException ex) {
throw new RuntimeException("Error getting file type for " +
f.getName(), ex);
}
}
FileSystem fs = null;
if (children.length > 0) {
fs = children[0].getFileSystem(); // This works even if the src is closed.
fsManager.closeFileSystem(fs);
}
}
I've got my private key stored in a known location and my public key has been distrubuted to the server (we have tested that these keys work succesfully when connecting using other tools)
I have played around with adding the following line
SftpFileSystemConfigBuilder.getInstance().setIdentities(this.opts, new File[]{new File("c:/Users/bobtbuilder/.ssh/id_dsa.ppk")});
This succesfully loads the private key into the whole framework but it never then uses that key to authenticate further.
Any help or direction most warmly received
After much digging around I finally got to the answer myself. Seems that much of my bother was to do with the format of the private and public key
privateKey must be in openSSH format
publicKey for whatever reason can only be pasted from the puttyGen window (exporting the public key always seemed to give it with missing headers meaning the freeSSHD windows server could not use it)
Anyhow below is my code I finally came up with including the javadoc, so hopefully should save some others the pain I went through
/**
* Fetches a file from a remote sftp server and copies it to a local file location. The authentication method used
* is public/private key authentication. <br><br>
* IMPORTANT: Your private key must be in the OpenSSH format, also it must not have a passphrase associated with it.
* (currently the apache-commons-vfs2 library does not support passphrases)<p>
*
* Also remember your public key needs to be on the sftp server. If you were connecting as user 'bob' then your
* public key will need to be in '.ssh/bob' on the server (the location of .ssh will change depending on the type
* of sftp server)
*
* #param server The server we care connection to
* #param userName The username we are connection as
* #param openSSHPrivateKey The location of the private key (which must be in openSSH format) on the local machine
* #param remoteDir The directory from where you want to retrieve the file on the remote machine (this is in reference to SSH_HOME, SSH_HOME is the direcory you
* automatically get directed to when connecting)
* #param remoteFile The name of the file on the remote machine to be collected (does not support wild cards)
* #param localDir The direcoty on the local machine where you want the file to be copied to
* #param localFileName The name you wish to give to retrieved file on the local machine
* #throws IOException - Gets thrown is there is any problem fetching the file
*/
public static void sftpGetFile_keyAuthentication(String server, String userName, String openSSHPrivateKey,
String remoteDir,String remoteFile, String localDir, String localFileName) throws IOException
{
FileSystemOptions fsOptions = new FileSystemOptions();
FileSystemManager fsManager = null;
String remoteURL = "sftp://" + userName + "#" + server + "/" + remoteDir + "/" + remoteFile;
String localURL = "file://" + localDir + "/" + localFileName;
try {
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions, new File[]{new File(openSSHPrivateKey)});
fsManager = VFS.getManager();
FileObject remoteFileObject = fsManager.resolveFile(remoteURL, fsOptions);
LocalFile localFile =
(LocalFile) fsManager.resolveFile(localURL);
localFile.copyFrom(remoteFileObject,
new AllFileSelector());
} catch (FileSystemException e) {
LOGGER.error("Problem retrieving from " + remoteURL + " to " + localURL,e );
throw new IOException(e);
}
}
I guess this is what you are looking for -
/**
* #param args
*/
public static void main(String[] args) {
/*Below we have declared and defined the SFTP HOST, PORT, USER
and Local private key from where you will make connection */
String SFTPHOST = "10.20.30.40";
int SFTPPORT = 22;
String SFTPUSER = "kodehelp";
// this file can be id_rsa or id_dsa based on which algorithm is used to create the key
String privateKey = "/home/kodehelp/.ssh/id_rsa";
String SFTPWORKINGDIR = "/home/kodehelp/";
JSch jSch = new JSch();
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
jSch.addIdentity(privateKey);
System.out.println("Private Key Added.");
session = jSch.getSession(SFTPUSER,SFTPHOST,SFTPPORT);
System.out.println("session created.");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("sftp");
channel.connect();
System.out.println("shell channel connected....");
channelSftp = (ChannelSftp)channel;
channelSftp.cd(SFTPWORKINGDIR);
System.out.println("Changed the directory...");
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SftpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(channelSftp!=null){
channelSftp.disconnect();
channelSftp.exit();
}
if(channel!=null) channel.disconnect();
if(session!=null) session.disconnect();
}
}
See more at
http://kodehelp.com/sftp-connection-public-key-authentication-java/
This post and answer were very helpful, thank you very much.
I just want to add an integration to the statement "currently the apache-commons-vfs2 library does not support passphrases", as I did it also with passphrase and it worked.
You have to import the jsch library in your project (I used 0.1.49) and implement the interface "com.jcraft.jsch.UserInfo".
Something like this should be fine:
public class SftpUserInfo implements UserInfo {
public String getPassphrase() {
return "yourpassphrase";
}
public String getPassword() {
return null;
}
public boolean promptPassphrase(String arg0) {
return true;
}
public boolean promptPassword(String arg0) {
return false;
}
}
And then you can add it to the SftpFileSystemConfigBuilder this way:
SftpFileSystemConfigBuilder.getInstance().setUserInfo(fsOptions, new SftpUserInfo());
Hope this helps.
I installed FileZilla FTP Server on my local Windows 7 machine.
I also installed FileZilla FTP client on the same machine.
Connection is successfull between both of them confirming the server and client partnership exists.
I wrote a small quick and dirtry Jsch program for connecting to the FileZilla FTP server and below is the program:
public class TestJSch {
/** Creates a new instance of TestCommonsNet */
public TestJSch() {
}
/**
* main - Unit test program
*
* #param args
* Command line arguments
*
*/
public static void main(String[] args) {
try {
String ftpHost = "127.0.0.1";
int ftpPort = 21;// 14147;
// int ftpPort = 990;// 14147;
String ftpUserName = "kedar";
String ftpPassword = "XXXXXXXXXXX";
String ftpRemoteDirectory = "C:\\KEDAR\\Java\\FTP_Folder";
String fileToTransmit = "C:\\KEDAR\\Java\\File_Folder\\Customer.txt";
String identityfile = "C:\\KEDAR\\Java\\Ftp\\certificate.crt";
//
// First Create a JSch session
//
JSch.setLogger(new MyLogger());
System.out.println("Creating session.");
JSch jsch = new JSch();
String knownHostsFilename = "C:\\Windows\\System32\\drivers\\etc\\hosts";
jsch.setKnownHosts(knownHostsFilename);
jsch.addIdentity(identityfile);
Session session = null;
Channel channel = null;
ChannelSftp c = null;
//
// Now connect and SFTP to the SFTP Server
//
try {
// Create a session sending through our username and password
session = jsch.getSession(ftpUserName, ftpHost, ftpPort);
System.out.println("Session created.");
session.setPassword(ftpPassword);
// Security.addProvider(new com.sun.crypto.provider.SunJCE());
// b
// Setup Strict HostKeyChecking to no so we dont get the
// unknown host key exception
//
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
System.out.println("Session connected.");
//
// Open the SFTP channel
//
System.out.println("Opening Channel.");
channel = session.openChannel("sftp");
channel.connect();
c = (ChannelSftp) channel;
} catch (Exception e) {
System.err.println("Unable to connect to FTP server."
+ e.toString());
throw e;
}
//
// Change to the remote directory
//
System.out.println("Changing to FTP remote dir: "
+ ftpRemoteDirectory);
c.cd(ftpRemoteDirectory);
//
// Send the file we generated
//
try {
File f = new File(fileToTransmit);
System.out.println("Storing file as remote filename: "
+ f.getName());
c.put(new FileInputStream(f), f.getName());
} catch (Exception e) {
System.err
.println("Storing remote file failed." + e.toString());
throw e;
}
//
// Disconnect from the FTP server
//
try {
c.quit();
} catch (Exception exc) {
System.err.println("Unable to disconnect from FTPserver. "
+ exc.toString());
}
} catch (Exception e) {
System.err.println("Error: " + e.toString());
}
System.out.println("Process Complete.");
System.exit(0);
}
public static class MyLogger implements com.jcraft.jsch.Logger {
static java.util.Hashtable name = new java.util.Hashtable();
static {
name.put(new Integer(DEBUG), "DEBUG: ");
name.put(new Integer(INFO), "INFO: ");
name.put(new Integer(WARN), "WARN: ");
name.put(new Integer(ERROR), "ERROR: ");
name.put(new Integer(FATAL), "FATAL: ");
}
public boolean isEnabled(int level) {
return true;
}
public void log(int level, String message) {
System.err.print(name.get(new Integer(level)));
System.err.println(message);
}
}
}
I tried running this program and below is the FTP log:
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> Connected, sending welcome message...
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> 220-FileZilla Server version 0.9.39 beta
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> 220-written by Tim Kosse (Tim.Kosse#gmx.de)
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> 220 Please visit http://sourceforge.net/projects/filezilla/
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> SSH-2.0-JSCH-0.1.44
(000033)9/12/2011 13:08:53 PM - (not logged in) (127.0.0.1)> 500 Syntax error, command unrecognized.
(000033)9/12/2011 13:09:54 PM - (not logged in) (127.0.0.1)> 421 Login time exceeded. Closing control connection.
(000033)9/12/2011 13:09:54 PM - (not logged in) (127.0.0.1)> disconnected.
I don't understand why the JSch program is issuing SSH-2.0-JSCH-0.1.44 command and the communication is then turned down. How do we avoid this?
JSch is not an FTP client. JSch is an SSH client (with an included SFTP implementation).
The SSH protocol is a protocol to allow secure connections to a server, for shell access, file transfer or port forwarding. For this, the server must have an SSH server (usually on port 22, but that can vary). SFTP is a binary file transfer protocol which is usually tunneled over SSH, and not related to FTP (other than by name).
If you want to use JSch to download/upload files, you need to install and activate an SSH/SFTP server on your computer (respective the computer you want to access).
For FTP, you have to use other Java libraries (Apache Commons FTPClient seems to be famous, from the questions here).
By the way, the known hosts file for JSch is a file listing the public keys of the SSH hosts, not the file listing their IP addresses (which is the Windows config file you are trying to supply here).
Use Apache commons-net FTP library.
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
public class FTPConnectionCode {
public static void main(String[] args) {
String server = "www.website.com";
// generally ftp port is 21
int port = 21;
String user = "ftpusername";
String pass = "ftppassword";
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(server, port);
showServerReply(ftpClient);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Connect failed");
return;
}
boolean success = ftpClient.login(user, pass);
showServerReply(ftpClient);
if (!success) {
System.out.println("Could not login to the server");
return;
}
// Changes working directory
success = ftpClient.changeWorkingDirectory("/dir");
showServerReply(ftpClient);
if (success) {
System.out.println("Successfully changed working directory.");
} else {
System.out.println("Failed to change working directory. See server's reply.");
}
// logs out
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException ex) {
System.out.println("Oops! Something wrong happened");
ex.printStackTrace();
}
}
private static void showServerReply(FTPClient ftpClient) {
String[] replies = ftpClient.getReplyStrings();
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}
}