How to use apache vfs2 for sftp with public-private-key and without password

17,751

Solution 1

Taking your code and wrapping it into a runnable example. Notice the IdentityInfo implementation. This can work with a key-with-passphrase by changing the obvious lines.

$ javac -cp 'jsch-0.1.51.jar;commons-vfs2-2.0.jar' SftpGet.java
$ java -cp 'jsch-0.1.51.jar;commons-vfs2-2.0.jar;commons-logging-1.1.1.jar;.' SftpGet

with

import java.io.File;

import com.jcraft.jsch.UserInfo;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.apache.commons.vfs2.provider.sftp.IdentityInfo;


    public class SftpGet {

        public static void main(String[] args) {
            downloadFile();
        }


        private static boolean downloadFile(){

            String host = "HOSTNAMEHERE";
            String user = "USERNAMEHERE";
            String password = "";
            String fileName = "/lines.txt";
            String localFilePath = "c:/cygwin64/home/woddle/wrote_lines.txt";

            // without passphrase
            String keyPath = "c:/cygwin64/home/woddle/.ssh/id_dsa_nopass";
            String passphrase = null;

            // with passphrase
            // String keyPath = "c:/cygwin64/home/woddle/.ssh/id_dsa_withpass";
            // String passphrase = "super-secrets";

            StandardFileSystemManager sysManager = new StandardFileSystemManager();

            //download der Datei
            try {
                sysManager.init();

                FileObject localFile = sysManager.resolveFile(localFilePath);

                FileObject remoteFile = sysManager.resolveFile(createConnectionString(host, user, password, keyPath, passphrase, fileName), createDefaultOptions(keyPath, passphrase));

                //Selectors.SELECT_FILES --> A FileSelector that selects only the base file/folder.
                localFile.copyFrom(remoteFile, Selectors.SELECT_FILES);


            } catch (Exception e) {
                System.out.println("Downloading file failed: " + e.toString());
                return false;
            }finally{
                sysManager.close();
            }
            return true;
        }


        public static String createConnectionString(String hostName, String username, String password, String keyPath, String passphrase, String remoteFilePath) {

            if (keyPath != null) {
                return "sftp://" + username + "@" + hostName + "/" + remoteFilePath;
            } else {
                return "sftp://" + username + ":" + password + "@" + hostName + "/" + remoteFilePath;
            }
        }



        private static FileSystemOptions createDefaultOptions(final String keyPath, final String passphrase) throws FileSystemException{

            //create options for sftp
            FileSystemOptions options = new FileSystemOptions();
            //ssh key
            SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(options, "no");
            //set root directory to user home
            SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(options, true);
            //timeout
            SftpFileSystemConfigBuilder.getInstance().setTimeout(options, 10000);

            if (keyPath != null) {
                IdentityInfo identityInfo = null;
                if(passPhrase!=null){
                    identityInfo = new IdentityInfo(new File(keyPath), passPhrase.getBytes());
                }else{
                    identityInfo =  new IdentityInfo(new File(keyPath));
                }
          SftpFileSystemConfigBuilder.getInstance().setIdentityInfo(options, identityInfo);
            }


            return options;
        }


    }

Solution 2

We should not use below method for creating the connection string. This may expose the password.

public static String createConnectionString(String hostName, String username, String password, String keyPath, String passphrase, String remoteFilePath) {

    if (keyPath != null) {
        return "sftp://" + username + "@" + hostName + "/" + remoteFilePath;
    } else {
        return "sftp://" + username + ":" + password + "@" + hostName + "/" + remoteFilePath;
    }
}

As per the documentation available on the Apache website, we should use

StaticUserAuthenticator auth = new StaticUserAuthenticator("domain", "username", "password");

Link: https://commons.apache.org/proper/commons-vfs/api.html

Also, if we are using public key or private key based authentication, then we should use setIdentityInfo(FileSystemOptions, IdentityInfo...) instead of setIdentities(FileSystemOptions opts, File... identityFiles).

Reference: https://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/org/apache/commons/vfs2/provider/sftp/SftpFileSystemConfigBuilder.html

FileSystemOptions opts = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, false);

String openSSHPrivateKey = "C:\\Users\\<filepath>\\id_rsa.key";

IdentityInfo myIdentityInfo = new IdentityInfo(new File(openSSHPrivateKey));
    
SftpFileSystemConfigBuilder.getInstance(). setIdentityInfo(opts, myIdentityInfo);
Share:
17,751
LStrike
Author by

LStrike

FNORD

Updated on June 14, 2022

Comments

  • LStrike
    LStrike almost 2 years

    Currently I am using apache vfs2 to download files from a sftp. For authentication I use user-name and password.

    Is there a way to use vfs2 only with public-private-keys and without a password?

    I think I have use this function,but how? Set it only to "yes"?

    SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(options, "no");
    

    This is my current code (snippet):

    private boolean downloadFile(){
    
        StandardFileSystemManager sysManager = new StandardFileSystemManager();
    
        //download der Datei
        try {
            sysManager.init();
    
            FileObject localFile = sysManager.resolveFile(localFilePath);
    
            FileObject remoteFile = sysManager.resolveFile(createConnectionString(host, user, password, fileName, port),createDefaultOptions());
    
            //Selectors.SELECT_FILES --> A FileSelector that selects only the base file/folder.
            localFile.copyFrom(remoteFile, Selectors.SELECT_FILES);
    
    
        } catch (Exception e) {
            logger.error("Downloading file failed: " + e.toString());
            return false;
        }finally{
            sysManager.close();
        }
        return true;
    }
    

    and

    private FileSystemOptions createDefaultOptions() throws FileSystemException{
    
        //create options for sftp
        FileSystemOptions options = new FileSystemOptions();
        //ssh key
        SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(options, "no");
        //set root directory to user home
        SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(options, true);
        //timeout
        SftpFileSystemConfigBuilder.getInstance().setTimeout(options, timeout);
    
        return options;
    }
    
  • Imran Jawaid
    Imran Jawaid about 6 years
    Can you provide the file you have for keyPath ? should it need to have only private key or both private and public keys ?? Like i have a ppk file which has lots of stuff. Should i provide path to that file here or what ? @woddle
  • tony
    tony over 2 years
    If we don't use the method to create the connection string, how do we handle the remote file, what do we pass in as the uri: FileObject remoteFile = sysManager.resolveFile(?, fileOptions).