SSH是任何一种every-day工具Linux系统管理工作。这是访问网络上的远程计算机,传输数据和执行远程命令的一种简单而安全的方法。除了交互模式之外,还有许多工具可以使依赖于现有技术的远程任务实现自动化ssh
服务器/客户端架构。对于这样一种工具,您可以阅读有关在Ubuntu上可以使用例如。您还可以找到ssh客户端的许多实现,但是如何从代码访问ssh提供的功能呢?
JSch是一个用Java实现ssh协议的项目。借助它的帮助,您可以构建能够连接到远程或本地并与之交互的应用程序SSH服务器。这样,您的应用程序就可以管理您本机ssh客户端可以完成的目标计算机的任何方面,这为已经庞大的Java工具集提供了又一强大的功能。
在本文中,我们将把JSch导入我们的Java项目,并开发最少的必要代码段,以创建可以登录到远程计算机的ssh服务器的应用程序,执行一些命令在远程交互式 shell 中,关闭会话,然后显示输出。这个应用程序将是最小的,但是,它可能会提示它提供的功能。
在本教程中,您将学习:
- 如何将JSch导入Java项目
- 如何设置测试环境
- 如何在自定义类中实现UserInfo接口
- 如何编写启动交互式ssh会话的应用程序
使用的软件要求和约定
类别 | 要求,约定或使用的软件版本 |
---|---|
系统 | 软呢帽30 |
软件 | OpenJDK 1.8,JSch 0.1.55,NetBeans 8.2 |
其他 | 以root身份或通过root特权访问Linux系统sudo 命令。 |
约定 | #-要求给出linux命令可以直接以root用户身份或通过使用root特权以root特权执行sudo 命令$-要求给出linux命令以普通非特权用户身份执行 |
介绍
在JSch的帮助下,我们将开发一个应用程序,尝试登录到localhost
通过ssh
,使用用户名test
和密码test
。我们将假定默认端口22
ssh服务器侦听,并且将接受服务器的指纹而不检查其有效性。成功登录后,我们将执行一些命令,这些命令可以在远程Shell中发出,注销,然后打印收到的所有输出。
我们的工具将包括Fedora桌面(作为客户端和服务器),最新的NetBeans IDE和(在撰写本文时)最新的稳定JSch。但是请注意,这些只是选择的工具。 Java是platform-independent,目标服务器可以在地球的另一端,并且可以是任何运行适当操作系统的操作系统ssh server
。
设置测试环境
我们需要以上凭证才能进行localhost
。在我们的示例中,这意味着我们需要一个名为”test”且密码为”test”的用户。我们还需要一个正在运行的ssh服务器。
添加测试用户
我们将执行useradd
如root
:
# useradd test
并设置新用户的密码:
# passwd test
在这里,我们需要提供两次以上的密码。这适用于临时的环境,也是外界无法访问的测试环境,但是在极有可能不受控制的访问时,请勿使用容易猜到的密码。
检查SSH服务器
我们可以检查状态ssh server
与systemd
:
# systemctl status sshd
如果它没有运行,请启动它:
# systemctl start sshd
在台式机安装上,可能需要执行此步骤,因为其中某些设置在默认情况下不会运行ssh服务器。
测试与本机客户端的连接
如果设置了我们的用户并且该服务正在运行,则我们应该能够使用以上信息登录:
$ ssh test@localhost
我们需要接受主机的指纹并提供密码。如果到了 shell ,我们的测试环境就完成了。
获取并将JSch导入我们的项目
下载档案
为了使用它的功能,我们需要下载JSch项目的字节码。您可以找到适当的链接在JSch主页上。我们需要.jar
Java档案。
在NetBeans中创建项目
首先,我们创建一个新的空项目,名为sshRemoteExample
在NetBeans中。我们可以从File菜单中选择”New Project”。
我们将选择”Java”类别和”Java Application”项目。
我们需要提供项目的名称,在这种情况下为”sshRemoteExample”。
在默认布局上,我们可以在左侧找到”Projects”窗口。在此,我们将右键单击新创建的项目下的”Libraries”节点,然后选择“添加JAR /文件夹”。将打开一个文件选择器窗口,我们需要在其中浏览.jar
从开发者网站下载的文件。
选择之后,如果我们打开”Libraries”节点,则存档应出现在包含的库中。
我们需要实施UserInfo
界面以便在我们的应用程序中使用它。为此,我们需要添加一个新java class
在我们的right-clicking到我们的项目sshremoteexample
在项目窗口中,选择”New”,然后选择“ Java Class …”。
我们将提供名称”sshRemoteExampleUserinfo”作为类名。
添加源代码
对于我们的接口实现,请考虑以下来源。这是我们盲目接受目标指纹的地方。在现实世界中不要这样做。您可以通过在项目窗口中单击该类来编辑源代码,或者如果该类已经打开,请使用源代码窗口顶部的选项卡切换到该类。
package sshremoteexample;
import com.jcraft.jsch.*;
public class sshRemoteExampleUserInfo implements UserInfo {
private final String pwd;
public sshRemoteExampleUserInfo (String userName, String password) {
pwd = password;
}
@Override
public String getPassphrase() {
throw new UnsupportedOperationException("getPassphrase Not supported yet.");
}
@Override
public String getPassword() {
return pwd;
}
@Override
public boolean promptPassword(String string) {
/*mod*/
return true;
}
@Override
public boolean promptPassphrase(String string) {
throw new UnsupportedOperationException("promptPassphrase Not supported yet.");
}
@Override
public boolean promptYesNo(String string) {
/*mod*/
return true;
}
@Override
public void showMessage (String string) {
}
}
我们的主要班级将是sshRemoteExample
具有以下来源的类:
package sshremoteexample;
import com.jcraft.jsch.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class SshRemoteExample {
public static void main(String[] args) {
String host = "localhost";
String user = "test";
String password = "test";
String command = "hostname\ndf -h\nexit\n";
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user,host, 22);
session.setUserInfo(new sshRemoteExampleUserInfo(user, password));
session.connect();
Channel channel = session.openChannel("shell");
channel.setInputStream(new ByteArrayInputStream(command.getBytes(StandardCharsets.UTF_8)));
channel.setOutputStream(System.out);
InputStream in = channel.getInputStream();
StringBuilder outBuff = new StringBuilder();
int exitStatus = -1;
channel.connect();
while (true) {
for (int c; ((c = in.read()) >= 0);) {
outBuff.append((char) c);
}
if (channel.isClosed()) {
if (in.available() > 0) continue;
exitStatus = channel.getExitStatus();
break;
}
}
channel.disconnect();
session.disconnect();
// print the buffer's contents
System.out.print (outBuff.toString());
// print exit status
System.out.print ("Exit status of the execution: " + exitStatus);
if ( exitStatus == 0 ) {
System.out.print (" (OK)\n");
} else {
System.out.print (" (NOK)\n");
}
} catch (IOException | JSchException ioEx) {
System.err.println(ioEx.toString());
}
}
}
请注意,在此示例中,我们hard-code连接所需的每个详细信息:目标主机名,用户名/密码以及要在远程会话中执行的命令字符串。这几乎不是现实生活中的示例,但它可以达到演示目的。
我们可以更改目标和凭据以在远程主机上执行命令。还要注意,远程会话将具有登录用户的特权。我不建议使用具有高特权的用户-例如root
-对于测试,如果目标计算机确实包含有价值的数据或服务。
运行应用程序
我们可以通过单击”Run”菜单中的“运行项目(sshRemoteExample)”直接从IDE直接运行应用程序,这将在源代码下方的输出窗口中提供输出。我们也可以从同一菜单中选择“清理并生成项目(sshRemoteExample)”,在这种情况下,IDE将生成.jar
Java归档文件可以在没有IDE的情况下执行。
提供的输出将显示存档的路径,类似于以下内容(确切的路径可能会因您的IDE设置而异):
To run this application from the command line without Ant, try:
java -jar "/var/projects/sshRemoteExample/dist/sshRemoteExample.jar"
可以猜测,我们可以从命令行运行构建的应用程序,如果一切顺利,它将提供类似于以下内容的输出。
$ java -jar "/var/projects/sshShellExample/dist/sshShellExample.jar"
Last login: Mon Jul 29 14:27:08 2019 from 127.0.0.1
hostname
df -h
exit
[test@test1 ~]$ hostname
test1.linuxconfig.org
[test@test1 ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3,9G 0 3,9G 0% /dev
tmpfs 3,9G 127M 3,8G 4% /dev/shm
tmpfs 3,9G 1,7M 3,9G 1% /run
tmpfs 3,9G 0 3,9G 0% /sys/fs/cgroup
/dev/mapper/fedora_localhost--live-root 49G 15G 32G 32% /
tmpfs 3,9G 6,1M 3,9G 1% /tmp
/dev/sdb1 275G 121G 140G 47% /mnt/hdd_open
/dev/sda2 976M 198M 711M 22% /boot
/dev/mapper/fedora_localhost--live-home 60G 50G 6,9G 88% /home
/dev/sda1 200M 18M 182M 9% /boot/efi
tmpfs 789M 9,7M 779M 2% /run/user/1000
tmpfs 789M 0 789M 0% /run/user/1001
[test@test1 ~]$ exit
logout
Exit status of the execution: 0 (OK)
请注意,您的输出可能会在主机名,卷名和大小上有所不同(如果没有其他区别),但是通常,您应该看到df -h
您将在ssh会话中获得的输出。
最后的想法
这个简单的例子表明了JSch项目的强大功能,尽管有点过分简化了。通过访问测试机和适当的客户端,以下简单命令将提供相同的信息:
$ ssh test@localhost "hostname; df -h"
并且也不会创建交互式会话。如果在命令模式下打开通道,JSch将提供相同的功能:
Channel channel = session.openChannel("command");
这样,您无需使用exit
Shell命令。
该项目的真正力量在于能够通过本机Shell命令连接到远程机器并与之交互,处理输出并以编程方式确定下一步操作的能力。想象一下一个multi-threaded应用程序,该应用程序本身可以管理数百个服务器,您将获得图片。