ftpclient - ¿Biblioteca de servidor de Java SFTP?
sftp java library (8)
Cómo configurar un servidor SFTP usando Apache Mina SSHD :
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();
}
}
Y eso es todo.
¿Hay una biblioteca Java que pueda usarse para implementar un servidor SFTP ?
Estoy tratando de recibir archivos a través de SFTP, pero parece que no puedo encontrar ninguna implementación de un servidor SFTP. Encontré bibliotecas de cliente FTP / SFTP / FTPS y bibliotecas de servidor FTP / FTPS, pero ninguna para un servidor para SFTP.
Para aclarar, estoy tratando de recibir archivos a través de SFTP. No puedo "obtener" o "poner" archivos de mi aplicación en otro servidor existente.
En este momento, mi aplicación permite que los usuarios se conecten al servidor local SFTP de Linux, eliminen los archivos y luego mi aplicación sondea el directorio, pero creo que esta es una implementación deficiente; Odio la idea de directorios de "sondeo", pero desafortunadamente TIENEN que usar SFTP. ¿Alguna sugerencia?
Eche un vistazo a SSHTools (j2ssh) . Incluye un cliente y servidor.
Sin embargo, sondear un directorio no es una mala idea, probablemente sea mucho más confiable que configurar tu propio servidor SFTP usando j2ssh. He perdido la cuenta de la cantidad de aplicaciones que he encontrado que hacen este tipo de sondeo, y generalmente funciona bastante bien.
Intenté hacer MINA 0.10.1 en Windows con lo anterior y solucioné algunos problemas, además necesito una mejor autenticación y soporte de PK (aún no recomendado para uso en producción):
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();
}
}
Solo para completar: la biblioteca SecureBlackbox , que mantenemos, ofrece clases para crear su propio servidor SSH / SFTP en Java (incluido Android).
Sugiero que eches un vistazo a Apache Camel . Es compatible con FTP, FTPS y SFTP
Tenga en cuenta que SFTP no es FTP sobre SSL, ni FTP sobre SSH. El soporte de servidor SFTP requiere una implementación de SSHD en Java. Su mejor apuesta es Apache SSHD,
http://mina.apache.org/sshd-project/
Nunca usé el SFTP pero escuché que es básico pero funcional.
estoy usando jftp http://j-ftp.sourceforge.net/ extraer jftp.jar de j-ftp - *. tgz / j-ftp / dist el único problema - ponen clases de apache dentro de jar (así que tengo que eliminar paquetes common-httpclient, log4j manualmente para evitar dependencias conflictivas)