踩坑记录:java连接ssh的问题
一、概述
手里有个CS架构的老系统,服务端要用SSH的方式传文件。没想到写了两天!遇到一堆问题,于是记录下。(老系统真恶心啊!)
一、第一个!
问题:
一开始使用原有的jsch包,但是ssh连不上,查资料后发现,服务器的ssh版本升级了,而且中央仓库的jsch包十几年不更新了,缺少很多密钥算法。
解决
改为使用apache的sshd包,我看一直有更新,因为线上服务器的ssh更高,于是用了比较新的版本。而且需要三个包,详细代码后面有。
sshd-core
sshd-sftp
sshd-common (这里和第二个坑有关!)
第二个!
问题
使用sshd后,本地测试没问题,而放到测试服务器,服务端就一直报找不到sshd下面的ClientSession。
分析
因为是ClassLoader报的,原以为是二次代理,导致的ClassLoader无法获取第二次代理的外部jar(老架构的service全是用代理模式获取的,之前遇到过因二次代理导致service中无法获取hutool的问题)。后来想想这里不存在二次代理的问题,应该就只是ClassLoader获取外部jar包,于是找了下这个类,谁知。。(这里是idea用maven看的,netbean看起来实在麻烦)
core和common都有org.apache.sshd.client包!ClientSession在core里(不理解为啥不都装到core里!)
ClassLoader会先去找上面的common包找org.apache.sshd.client.ClientSession,找不到就不接着找了。
解决
用URLClassLoader去指定加载core里的ClientSession,但是想想太麻烦算了,于是准备把ssh传文件写成脚本,service去调用脚本的方式。
第三个!
问题
开始写脚本,因为服务器没有go环境,python也有各种问题不想用,就用java写了个脚本。
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.kex.DHGClient;
import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.scp.client.ScpClient;
import org.apache.sshd.scp.client.ScpClientCreator;
import java.util.Arrays;
/**
* ssh执行器
*
* @author zilong
* @date 2023/12/14
**/
public class SshExcute {
public static void main(String args[]) {
String username = null;
String password = null;
String ip = null;
String sourcePath = null;
String targetPath = null;
String fileName = null;
if (args[0] != null) {
username = args[0];
}
if (args[1] != null) {
password = args[1];
}
if (args[2] != null) {
ip = args[2];
}
if (args[3] != null) {
sourcePath = args[3];
}
if (args[4] != null) {
targetPath = args[4];
}
if (args[5] != null) {
fileName = args[5];
}
sendFile(
username,
password,
ip,
sourcePath,
targetPath,
fileName
);
}
public static boolean sendFile (
String username, String password, String ip, String sourcePath,
String targetPath, String fileName
) {
Security.addProvider(new BouncyCastleProvider());
int port = 22;
try {
sourcePath = sourcePath + "/";
String osName = System.getProperty("os.name");
if (osName.toUpperCase().contains("WINDOWS")) {
sourcePath = sourcePath.replaceAll("/", "\\\\");
}
String source = sourcePath + fileName;
String target = targetPath + "/" + fileName;
SshClient client = SshClient.setUpDefaultClient();
client.start();
ClientSession session = client.connect(username, ip, port).verify().getSession();
session.addPasswordIdentity(password);
boolean isSuccess = session.auth().verify().isSuccess();
if (isSuccess) {
ScpClientCreator creator = ScpClientCreator.instance();
ScpClient scpClient = creator.createScpClient(session);
System.out.println("Scp beginning...");
scpClient.upload(source, target, ScpClient.Option.Recursive);
System.out.println("Scp finished...");
if (scpClient != null) {
scpClient = null;
}
if (session != null && session.isOpen()) {
session.close();
}
if (client != null && client.isOpen()) {
client.stop();
client.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
java.lang.IllegalArgumentException: KeyExchangeFactories not set
at org.apache.sshd.common.util.ValidateUtils.createFormattedException(ValidateUtils.java:213)
at org.apache.sshd.common.util.ValidateUtils.throwIllegalArgumentException(ValidateUtils.java:179)
at org.apache.sshd.common.util.ValidateUtils.checkTrue(ValidateUtils.java:174)
at org.apache.sshd.common.util.ValidateUtils.checkNotNullAndNotEmpty(ValidateUtils.java:80)
at org.apache.sshd.common.helpers.AbstractFactoryManager.checkConfig(AbstractFactoryManager.java:513)
at org.apache.sshd.client.SshClient.checkConfig(SshClient.java:389)
at org.apache.sshd.client.SshClient.start(SshClient.java:450)
at Ss.sendFile(Ss.java:81)
at Ss.main(Ss.java:46)
分析
debug看源码
本地测试是有这些密钥算法的,但是服务器上没有,不知道从哪获取的,手动加上试试
又报错
java.security.NoSuchAlgorithmException: Algorithm ECDH not avaliable
感觉还是得从源头下手,应该是服务器缺少相关环境,于是百度,发现是jre缺少加密算法相关的包导致的,那么手动加下就好了。
The Bouncy Castle Crypto package
解决
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.kex.DHGClient;
import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.scp.client.ScpClient;
import org.apache.sshd.scp.client.ScpClientCreator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
import java.util.Arrays;
/**
* ssh执行器
*
* @author zilong
* @date 2023/12/14
**/
public class SshExcute {
public static void main(String args[]) {
String username = null;
String password = null;
String ip = null;
String sourcePath = null;
String targetPath = null;
String fileName = null;
if (args[0] != null) {
username = args[0];
}
if (args[1] != null) {
password = args[1];
}
if (args[2] != null) {
ip = args[2];
}
if (args[3] != null) {
sourcePath = args[3];
}
if (args[4] != null) {
targetPath = args[4];
}
if (args[5] != null) {
fileName = args[5];
}
sendFile(
username,
password,
ip,
sourcePath,
targetPath,
fileName
);
}
public static boolean sendFile (
String username, String password, String ip, String sourcePath,
String targetPath, String fileName
) {
Security.addProvider(new BouncyCastleProvider());
int port = 22;
try {
sourcePath = sourcePath + "/";
String osName = System.getProperty("os.name");
if (osName.toUpperCase().contains("WINDOWS")) {
sourcePath = sourcePath.replaceAll("/", "\\\\");
}
String source = sourcePath + fileName;
String target = targetPath + "/" + fileName;
SshClient client = SshClient.setUpDefaultClient();
client.setKeyExchangeFactories(Arrays.<KeyExchangeFactory>asList(
DHGClient.newFactory(BuiltinDHFactories.ecdhp521),
DHGClient.newFactory(BuiltinDHFactories.ecdhp384),
DHGClient.newFactory(BuiltinDHFactories.ecdhp256),
DHGEXClient.newFactory(BuiltinDHFactories.dhgex256),
DHGClient.newFactory(BuiltinDHFactories.dhg18_512),
DHGClient.newFactory(BuiltinDHFactories.dhg17_512),
DHGClient.newFactory(BuiltinDHFactories.dhg16_512),
DHGClient.newFactory((BuiltinDHFactories.dhg15_512)),
DHGClient.newFactory(BuiltinDHFactories.dhg14_256)));
client.start();
ClientSession session = client.connect(username, ip, port).verify().getSession();
session.addPasswordIdentity(password);
boolean isSuccess = session.auth().verify().isSuccess();
if (isSuccess) {
ScpClientCreator creator = ScpClientCreator.instance();
ScpClient scpClient = creator.createScpClient(session);
System.out.println("Scp beginning...");
scpClient.upload(source, target, ScpClient.Option.Recursive);
System.out.println("Scp finished...");
if (scpClient != null) {
scpClient = null;
}
if (session != null && session.isOpen()) {
session.close();
}
if (client != null && client.isOpen()) {
client.stop();
client.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!