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