这个应用需要依赖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,可以说非常年轻,在商用的产品中使用时,需要考虑风险。