1. 程式人生 > >在Java應用中嵌入sshd服務

在Java應用中嵌入sshd服務

這個應用需要依賴apache mina的子專案sshd,專案主頁http://mina.apache.org/sshd-project/index.html,當前版本號為0.8.0。這裡的sshd和Linux下的sshd服務在特性上類似,但卻是使用純Java語言實現的,為Java應用提供了自定義ssh協議接入的能力。相關的API使用比較簡單,見如下程式碼樣例,API的含義也在註釋中做了簡單的說明。由於我在家沒有Linux環境,因而只在Windows平臺做了簡單的試驗,比如使用者登入、校驗口令等,但不能體驗sftp接入控制的實現。

package com.sftp;

import java.io.IOException;
import java.util.EnumSet;

import org.apache.sshd.SshServer;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.FileSystemFactory;
import org.apache.sshd.server.FileSystemView;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.SshFile;
import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.ProcessShellFactory;

public class SshdServer {

    public static void main(final String[] args) throws Exception {
        final SshServer sshd = SshServer.setUpDefaultServer();// 工廠方法,使用預設屬性建立ssh服務物件
        if (SecurityUtils.isBouncyCastleRegistered()) {// 儲存會話安全校驗資訊,key.pem和key.ser為檔名
            sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider("key.pem"));
        }
        else {
            sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("key.ser"));
        }
        if (OsUtils.isUNIX()) { // 在Unix環境下,使用系統自帶的sh來執行命令
            sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" }, EnumSet
                            .of(org.apache.sshd.server.shell.ProcessShellFactory.TtyOptions.ONlCr)));
        }
        else { // 在Windows平臺下,只能使用標準的cmd命令
            sshd.setShellFactory(new ProcessShellFactory(new String[] { "cmd.exe " }, EnumSet.of(
                            org.apache.sshd.server.shell.ProcessShellFactory.TtyOptions.Echo,
                            org.apache.sshd.server.shell.ProcessShellFactory.TtyOptions.ICrNl,
                            org.apache.sshd.server.shell.ProcessShellFactory.TtyOptions.ONlCr)));
        }
// 在Windows平臺,如果安裝了Cygwin,還可以使用如下的呼叫,把使用者的輸入委託給Cygwin的shell
        sshd.setShellFactory(new ProcessShellFactory(new String[] { "D:\\cygwin\\bin\\bash", "-i", "-l" }));

        sshd.setPasswordAuthenticator(new PasswordAuthenticator() { // 使用使用者名稱和口令方式,自定義對接入使用者的校驗
            public boolean authenticate(final String username, final String password, final ServerSession serversession) {
// 我本地的測試程式碼只是為了演示使用方法,所以只是簡單實現,對於一切來訪使用者都大開綠燈
                return true;
            }
        });
        sshd.setHost("127.0.0.1");// 指定提供ssh服務的IP
        sshd.setPort(2022); // 指定ssh服務的埠,為了避免影響系統的服務,這裡使用了自定義的2022埠
        sshd.setFileSystemFactory(new FileSystemFactory() {// 如果需要使用ssh協議來提供檔案下載、上傳能力,則需要實現FileSystemFactory和SshFile介面

            public FileSystemView createFileSystemView(final Session session) throws IOException {
                return new FileSystemView() {

                    public SshFile getFile(final SshFile sshfile, final String s) {
                        return null;
                    }

                    public SshFile getFile(final String s) {
                        return null;
                    }
                };
            }
        });
        sshd.start();// 啟動ssh服務

    }

}

使用自定義的ssh服務有如下幾點好處:

1、不需要建立作業系統的賬號。在Linux環境下,如果要使用預設的ssh服務,事先需要建立一個作業系統的賬號,這樣存在安全隱患,對於心存惡意的來訪者,系統被攻破只是時間問題;

2、可以通過實現FileSytemFactory介面和SshFile介面控制來訪使用者通過sftp訪問到的目錄及檔案列表,避免來訪者對無權路徑的訪問;

不過這個專案當前版本號為0.8.0,可以說非常年輕,在商用的產品中使用時,需要考慮風險。