From fcb336b4530964b7c3567f1098f9a568eb04867f Mon Sep 17 00:00:00 2001 From: Greg Knox Date: Sat, 28 Dec 2024 13:54:50 +1000 Subject: [PATCH 1/4] Added SocketClient.connectVia(InputStream, OutputStream) method for ProxyCommand support (#970) --- src/main/java/net/schmizz/sshj/SocketClient.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/net/schmizz/sshj/SocketClient.java b/src/main/java/net/schmizz/sshj/SocketClient.java index e4809e0d..9ccc24fd 100644 --- a/src/main/java/net/schmizz/sshj/SocketClient.java +++ b/src/main/java/net/schmizz/sshj/SocketClient.java @@ -94,6 +94,16 @@ public void connectVia(Channel channel, String hostname, int port) throws IOExce onConnect(); } + public void connectVia(InputStream input, OutputStream output) throws IOException { + this.hostname = null; + this.port = -1; + this.input = input; + this.output = output; + this.tunneled = true; + onConnect(); + } + + /** Connect to a remote address via a direct TCP/IP connection from the server. */ public void connectVia(DirectConnection directConnection) throws IOException { connectVia(directConnection, directConnection.getRemoteHost(), directConnection.getRemotePort()); From fc8512af27dd0d0a5a477944181318f51f66a440 Mon Sep 17 00:00:00 2001 From: Greg Knox Date: Sat, 28 Dec 2024 13:55:33 +1000 Subject: [PATCH 2/4] Added ProxyCommand example (#970) --- .../schmizz/sshj/examples/ProxyCommand.java | 65 +++++++++++++++++++ .../java/net/schmizz/sshj/SocketClient.java | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java diff --git a/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java b/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java new file mode 100644 index 00000000..df5867bf --- /dev/null +++ b/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java @@ -0,0 +1,65 @@ +package net.schmizz.sshj.examples; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.TimeUnit; + +import net.schmizz.sshj.SSHClient; +import net.schmizz.sshj.common.IOUtils; +import net.schmizz.sshj.connection.channel.direct.Session; +import net.schmizz.sshj.transport.verification.PromiscuousVerifier; + +/** + * This example uses a separate process to handle I/O, similar to the "ProxyCommand" directive in openssh. + */ +public class ProxyCommand { + public static void main(String... args) + throws IOException { + + /* + for testing, use a locally-installed ssh client (which sort of defeats the purpose of using sshj), + + but for AWS SSM, once you've negotiated the OAuth/SAML login for SSO, + then called StsClient.getCallerIdentity() to check that worked + then called Ec2Client.describeInstances() to convert an IP to an instanceId/availableZone combo + then called Ec2InstanceConnectClient.sendSSHPublicKey() to open a 60-second login window + you'd create an SSM ssh session via something like + + ProcessBuilder pb = new ProcessBuilder("aws", "ssm", "start-session", "--region", "ap-southeast-2", "--target", instanceId, + "--document-name", "AWS-StartSSHSession", + "--parameters", "portNumber=22" + + and wire up the inputStreams/outputStreams from that instead. + */ + + + // for testing only + String jumpBox = "localhost"; // this would typically be something remote + String targetBox = "localhost"; // this would typically be something even more remote + ProcessBuilder pb = new ProcessBuilder("ssh", jumpBox, "-W", targetBox + ":22"); + Process proc = pb.start(); + InputStream recvStream = proc.getInputStream(); + OutputStream xmitStream = proc.getOutputStream(); + + SSHClient ssh = new SSHClient(); + ssh.addHostKeyVerifier(new PromiscuousVerifier()); + ssh.connectVia(recvStream, xmitStream); + + try { + ssh.authPublickey(System.getProperty("user.name")); + final Session session = ssh.startSession(); + try { + final Session.Command cmd = session.exec("ping -c 1 google.com"); + System.out.println(IOUtils.readFully(cmd.getInputStream()).toString()); + cmd.join(5, TimeUnit.SECONDS); + System.out.println("\n** exit status: " + cmd.getExitStatus()); + } finally { + session.close(); + } + } finally { + ssh.disconnect(); + ssh.close(); + } + } +} diff --git a/src/main/java/net/schmizz/sshj/SocketClient.java b/src/main/java/net/schmizz/sshj/SocketClient.java index 9ccc24fd..dbc6e4ed 100644 --- a/src/main/java/net/schmizz/sshj/SocketClient.java +++ b/src/main/java/net/schmizz/sshj/SocketClient.java @@ -94,6 +94,7 @@ public void connectVia(Channel channel, String hostname, int port) throws IOExce onConnect(); } + /** Connect using the supplied InputStream and OutputStream. */ public void connectVia(InputStream input, OutputStream output) throws IOException { this.hostname = null; this.port = -1; @@ -103,7 +104,6 @@ public void connectVia(InputStream input, OutputStream output) throws IOExceptio onConnect(); } - /** Connect to a remote address via a direct TCP/IP connection from the server. */ public void connectVia(DirectConnection directConnection) throws IOException { connectVia(directConnection, directConnection.getRemoteHost(), directConnection.getRemotePort()); From c37ec155212bb5d0022aa3f7ad9755630bac9096 Mon Sep 17 00:00:00 2001 From: Greg Knox Date: Sat, 28 Dec 2024 14:08:32 +1000 Subject: [PATCH 3/4] Comment only (#970) --- .../src/main/java/net/schmizz/sshj/examples/ProxyCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java b/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java index df5867bf..9858035f 100644 --- a/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java +++ b/examples/src/main/java/net/schmizz/sshj/examples/ProxyCommand.java @@ -18,7 +18,7 @@ public static void main(String... args) throws IOException { /* - for testing, use a locally-installed ssh client (which sort of defeats the purpose of using sshj), + for testing, uses a locally-installed ssh client, but for AWS SSM, once you've negotiated the OAuth/SAML login for SSO, then called StsClient.getCallerIdentity() to check that worked @@ -47,7 +47,7 @@ public static void main(String... args) ssh.connectVia(recvStream, xmitStream); try { - ssh.authPublickey(System.getProperty("user.name")); + ssh.authPublickey(System.getProperty("user.name")); final Session session = ssh.startSession(); try { final Session.Command cmd = session.exec("ping -c 1 google.com"); From c6b019e8d9624c6829175ab5ee2da2df24d7e369 Mon Sep 17 00:00:00 2001 From: Greg Knox Date: Sat, 28 Dec 2024 14:24:50 +1000 Subject: [PATCH 4/4] NullPointerException (#970) --- src/main/java/net/schmizz/sshj/SocketClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/SocketClient.java b/src/main/java/net/schmizz/sshj/SocketClient.java index dbc6e4ed..0c5f530c 100644 --- a/src/main/java/net/schmizz/sshj/SocketClient.java +++ b/src/main/java/net/schmizz/sshj/SocketClient.java @@ -96,8 +96,8 @@ public void connectVia(Channel channel, String hostname, int port) throws IOExce /** Connect using the supplied InputStream and OutputStream. */ public void connectVia(InputStream input, OutputStream output) throws IOException { - this.hostname = null; - this.port = -1; + this.hostname = "localhost"; + this.port = 65535; this.input = input; this.output = output; this.tunneled = true;