how to execute remote commands using apache mina sshd



I am trying to execute remote commands on an SSHServer running on my local windows machine.

I am able to run simple command like “whoami” but failing to run something like “java -version” or “dir”

Here is my code so far, can you tell where I am going wrong?

SSHServer.java

import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.command.CommandFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.scp.ScpCommandFactory;
import org.apache.sshd.server.shell.InteractiveProcessShellFactory;
import org.apache.sshd.server.shell.ProcessShellCommandFactory;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SSHServer {

    private SshServer sshServer;
    private static final Logger logger = LoggerFactory.getLogger(SSHServer.class);

    public SSHServer(int port) {
        sshServer = SshServer.setUpDefaultServer();
        initializeServer(port);
    }

    private void initializeServer(int port) {
        sshServer.setPort(port);
        sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
        sshServer.setFileSystemFactory(getFileSystemFactory());
        sshServer.setCommandFactory(getScpCommandFactory());
        sshServer.setPasswordAuthenticator(getPasswordAuthenticator());
        sshServer.setShellFactory(getProcessShellFactory());
        //sshServer.setSessionHeartbeat(SessionHeartbeatController.HeartbeatType.IGNORE, TimeUnit.SECONDS, 5);
    }

    public int getPort() {
        return sshServer.getPort();
    }

    public String getHost() {
        return sshServer.getHost();
    }

    public void startServer() throws IOException {
        sshServer.start();
        logger.debug("SSHServer started on Port: {}", sshServer.getPort());
    }

    public void stopServer() throws IOException {
        sshServer.stop();
        logger.debug("SSHServer stopped...");
    }

    private ScpCommandFactory getScpCommandFactory() {
        CommandFactory myCommandFactory = new CommandFactory() {
            @Override
            public Command createCommand(ChannelSession channelSession, String s) {
                logger.info("Command on SSHServer: {}", s);
                return null;
            }
        };
        return new ScpCommandFactory.Builder().withDelegate(new ProcessShellCommandFactory()).build();
    }

    private VirtualFileSystemFactory getFileSystemFactory() {
        return new VirtualFileSystemFactory() {
            @Override
            public Path getUserHomeDir(SessionContext session) {
                String userHomeDir = System.getProperty("user.home");
                return Paths.get(userHomeDir);
            }
        };
    }

    private PasswordAuthenticator getPasswordAuthenticator() {
        return (username, password, serverSession) -> {
           logger.info("authenticating user: {}", username);
           return true;
        };
    }

    private ProcessShellFactory getProcessShellFactory() {
        return new InteractiveProcessShellFactory();
    }
}

SSHClient.java

import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.future.ConnectFuture;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.session.SessionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SSHClient {

    private SshClient sshClient;
    private String username;
    private String host;
    private String password;
    private int port;
    private static final Logger logger = LoggerFactory.getLogger(SSHClient.class);

    private SSHClient(){}

    public SSHClient(String username, String password, String host, int port) {
        logger.info("Creating SSHClient for username: {} for {}:{}", username, host, port);
        sshClient = SshClient.setUpDefaultClient();
        sshClient.setFileSystemFactory(new VirtualFileSystemFactory() {
            @Override
            public Path getUserHomeDir(SessionContext session) {
                return Paths.get(System.getProperty("user.home"));
            }
        });
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }

    public ClientSession connect()  throws IOException {
        ConnectFuture connectFuture = sshClient.connect(username, host, port).verify();
        logger.info("SSHClient is connected: {}", connectFuture.isConnected());
        return connectFuture.getSession();
    }

    public void startClient() {
        sshClient.start();
        logger.info("SSHClient is started...");
    }

    public void stopClient() {
        sshClient.stop();
        logger.info("SSHClient is stopped...");
    }
}

TestSSH.java

import org.apache.sshd.client.channel.ClientChannel;
import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.session.ClientSession;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.EnumSet;
import java.util.concurrent.TimeUnit;

public class TestSSH {

    public static void main(String[] args) throws IOException {
        SSHServer sshServer = new SSHServer(null, 45018);
        sshServer.startServer();
        SSHClient sshClient = new SSHClient("", "", "localhost", 45018);
        sshClient.startClient();
        ClientSession clientSession = sshClient.connect();
        clientSession.addPasswordIdentity("randompassword");
        System.out.println(clientSession.auth().verify().isSuccess());
                    
        ClientChannel execChannel = clientSession.createChannel(ClientChannel.CHANNEL_EXEC, "whoami");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayOutputStream err = new ByteArrayOutputStream();
        execChannel.setOut(out);
        execChannel.setErr(err);
        execChannel.open().await(1, TimeUnit.SECONDS);
        Collection<ClientChannelEvent> waitMask = execChannel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 10000);
        waitMask.forEach(event -> System.out.println(event.name()));
        System.out.println(execChannel.getExitStatus());
        byte[] errBytes = err.toByteArray();
        byte[] outBytes = out.toByteArray();
        System.out.println(new String(outBytes, StandardCharsets.UTF_8));
        System.out.println(new String(errBytes, StandardCharsets.UTF_8));
       /* Scanner scanner = new Scanner(System.in);
        scanner.nextInt();*/
        sshServer.stopServer();
        System.out.println("Exiting");
        System.exit(0);
    }
}

here is the output for “whoami”:

2020-07-24 19:22:44,267 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started on Port: 45018
2020-07-24 19:22:44,278 INFO c.w.v.g.s.SSHClient [main] Creating SSHClient for username:  for localhost:45018
2020-07-24 19:22:44,369 INFO c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-24 19:22:44,713 INFO c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-24 19:22:45,835 INFO c.w.v.g.s.SSHServer [sshd-SshServer[41d477ed](port=45018)-nio2-thread-3] authenticating user: 
true

CLOSED
EOF
EXIT_STATUS
OPENED
0
properOutputhere


2020-07-24 19:22:46,969 DEBUG c.w.v.g.s.SSHServer [main] SSHServer stopped...
Exiting

Process finished with exit code 0

here is the output when I try to execute “dir” using:

ClientChannel execChannel = clientSession.createChannel(ClientChannel.CHANNEL_EXEC, "dir");

output:

2020-07-24 19:25:20,128 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started on Port: 45018
2020-07-24 19:25:20,140 INFO c.w.v.g.s.SSHClient [main] Creating SSHClient for username:  for localhost:45018
2020-07-24 19:25:20,237 INFO c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-24 19:25:20,566 INFO c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-24 19:25:21,453 INFO c.w.v.g.s.SSHServer [sshd-SshServer[33d512c1](port=45018)-nio2-thread-3] authenticating user: 
true
TIMEOUT
OPENED
null


2020-07-24 19:25:31,539 DEBUG c.w.v.g.s.SSHServer [main] SSHServer stopped...
Exiting

Process finished with exit code 0

Answer

    package com.example.demo;
    
    import java.io.ByteArrayOutputStream;
    import java.io.OutputStream;
    import java.security.KeyPair;
    import java.util.EnumSet;
    import java.util.concurrent.TimeUnit;
    
    import org.apache.sshd.client.SshClient;
    import org.apache.sshd.client.channel.ClientChannel;
    import org.apache.sshd.client.channel.ClientChannelEvent;
    import org.apache.sshd.client.session.ClientSession;
    import org.apache.sshd.common.channel.Channel;
    
    // https://stackoverflow.com/questions/63075107/how-to-execute-remote-commands-using-//apache-mina-sshd
    public class SshClientDemo {
        public String getFileList(String host, String username, String password, int port, long defaultTimeout) throws Exception {
            
            // uses the default id_rsa and id_rsa.pub files to connect to ssh server
            SshClient client = SshClient.setUpDefaultClient();      
            client.start();
            try (ClientSession session = client.connect(username, host, port).verify(defaultTimeout, TimeUnit.SECONDS).getSession()) {
                //session.addPasswordIdentity(password);
                session.auth().verify(defaultTimeout, TimeUnit.SECONDS);
                try (ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
                        ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
                        ClientChannel channel = session.createChannel(Channel.CHANNEL_EXEC, "dir")) // to execute remote commands                   
                {
                    channel.setOut(responseStream);
                    channel.setErr(errorStream);
                    try {
                        channel.open().verify(defaultTimeout, TimeUnit.SECONDS);
                        try (OutputStream pipedIn = channel.getInvertedIn()) {
                            pipedIn.write("dir".getBytes());
                            pipedIn.flush();
                        }
                        channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED),       
                        TimeUnit.SECONDS.toMillis(defaultTimeout));
                        String error = new String(errorStream.toByteArray());
                        if (!error.isEmpty()) {
                            throw new Exception(error);
                        }
                        return responseStream.toString();                   
                    } 
                    finally {
                        channel.close(false);
                    }
                }
            }
            finally {
                client.stop();
            }
        }
    }
    
    
    
    // use this where you need to maybe main method
    
    SshClientDemo demo = new SshClientDemo();
            try {
                String data = demo.getFileList("<your host name>", "<your user name>", null, 22, 10);
                System.out.println(" listing.....");
                System.out.println(data);
            } 
            catch (Exception e) {
                e.printStackTrace();
            }

# output

listing.....
 Volume in drive C is win-ent
 Volume Serial Number is 2C26-6048

 Directory of c:usersatlantis

06/04/2021  04:03 PM    <DIR>          .
06/04/2021  04:03 PM    <DIR>          ..
06/18/2020  07:34 PM    <DIR>          .android
06/20/2020  10:24 PM                57 .angular-config.json
06/01/2020  11:26 AM    <DIR>          .ApacheDirectoryStudio
02/16/2020  12:11 AM    <DIR>          .aws
04/20/2021  03:01 PM            30,199 .bash_history
08/14/2020  08:06 PM               995 .bash_history2
04/22/2020  02:16 PM            20,438 .boto
04/01/2021  04:21 PM    <DIR>          .cache
07/23/2020  07:26 PM    <DIR>          .cassandra
08/14/2020  12:07 AM    <DIR>          .codemix
08/14/2020  12:13 AM    <DIR>          .codemix-store
08/13/2020  05:54 PM               104 .codemix.properties
09/01/2020  07:03 PM    <DIR>          .codewind
06/16/2020  12:06 PM    <DIR>          .config
07/26/2020  07:22 PM                15 .dbshell
03/13/2021  07:18 PM    <DIR>          .docker
11/23/2020  12:28 PM    <DIR>          .eclipse
04/17/2020  07:56 PM                60 .gitconfig
04/17/2021  03:06 PM    <DIR>          .gnupg
04/11/2021  10:46 PM    <DIR>          .gradle
03/31/2020  11:33 PM    <DIR>          .groovy
03/26/2021  09:51 PM    <DIR>          .hawtjni
06/19/2020  02:11 PM    <DIR>          .IntelliJIdea2019.2
04/26/2021  04:18 PM    <DIR>          .ipython
04/07/2021  07:24 PM    <DIR>          .jenkins
12/07/2020  09:26 PM    <DIR>          .jmc
04/26/2021  04:17 PM    <DIR>          .jupyter
03/13/2021  07:51 PM    <DIR>          .kube
09/15/2020  12:20 PM    <DIR>          .lemminx
04/14/2020  06:14 PM    <DIR>          .m2
04/23/2020  11:01 AM                37 .minttyrc
07/21/2020  12:18 PM                 0 .mongorc.js
06/18/2020  08:58 PM    <DIR>          .nbi
06/18/2020  01:29 PM                 4 .node_repl_history
06/07/2021  07:34 PM    <DIR>          .p2
05/07/2021  02:19 PM    <DIR>          .remain
06/04/2021  04:03 PM    <DIR>          .scalaide
08/10/2020  04:52 PM                11 .scala_history
06/14/2021  01:26 AM    <DIR>          .ssh
08/02/2020  06:06 PM    <DIR>          .sts4
08/22/2020  07:21 PM    <DIR>          .swt
04/16/2021  06:46 PM    <DIR>          .tmp
02/14/2020  10:58 PM    <DIR>          .tooling
04/16/2021  02:20 PM    <DIR>          .VirtualBox
04/12/2020  10:25 PM    <DIR>          .vscode
06/26/2020  11:00 AM                32 .vuerc
03/13/2021  03:30 PM    <DIR>          .webclipse
06/20/2020  11:17 AM    <DIR>          .WebStorm2019.3
06/07/2021  04:22 PM                 0 .xdm-global-lock
06/06/2020  11:46 AM    <DIR>          .xdman
03/11/2021  10:02 PM    <DIR>          3D Objects
04/11/2021  10:14 PM    <DIR>          caches
03/11/2021  10:02 PM    <DIR>          Contacts
04/11/2021  10:14 PM    <DIR>          daemon
05/12/2021  08:41 PM    <DIR>          Desktop
06/13/2021  10:35 PM    <DIR>          Documents
06/12/2021  04:18 PM    <DIR>          Downloads
03/11/2021  10:02 PM    <DIR>          Favorites
04/01/2021  11:58 PM    <DIR>          go
08/02/2020  05:20 PM    <DIR>          hsperfdata_atlantis
08/06/2020  08:30 PM    <DIR>          IBM
02/14/2020  05:14 PM    <DIR>          Intel
07/16/2020  07:23 PM            52,192 java_error_in_idea_6696.log
06/24/2020  11:01 AM            68,569 java_error_in_webstorm_17796.log
04/11/2021  10:17 PM    <DIR>          jdks
03/11/2021  10:02 PM    <DIR>          Links
07/23/2020  01:35 PM             1,180 mongo.sql
03/11/2021  10:02 PM    <DIR>          Music
04/11/2021  10:13 PM    <DIR>          native
09/04/2020  05:57 PM    <DIR>          OneDrive
06/30/2020  12:05 PM    <DIR>          opera autoupdate
06/08/2021  04:32 PM    <DIR>          Pictures
02/14/2020  05:27 PM    <DIR>          Roaming
03/11/2021  10:02 PM    <DIR>          Saved Games
07/13/2020  11:28 AM    <DIR>          sdk
03/11/2021  10:02 PM    <DIR>          Searches
03/11/2021  10:02 PM    <DIR>          Videos
06/15/2020  07:20 PM               144 webstorm.txt
              17 File(s)        174,037 bytes
              63 Dir(s)  36,056,952,832 bytes free


Source: stackoverflow