From d27f91c0830ae12515f7b9cae3e6278989fc32e7 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 24 Sep 2023 19:12:15 +0800 Subject: [PATCH] fix code --- .../org/dromara/hutool/extra/ssh/Session.java | 7 + .../ssh/engine/ganymed/GanymedSession.java | 6 + .../extra/ssh/engine/jsch/JschSession.java | 41 +++--- .../extra/ssh/engine/mina/MinaSession.java | 123 ++++++++++++++++++ .../extra/ssh/engine/mina/MinaUtil.java | 68 ++++++++++ .../extra/ssh/engine/sshj/SshjSession.java | 6 +- 6 files changed, 222 insertions(+), 29 deletions(-) create mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaSession.java create mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaUtil.java diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java index 9f4380817..4f5a588d3 100644 --- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java @@ -22,4 +22,11 @@ import java.io.Closeable; * @author looly */ public interface Session extends Wrapper, Closeable { + + /** + * 是否连接状态 + * + * @return 是否连接状态 + */ + boolean isConnected(); } diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/ganymed/GanymedSession.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/ganymed/GanymedSession.java index f1af936f8..e5173bf10 100644 --- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/ganymed/GanymedSession.java +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/ganymed/GanymedSession.java @@ -75,6 +75,12 @@ public class GanymedSession implements Session { return raw; } + @Override + public boolean isConnected() { + // 未找到合适的方法判断是否在线 + return true; + } + @Override public void close() throws IOException { if (raw != null) { diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java index 374ddb448..bc2d23f12 100644 --- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java @@ -60,12 +60,7 @@ public class JschSession implements Session { return this.raw; } - /** - * 是否连接状态 - * - * @return 是否连接状态 - */ - @SuppressWarnings("BooleanMethodIsAlwaysInverted") + @Override public boolean isConnected() { return null != this.raw && this.raw.isConnected(); } @@ -103,16 +98,15 @@ public class JschSession implements Session { * @throws SshException 端口绑定失败异常 */ public boolean bindLocalPort(final String remoteHost, final int remotePort, final String localHost, final int localPort) throws SshException { - if (!isConnected()) { - return false; + if (isConnected()) { + try { + this.raw.setPortForwardingL(localHost, localPort, remoteHost, remotePort); + } catch (final JSchException e) { + throw new SshException(e, "From [{}:{}] mapping to [{}:{}] error!", remoteHost, remotePort, localHost, localPort); + } + return true; } - - try { - this.raw.setPortForwardingL(localHost, localPort, remoteHost, remotePort); - } catch (final JSchException e) { - throw new SshException(e, "From [{}:{}] mapping to [{}:{}] error!", remoteHost, remotePort, localHost, localPort); - } - return true; + return false; } /** @@ -139,16 +133,15 @@ public class JschSession implements Session { * @throws SshException 端口绑定失败异常 */ public boolean bindRemotePort(final int bindPort, final String host, final int port) throws SshException { - if (!isConnected()) { - return false; + if (isConnected()) { + try { + this.raw.setPortForwardingR(bindPort, host, port); + } catch (final JSchException e) { + throw new SshException(e, "From [{}] mapping to [{}] error!", bindPort, port); + } + return true; } - - try { - this.raw.setPortForwardingR(bindPort, host, port); - } catch (final JSchException e) { - throw new SshException(e, "From [{}] mapping to [{}] error!", bindPort, port); - } - return true; + return false; } /** diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaSession.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaSession.java new file mode 100644 index 000000000..f6d6aa5aa --- /dev/null +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaSession.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.extra.ssh.engine.mina; + +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ChannelShell; +import org.apache.sshd.client.session.ClientSession; +import org.dromara.hutool.core.io.IORuntimeException; +import org.dromara.hutool.core.io.IoUtil; +import org.dromara.hutool.extra.ssh.Connector; +import org.dromara.hutool.extra.ssh.Session; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; + +/** + * Apache MINA SSHD(https://mina.apache.org/sshd-project/)会话封装 + * + * @author looly + */ +public class MinaSession implements Session { + + private final SshClient sshClient; + private final ClientSession raw; + + /** + * 构造 + * + * @param connector 连接信息 + */ + public MinaSession(final Connector connector) { + this.sshClient = MinaUtil.openClient(); + this.raw = MinaUtil.openSession(this.sshClient, connector); + } + + @Override + public Object getRaw() { + return this.raw; + } + + @Override + public boolean isConnected() { + return null != this.raw && this.raw.isOpen(); + } + + @Override + public void close() throws IOException { + IoUtil.closeQuietly(this.raw); + if (null != this.sshClient) { + this.sshClient.stop(); + } + IoUtil.closeQuietly(this.sshClient); + } + + /** + * 执行Shell命令 + * + * @param cmd 命令 + * @param charset 发送和读取内容的编码 + * @return 结果 + */ + public String exec(final String cmd, final Charset charset) { + return exec(cmd, charset, System.err); + } + + /** + * 执行Shell命令(使用EXEC方式) + *

+ * 此方法单次发送一个命令到服务端,不读取环境变量,执行结束后自动关闭channel,不会产生阻塞。 + *

+ * 参考:https://github.com/apache/mina-sshd/blob/master/docs/client-setup.md#running-a-command-or-opening-a-shell + * + * @param cmd 命令 + * @param charset 发送和读取内容的编码 + * @param errStream 错误信息输出到的位置 + * @return 执行结果内容 + */ + public String exec(final String cmd, final Charset charset, final OutputStream errStream) { + try { + return this.raw.executeRemoteCommand(cmd, errStream, charset); + } catch (final IOException e) { + throw new IORuntimeException(e); + } + } + + /** + * 执行Shell命令 + *

+ * 此方法单次发送一个命令到服务端,自动读取环境变量,执行结束后自动关闭channel,不会产生阻塞。 + *

+ * + * @param cmd 命令 + * @param charset 发送和读取内容的编码 + * @param errStream 异常输出位置 + * @return 结果 + */ + public String execByShell(final String cmd, final Charset charset, final OutputStream errStream){ + final ChannelShell shellChannel; + try { + shellChannel = this.raw.createShellChannel(); + if(null != errStream){ + shellChannel.setErr(errStream); + } + shellChannel.open().verify(); + } catch (final IOException e) { + throw new IORuntimeException(e); + } + + IoUtil.write(shellChannel.getInvertedIn(), charset, false, cmd); + return IoUtil.read(shellChannel.getInvertedOut(),charset); + } +} diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaUtil.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaUtil.java new file mode 100644 index 000000000..c91ddd58c --- /dev/null +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/mina/MinaUtil.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.extra.ssh.engine.mina; + +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.session.ClientSession; +import org.dromara.hutool.core.io.IORuntimeException; +import org.dromara.hutool.extra.ssh.Connector; + +import java.io.IOException; + +/** + * Apache MINA SSHD(https://mina.apache.org/sshd-project/)相关工具类 + * + * @author looly + */ +public class MinaUtil { + + /** + * 打开一个客户端对象 + * @return 客户端对象 + */ + public static SshClient openClient(){ + final SshClient sshClient = SshClient.setUpDefaultClient(); + sshClient.start(); + + return sshClient; + } + + /** + * 打开一个新的Session + * + * @param sshClient 客户端 + * @param connector 连接信息 + * @return {@link ClientSession} + */ + public static ClientSession openSession(final SshClient sshClient, final Connector connector){ + final ClientSession session; + final boolean success; + try { + session = sshClient + .connect(connector.getUser(), connector.getHost(), connector.getPort()) + .verify() + .getSession(); + + session.addPasswordIdentity(connector.getPassword()); + success = session.auth().verify().isSuccess(); + } catch (final IOException e) { + throw new IORuntimeException(e); + } + + if(!success){ + throw new IORuntimeException("Authentication failed."); + } + + return session; + } +} diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSession.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSession.java index 9ff9cf2c9..93847f289 100644 --- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSession.java +++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSession.java @@ -74,11 +74,7 @@ public class SshjSession implements Session { return raw; } - /** - * 是否连接状态 - * - * @return 是否连接状态 - */ + @Override public boolean isConnected() { return null != this.raw && (null == this.ssh || this.ssh.isConnected()); }