From fc8512af27dd0d0a5a477944181318f51f66a440 Mon Sep 17 00:00:00 2001 From: Greg Knox Date: Sat, 28 Dec 2024 13:55:33 +1000 Subject: [PATCH] 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());