Java SFTP 服务器库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3076443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java SFTP server library?
提问by CB.
Is there a Java library that can be used to implement an SFTPserver?
是否有可用于实现SFTP服务器的 Java 库?
I'm trying to receive files via SFTP, but I can't seem to find any implementation of an SFTP server. I've found FTP/SFTP/FTPS clientlibraries, and FTP/FTPS server libraries, but none for a server for SFTP.
我正在尝试通过 SFTP 接收文件,但似乎找不到 SFTP 服务器的任何实现。我找到了 FTP/SFTP/FTPS客户端库和 FTP/FTPS 服务器库,但没有找到用于 SFTP 的服务器。
To clarify, I'm trying to receivefiles via SFTP. Not "get" or "put" files from my application to another existing server.
澄清一下,我正在尝试通过 SFTP接收文件。不是从我的应用程序“获取”或“放置”文件到另一个现有服务器。
Right now my application lets the users connect to the local linux SFTP server, drop the files, and then my application polls the directory, but I feel that this is a poor implementation; I hate the idea of "polling" directories, but unfortunately they HAVE to use SFTP. Any suggestions?
现在我的应用程序让用户连接到本地 linux SFTP 服务器,删除文件,然后我的应用程序轮询目录,但我觉得这是一个糟糕的实现;我讨厌“轮询”目录的想法,但不幸的是他们必须使用 SFTP。有什么建议?
采纳答案by Gijs Overvliet
How to setup an SFTP server using Apache Mina SSHD:
如何使用Apache Mina SSHD设置 SFTP 服务器:
public void setupSftpServer(){
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(22);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
userAuthFactories.add(new UserAuthNone.Factory());
sshd.setUserAuthFactories(userAuthFactories);
sshd.setCommandFactory(new ScpCommandFactory());
List<NamedFactory<Command>> namedFactoryList = new ArrayList<NamedFactory<Command>>();
namedFactoryList.add(new SftpSubsystem.Factory());
sshd.setSubsystemFactories(namedFactoryList);
try {
sshd.start();
} catch (Exception e) {
e.printStackTrace();
}
}
And that's all.
就这样。
回答by pakore
回答by ZZ Coder
Please notice that SFTP is a not FTP over SSL, nor FTP over SSH. The SFTP server support requires an implementation of SSHD in Java. Your best bet is Apache SSHD,
请注意,SFTP 不是基于 SSL 的 FTP,也不是基于 SSH 的 FTP。SFTP 服务器支持需要在 Java 中实现 SSHD。您最好的选择是 Apache SSHD,
http://mina.apache.org/sshd-project/
http://mina.apache.org/sshd-project/
I never used the SFTP but I heard it's basic but functional.
我从未使用过 SFTP,但我听说它很基本但很实用。
回答by Bruce Blackshaw
Take a look at SSHTools (j2ssh). It includes a client and server.
看看SSHTools (j2ssh)。它包括客户端和服务器。
However polling a directory isn't that bad an idea - it's probably much more reliable than setting up your own SFTP server using j2ssh. I've lost count of the number of applications I've encountered that do this kind of polling, and it usually works quite well.
然而,轮询目录并不是一个坏主意——它可能比使用 j2ssh 设置自己的 SFTP 服务器可靠得多。我已经数不清我遇到的执行这种轮询的应用程序的数量,而且它通常工作得很好。
回答by valera shibaev
i am using jftp http://j-ftp.sourceforge.net/extract jftp.jar from j-ftp-*.tgz/j-ftp/dist the only problem - they put apache classes inside there jar (so i have to remove common-httpclient, log4j packages manually to avoid conflicting dependencies)
我正在使用 jftp http://j-ftp.sourceforge.net/从 j-ftp-*.tgz/j-ftp/dist 中提取 jftp.jar 唯一的问题 - 他们将 apache 类放在那里 jar (所以我必须手动删除 common-httpclient、log4j 包以避免冲突的依赖项)
回答by Eugene Mayevski 'Callback
Just for completeness - the SecureBlackboxlibrary, which we maintain, offers classes to create your own SSH/SFTP server in Java (including Android).
只是为了完整性 -我们维护的SecureBlackbox库提供了用 Java(包括 Android)创建您自己的 SSH/SFTP 服务器的类。
回答by Richard Sandoz
I tried doing MINA 0.10.1 on Windows with the above and fixed some issues, plus I need better authentication and PK support (still not recommended for production use):
我尝试使用上述方法在 Windows 上执行 MINA 0.10.1 并修复了一些问题,另外我需要更好的身份验证和 PK 支持(仍然不推荐用于生产用途):
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.SshServer;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthPassword;
import org.apache.sshd.server.auth.UserAuthPublicKey;
import org.apache.sshd.common.KeyExchange;
//import org.apache.sshd.server.kex.DHGEX;
//import org.apache.sshd.server.kex.DHGEX256;
import org.apache.sshd.server.kex.ECDHP256;
import org.apache.sshd.server.kex.ECDHP384;
import org.apache.sshd.server.kex.ECDHP521;
import org.apache.sshd.server.kex.DHG1;
import org.apache.mina.util.Base64;
/*
javac -classpath .;lib/sshd-core-0.10.1.jar;lib/mina-core-2.0.7.jar;lib/waffle-jna.jar;lib/guava-13.0.1.jar;lib/jna-platform-4.0.0.jar;lib/jna-4.0.0.jar SFTPServer.java
java -classpath .;lib/sshd-core-0.10.1.jar;lib/slf4j-simple-1.7.6.jar;lib/slf4j-api-1.6.6.jar;lib/mina-core-2.0.7.jar;lib/waffle-jna.jar;lib/guava-13.0.1.jar;lib/jna-platform-4.0.0.jar;lib/jna-4.0.0.jar SFTPServer
*/
public class SFTPServer {
public void setupSftpServer() throws Exception {
class AuthorizedKeyEntry {
private String keyType;
private String pubKey;
private byte[] bytes;
private int pos;
private PublicKey key = null;
private int decodeInt() {
return ((bytes[pos++] & 0xFF) << 24) | ((bytes[pos++] & 0xFF) << 16)
| ((bytes[pos++] & 0xFF) << 8) | (bytes[pos++] & 0xFF);
}
private BigInteger decodeBigInt() {
int len = decodeInt();
byte[] bigIntBytes = new byte[len];
System.arraycopy(bytes, pos, bigIntBytes, 0, len);
pos += len;
return new BigInteger(bigIntBytes);
}
private void decodeType() {
int len = decodeInt();
keyType = new String(bytes, pos, len);
pos += len;
}
public PublicKey getPubKey() {
return key;
}
public void setPubKey(PublicKey key) throws Exception {
this.key = key;
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
if (key instanceof RSAPublicKey) {
keyType = "ssh-rsa";
dos.writeInt(keyType.getBytes().length);
dos.write(keyType.getBytes());
RSAPublicKey rsakey = (RSAPublicKey)key;
BigInteger e = rsakey.getPublicExponent();
dos.writeInt(e.toByteArray().length);
dos.write(e.toByteArray());
BigInteger m = rsakey.getModulus();
dos.writeInt(m.toByteArray().length);
dos.write(m.toByteArray());
} else if (key instanceof DSAPublicKey) {
keyType = "ssh-dss";
dos.writeInt(keyType.getBytes().length);
dos.write(keyType.getBytes());
DSAPublicKey dsskey = (DSAPublicKey)key;
BigInteger p = dsskey.getParams().getP();
dos.writeInt(p.toByteArray().length);
dos.write(p.toByteArray());
BigInteger q = dsskey.getParams().getQ();
dos.writeInt(q.toByteArray().length);
dos.write(q.toByteArray());
BigInteger g = dsskey.getParams().getG();
dos.writeInt(g.toByteArray().length);
dos.write(g.toByteArray());
BigInteger y = dsskey.getY();
dos.writeInt(y.toByteArray().length);
dos.write(y.toByteArray());
} else {
throw new IllegalArgumentException("unknown key encoding " + key.getAlgorithm());
}
bytes = byteOs.toByteArray();
this.pubKey = new String(Base64.encodeBase64(bytes));
}
public void setPubKey(String pubKey) throws Exception {
this.pubKey = pubKey;
bytes = Base64.decodeBase64(pubKey.getBytes());
if (bytes == null)
return;
decodeType();
if (keyType.equals("ssh-rsa")) {
BigInteger e = decodeBigInt();
BigInteger m = decodeBigInt();
KeySpec spec = new RSAPublicKeySpec(m, e);
key = KeyFactory.getInstance("RSA").generatePublic(spec);
} else if (keyType.equals("ssh-dss")) {
BigInteger p = decodeBigInt();
BigInteger q = decodeBigInt();
BigInteger g = decodeBigInt();
BigInteger y = decodeBigInt();
KeySpec spec = new DSAPublicKeySpec(y, p, q, g);
key = KeyFactory.getInstance("DSA").generatePublic(spec);
} else {
throw new IllegalArgumentException("unknown type " + keyType);
}
}
}
final SshServer sshd = SshServer.setUpDefaultServer();
final Map<ServerSession, PublicKey> sessionKeys = new HashMap();
class AuthorizedKeys extends HashMap<String,AuthorizedKeyEntry> {
private File file;
public void load(File file) throws Exception {
this.file = file;
Scanner scanner = new Scanner(file).useDelimiter("\n");
while (scanner.hasNext())
decodePublicKey(scanner.next());
scanner.close();
}
public void save() throws Exception {
PrintWriter w = new PrintWriter(file);
for (String username : keySet()) {
AuthorizedKeyEntry entry = get(username);
w.print(entry.keyType + " " + entry.pubKey + " " + username + "\n");
}
w.close();
}
public void put(String username, PublicKey key) {
AuthorizedKeyEntry entry = new AuthorizedKeyEntry();
try {
entry.setPubKey(key);
} catch (Exception e) {
e.printStackTrace();
}
super.put(username,entry);
}
private void decodePublicKey(String keyLine) throws Exception {
AuthorizedKeyEntry entry = new AuthorizedKeyEntry();
String[] toks = keyLine.split(" ");
String username = toks[toks.length-1];
for (String part : toks) {
if (part.startsWith("AAAA")) {
entry.setPubKey(part);
//bytes = Base64.decodeBase64(part.getBytes());
break;
}
}
super.put(username,entry);
}
};
final AuthorizedKeys authenticUserKeys = new AuthorizedKeys(); // load authorized_keys
File file = new File("authorized_keys");
file.createNewFile(); // create if not exists
authenticUserKeys.load(file);
sshd.setPort(22);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("key.ser"));
sshd.setShellFactory(new ProcessShellFactory(new String[] { "cmd.exe "}));
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
public boolean authenticate(String username, String password, ServerSession session) {
boolean authentic = false;
try {
new waffle.windows.auth.impl.WindowsAuthProviderImpl().logonUser(username,password);
authentic = true;
//authentic = username != null && username.equals(password+password); // obsecurity :)
if (authentic) {
PublicKey sessionKey = sessionKeys.get(session);
if (sessionKey != null)
authenticUserKeys.put(username, sessionKey); //save entry to authorized_keys
}
} catch (Exception e) {
System.err.println(e);
}
return authentic;
}
});
sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
public boolean authenticate(String username, PublicKey key, ServerSession session) {
sessionKeys.put(session,key);
return key.equals(authenticUserKeys.get(username).getPubKey());
}
});
sshd.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(
new UserAuthPublicKey.Factory()
,new UserAuthPassword.Factory()));
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(
new SftpSubsystem.Factory()));
//workaround for apache sshd 10.0+ (putty)
sshd.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
//new DHGEX256.Factory()
//,new DHGEX.Factory()
new ECDHP256.Factory()
,new ECDHP384.Factory()
,new ECDHP521.Factory()
,new DHG1.Factory()));
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
authenticUserKeys.save();
System.out.println("Stopping");
sshd.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
});
System.out.println("Starting");
try {
sshd.start();
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
static public void main(String[] args) throws Exception {
new SFTPServer().setupSftpServer();
}
}