2010-06-19 33 views
32

Có thư viện Java nào có thể được sử dụng để triển khai máy chủ SFTP không?Thư viện máy chủ SFTP Java?

Tôi đang cố gắng nhận tệp qua SFTP, nhưng dường như tôi không thể tìm thấy bất kỳ triển khai nào của máy chủ SFTP. Tôi đã tìm thấy thư viện máy chủ FTP/SFTP/FTPS và thư viện máy chủ FTP/FTPS nhưng không tìm thấy máy chủ cho SFTP.

Để làm rõ, tôi đang cố gắng để nhận được tệp qua SFTP. Không "tải" hoặc "đặt" các tệp từ ứng dụng của tôi vào một máy chủ hiện có khác. Ngay bây giờ ứng dụng của tôi cho phép người dùng kết nối với máy chủ SFTP linux cục bộ, thả các tệp, và sau đó ứng dụng của tôi thăm dò thư mục, nhưng tôi cảm thấy rằng đây là một triển khai kém; Tôi ghét ý tưởng của các thư mục "bỏ phiếu", nhưng tiếc là họ phải sử dụng SFTP. Bất kỳ đề xuất?

Trả lời

40

Làm thế nào để thiết lập một máy chủ SFTP sử dụng 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(); 
    } 
} 

Và đó là tất cả.

+0

Điều này tạo ra một máy chủ SSH mà hầu hết các khách hàng hiện đại sẽ từ chối kết nối với :-(Xem http://stackoverflow.com/questions/33690689/no-matching-host-key-type-found-apache-mina-sftp-server – Rich

0
+0

Các liên kết mà bạn cung cấp không phải là một thư viện java, nó là một sản phẩm độc lập. Ngoài ra, nó dường như không sử dụng SFTP, mà thay vào đó là FTPS. Bạn đã đọc bất cứ điều gì về sản phẩm này, hay bạn chỉ cần chọn liên kết thứ hai khi bạn googled "java secure ftp"? –

+5

Lời xin lỗi của tôi, tôi đã đi qua một liên kết nói rằng javasecureftpd đang triển khai SFTP và tôi nghĩ nó đã xảy ra. Dù sao, bạn không phải là có nghĩa là, tôi chỉ cố gắng để giúp bạn. – pakore

-1

tôi đề nghị bạn hãy xem Apache Camel. Nó hỗ trợ cả FTP, FTPS cũng như SFTP

+1

Đây là trích dẫn trực tiếp từ trang web Apache Camel mà bạn đã liên kết: "Thành phần này cung cấp quyền truy cập vào hệ thống tệp từ xa qua giao thức FTP và SFTP". Điểm chính là "quyền truy cập vào hệ thống tệp từ xa", điều này không cho phép bạn lưu trữ máy chủ SFTP của riêng mình. –

4

Hãy lưu ý rằng SFTP không phải là FTP qua SSL, cũng như FTP qua SSH. Hỗ trợ máy chủ SFTP yêu cầu triển khai SSHD trong Java. Tốt nhất là Apache sshd,

http://mina.apache.org/sshd-project/

tôi không bao giờ sử dụng SFTP nhưng tôi nghe nói đó là cơ bản nhưng chức năng.

+0

Điểm tốt. Thuật ngữ là hết sức khó hiểu. Vì vậy, nhiều người nghĩ rằng SFTP là "Secure FTP", hoặc một phiên bản của FTP chạy trên SSL hoặc SSH, hoặc một cái gì đó (và nó không phải). Tôi ước họ đã gọi nó là một thứ hoàn toàn khác. – hotshot309

+0

Liên kết đã chết btw – Tommy

1

Hãy xem SSHTools (j2ssh). Nó bao gồm một máy khách và máy chủ.

Tuy nhiên, bỏ phiếu một thư mục không phải là một ý tưởng tồi - nó có thể đáng tin cậy hơn nhiều so với việc thiết lập máy chủ SFTP của riêng bạn bằng cách sử dụng j2ssh. Tôi đã mất số lượng ứng dụng tôi đã gặp phải thực hiện loại bỏ phiếu này và nó thường hoạt động khá tốt.

+0

Tôi không biết nếu nó đã làm trong quá khứ nhưng nó dường như không cung cấp một (n mã nguồn mở) máy chủ bây giờ. Có lẽ nó đã được chuyển sang cung cấp thương mại của họ. –

0

tôi đang sử dụng jftp http://j-ftp.sourceforge.net/ chiết xuất từ ​​jftp.jar jftp -. * Tgz/jftp/quận vấn đề duy nhất - họ đặt lớp apache bên trong có jar (vì vậy tôi phải loại bỏ chung httpclient, gói log4j bằng tay để tránh phụ thuộc mâu thuẫn)

+0

Tại sao bỏ phiếu xuống? –

+1

Có thể do câu hỏi về máy chủ SFTP, không phải là máy khách. – FelixM

1

Chỉ để hoàn thành - thư viện SecureBlackbox (ấn bản Java) của chúng tôi cung cấp các lớp học để tạo máy chủ SSH/SFTP của riêng bạn trong Java (bao gồm Android).

+3

là quảng cáo thương mại. – Alvins

2

tôi đã cố gắng làm MINA 0.10.1 trên Windows với bên trên và cố định một số vấn đề, cộng với tôi cần phải xác thực tốt hơn và hỗ trợ PK (vẫn không được khuyến khích sử dụng sản xuất):

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(); 
    } 
}