![](/img/trans.png)
[英]SFTP public/private key authentication - can it work without the key location?
[英]Reliable example of how to use SFTP using public private key authentication with Java
最近,我們的一個客戶意外地將我們從 ftp 收集的一些重要文件轉移到了 sftp 服務器。 最初我的印象是編寫或找到一個可以處理 sftp 的 java 實用程序會很簡單,但事實證明並非如此。 使這個問題更加復雜的是我們正試圖從 Windows 平台連接到 sftp 服務器(因此 SSH_HOME 在客戶端上的位置的定義變得非常混亂)。
我一直在使用 apache-commons-vfs 庫並設法獲得了一個可靠地用於用戶名/密碼身份驗證的解決方案,但到目前為止還沒有任何東西可以可靠地處理私鑰/公鑰身份驗證。
以下示例適用於用戶名/密碼身份驗證,但我想將其調整為私鑰/公鑰身份驗證。
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);
}
}
我的私鑰存儲在已知位置,並且我的公鑰已分發到服務器(我們已經測試這些密鑰在使用其他工具連接時可以成功工作)
我玩過添加以下行
SftpFileSystemConfigBuilder.getInstance().setIdentities(this.opts, new File[]{new File("c:/Users/bobtbuilder/.ssh/id_dsa.ppk")});
這成功地將私鑰加載到整個框架中,但它永遠不會使用該密鑰進行進一步的身份驗證。
最熱烈地接受的任何幫助或指導
經過大量挖掘,我終於自己得到了答案。 似乎我的大部分煩惱與私鑰和公鑰的格式有關
privateKey 必須是 openSSH 格式 publicKey 出於某種原因只能從 puttyGen 窗口粘貼(導出公鑰似乎總是給它缺少標頭,這意味着 freeSSHD windows 服務器無法使用它)
無論如何,下面是我最終想出的代碼,包括javadoc,所以希望可以為其他人節省我所經歷的痛苦
/**
* 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);
}
}
我想這就是你要找的 -
/**
* @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();
}
}
更多信息請訪問
http://kodehelp.com/sftp-connection-public-key-authentication-java/
這個帖子和答案非常有幫助,非常感謝。
我只想在語句“當前 apache-commons-vfs2 庫不支持密碼短語”中添加一個集成,因為我也使用密碼短語並且它有效。
您必須在您的項目中導入 jsch 庫(我使用的是 0.1.49)並實現接口“com.jcraft.jsch.UserInfo”。
這樣的事情應該沒問題:
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;
}
}
然后你可以通過這種方式將它添加到 SftpFileSystemConfigBuilder 中:
SftpFileSystemConfigBuilder.getInstance().setUserInfo(fsOptions, new SftpUserInfo());
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.