From 64975c1ea93be30e8431fc30146e2b251e508036 Mon Sep 17 00:00:00 2001 From: creekmoon Date: Wed, 12 Apr 2023 22:43:44 +0800 Subject: [PATCH] =?UTF-8?q?JschUtil=E6=96=B0=E5=A2=9E=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E9=87=8D=E8=BD=BD=E6=96=B9=E6=B3=95=E4=BB=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=A7=81=E9=92=A5=E4=BB=A5byte=E6=95=B0=E7=BB=84=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E8=BD=BD=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/extra/ssh/JschSessionPool.java | 16 ++++ .../java/cn/hutool/extra/ssh/JschUtil.java | 76 +++++++++++++++++++ .../cn/hutool/extra/ssh/JschUtilTest.java | 40 +++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java index 164b7824f..0746324e6 100755 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java @@ -60,6 +60,22 @@ public enum JschSessionPool { return this.cache.get(key, Session::isConnected, ()->JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase)); } + /** + * 获得一个SSH跳板机会话,重用已经使用的会话 + * + * @param sshHost 跳板机主机 + * @param sshPort 跳板机端口 + * @param sshUser 跳板机用户名 + * @param prvkey 跳板机私钥内容 + * @param passphrase 跳板机私钥密码 + * @return SSH会话 + * @since 5.8.18 + */ + public Session getSession(String sshHost, int sshPort, String sshUser, byte[] prvkey, byte[] passphrase) { + final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); + return this.cache.get(key, Session::isConnected, ()->JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase)); + } + /** * 加入Session * diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java index 1e5daaf1f..cd50b0647 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java @@ -69,6 +69,21 @@ public class JschUtil { return JschSessionPool.INSTANCE.getSession(sshHost, sshPort, sshUser, privateKeyPath, passphrase); } + /** + * 获得一个SSH会话,重用已经使用的会话 + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名 + * @param privateKey 私钥内容 + * @param passphrase 私钥密码 + * @return SSH会话 + * @since 5.8.18 + */ + public static Session getSession(String sshHost, int sshPort, String sshUser, byte[] privateKey, byte[] passphrase) { + return JschSessionPool.INSTANCE.getSession(sshHost, sshPort, sshUser, privateKey, passphrase); + } + /** * 打开一个新的SSH会话 * @@ -117,6 +132,42 @@ public class JschUtil { return openSession(sshHost, sshPort, sshUser, privateKeyPath, passphrase, 0); } + /** + * 打开一个新的SSH会话 + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名 + * @param privateKey 私钥内容 + * @param passphrase 私钥文件的密码,可以为null + * @return SSH会话 + * @since 5.8.18 + */ + public static Session openSession(String sshHost, int sshPort, String sshUser, byte[] privateKey, byte[] passphrase) { + return openSession(sshHost, sshPort, sshUser, privateKey, passphrase, 0); + } + + /** + * 打开一个新的SSH会话 + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名 + * @param privateKey 私钥内容 + * @param passphrase 私钥文件的密码,可以为null + * @return SSH会话 + * @since 5.8.18 + */ + public static Session openSession(String sshHost, int sshPort, String sshUser, byte[] privateKey, byte[] passphrase, int timeOut) { + final Session session = createSession(sshHost, sshPort, sshUser, privateKey, passphrase); + try { + session.connect(timeOut); + } catch (JSchException e) { + throw new JschRuntimeException(e); + } + return session; + } + /** * 打开一个新的SSH会话 * @@ -184,6 +235,31 @@ public class JschUtil { return createSession(jsch, sshHost, sshPort, sshUser); } + /** + * 新建一个新的SSH会话,此方法并不打开会话(既不调用connect方法) + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名,如果为null,默认root + * @param privateKey 私钥内容 + * @param passphrase 私钥文件的密码,可以为null + * @return SSH会话 + * @since 5.8.18 + */ + public static Session createSession(String sshHost, int sshPort, String sshUser, byte[] privateKey, byte[] passphrase) { + Assert.isTrue(privateKey != null && privateKey.length > 0, "PrivateKey must be not empty!"); + + final JSch jsch = new JSch(); + final String identityName = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); + try { + jsch.addIdentity(identityName, privateKey, null, passphrase); + } catch (JSchException e) { + throw new JschRuntimeException(e); + } + + return createSession(jsch, sshHost, sshPort, sshUser); + } + /** * 创建一个SSH会话,重用已经使用的会话 * diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ssh/JschUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ssh/JschUtilTest.java index d43f7f2fe..05b1725cb 100755 --- a/hutool-extra/src/test/java/cn/hutool/extra/ssh/JschUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ssh/JschUtilTest.java @@ -7,9 +7,11 @@ import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; +import java.nio.charset.StandardCharsets; + /** * Jsch工具类单元测试 - * + * * @author looly * */ @@ -47,7 +49,7 @@ public class JschUtilTest { sftp.mkDirs("/opt/test/aaa/bbb"); Console.log("OK"); } - + @Test @Ignore public void reconnectIfTimeoutTest() throws InterruptedException { @@ -81,4 +83,38 @@ public class JschUtilTest { public void getSessionTest(){ JschUtil.getSession("192.168.1.134", 22, "root", "aaa", null); } + @Test + @Ignore + public void sftpPrivateKeyTest(){ + Session session = JschUtil.getSession("192.168.1.109", 22, "root", ("-----BEGIN RSA PRIVATE KEY-----\n" + + "MIIEpAIBAAKCAQEA5SJ1bjhSA0uQJjbbF/LCFiQvs+nMKgkSnSE+JEll7azv7jnh\n" + + "oBEJdg63tf66oDXCDCMdrYbTtenw1TqkQI2PO8sHuvAZ2UUjqk5zlcrWLiNTCWBw\n" + + "IgIxbVj3/nQliaZSufLxepf8qr6wXWP/PG6p+ScFhTSGjK2Z4r/t9cqPaTtfYJye\n" + + "lbXNsrn0JK99XGj3cNvHzljAHRUCwGRTiHAOJ7Gk9WLGcZQRKuMPrQFMnoLoxZ8m\n" + + "0y+1+AoND6pKLad9/52JCHBi5d7XgwPPEKxVqi8Aklpgb45G4A3FXSKx3tkolXAP\n" + + "3zGm95CwmqdI9Q8t72SkOWDJR4lFPb12k6H0FwIDAQABAoIBAQCTeO4jllQSktuf\n" + + "/MZeT3vjTD73iI5Cr7wvLWoVaLgVlKyHovE4WD7CoQ5UMDJlUrQlo6RCPvibqIm8\n" + + "cxWsBnAdh7rd8hJw6DLgNcXmrrnS0CFtc4g4Gzk8q3pRZueSBF5SF66bvJ5+NmTE\n" + + "dsubVY5IMXk4FmpSuJjGe8jn3QsYKkptOa/s28UekaWzqnstIx42IgS33w7qpUx9\n" + + "v0XKoOCj41HxwGYexNmOiIufh6dEzZtNZGQb+f7JiIpbClpCXO0Dfi+jkNOBjI6Z\n" + + "VMLxIdAZpb9Q97g03hWxH+ZQ9UBeYc9n4p2UzKMnXMBM0lu/cx++hyu6OfAxL8Yr\n" + + "eeZEMIrBAoGBAPslHABM0tCf2UC0vs0mfQFqQiO+Mu9Lp6wGbtvNPt+aNdw+ia+g\n" + + "CPcvBWdpMKq6eg8XEwLZ59YyoBDlipCG4h/5Xq4wyf77ydamy9mdH6nOcuUDy9KH\n" + + "07O39wDdU8EH9Jq29lUYIQgkakRGpi45unq10eo8zAy0ggN1hgI1tYwpAoGBAOmQ\n" + + "bB8hj1e1ozrrMWSv/xIntmRGswR+RwLCJECJy/Oai3SvdB9L1Rh1SUOD6Q/vakXd\n" + + "pYAzEkEAxm6h+YecxhlwiOFi8rLAWYMLu31LH7WGGVM7SvwLxB/YmL/hpZ0Jqrc6\n" + + "Au8MoQtFDtP7IntRkC70Sx7GoKqKudFJlnzyv4Y/AoGAHImn9+TC48/2KOMg90DT\n" + + "XZDMeTFIqmZnZCXK/RECfvgP/LnifWFrA2OFcq3CSPQtoH9XurA2JuHTzHe42hlp\n" + + "ooZ8msCSg3XrBogni8/N5EbASYO36nFivf4+hAuiU8HqqpX1wc+fGUTCCoYYphIL\n" + + "PZxhgQNtkFgGmgwFsUSXH5kCgYEAtvxoSSeQ1yW+Qb3cD8d3LjEgy4U8YavRVI7n\n" + + "ugx7VlphIcUIVDCkPio9gQDKyqpG93/EVyEsDvNdg3WxOpcP+QRaqUJNZNAgEPRT\n" + + "KsF9kUkDdFsCz18kg9K9Ma/Ggbb+Idj4TXL2hQ7QpDGf/T+Ul8TbSbxSSeqv1BE0\n" + + "LqY8eR8CgYBqzKpZcqnNuuwZgdLEnZ/rQoeubw4cHoMWBOkP0N/+mgcE/eEpkr0n\n" + + "9llf+wJg96adgqhwlEHkOMQdsF+FfQA5yJWW4FHA8bfA9YsxjBgheL2RU1Z2iTp4\n" + + "aLmoAsh17p8MGk/3Zfh10t3tq4c67WlFS2kX2qPBXuwDnm51iNyp2A==\n" + + "-----END RSA PRIVATE KEY-----\n").getBytes(StandardCharsets.UTF_8), null); + Sftp sftp = JschUtil.createSftp(session); + sftp.mkDirs("/opt/test/aaa1/bbb1"); + Console.log("OK"); + } }