2

I don't know what I doing wrong in setting up a ScpClient to send/receive files.

I am using Apache MINA SSHD library to start a SSH server and try to copy files to/from it.

Here is my setup:

SSHServer.java

public class SSHServer {

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

    public SSHServer() {
        sshServer = SshServer.setUpDefaultServer();
        sshServer.setHost("127.0.0.1");
        sshServer.setPort(22);
        sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
        //Accept all keys for authentication
        //sshServer.setPublickeyAuthenticator((s, publicKey, serverSession) -> true);
        sshServer.setFileSystemFactory(new VirtualFileSystemFactory() {
            @Override
            public Path getUserHomeDir(SessionContext session) throws IOException {
                return Paths.get("C:/Users/u660221");
            }
        });
        sshServer.setCommandFactory(new ScpCommandFactory());
        sshServer.setPasswordAuthenticator((username, password, serverSession) -> {
            logger.debug("authenticating: {} password: {}", username, password);
            return username != null && "changeit".equals(password);
        });
    }

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

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

    public void startServer() throws IOException{
        sshServer.start();
        logger.debug("SSHServer started...");
    }

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

SSHClient.java

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) {
        sshClient = SshClient.setUpDefaultClient();
        sshClient.setFileSystemFactory(new VirtualFileSystemFactory() {
            @Override
            public Path getUserHomeDir(SessionContext session) throws IOException {
                return Paths.get("C:/Users/u660221");
            }
        });
        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.debug("SSHClient is connected: {}", connectFuture.isConnected());
        return connectFuture.getSession();
    }

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

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

TestSSH.java

    public class TestSSH {
        private static final Logger logger = LoggerFactory.getLogger(TestSSH.class);
        public static void main(String[] args) throws IOException {
            SSHServer sshServer = new SSHServer();
            sshServer.startServer();
            logger.debug("Started SSHServer on HOST: " + sshServer.getHost() + " PORT: " + sshServer.getPort());
            SSHClient sshClient = new SSHClient("u660221", "changeit",
                                                        sshServer.getHost(), sshServer.getPort());
            sshClient.startClient();
            ClientSession clientSession = sshClient.connect();
            clientSession.addPasswordIdentity("changeit");
            AuthFuture authFuture = clientSession.auth().verify();
            logger.debug("is client auth success: "  + authFuture.isSuccess());
            logger.debug("client connect address: {}", clientSession.getConnectAddress().toString());
            ScpClientCreator creator = ScpClientCreator.instance();
            ScpClient scpClient = creator.createScpClient(clientSession);
//FileOutputStream fo = new FileOutputStream("C:\\Users\\u660221\\destination\\file.jar");
//scpClient.download("u660221@127.0.0.1:\\Project\\file.jar", fo); //this works!!!!!
       //does not work     //scpClient.upload(Paths.get("C:/Users/u660221/source"), "u660221@127.0.0.1:/destination", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes, ScpClient.Option.TargetIsDirectory);
            scpClient.download("u660221@127.0.0.1:/source/", Paths.get("C:/Users/u660221/destination"), ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes); //does not work
        }
    }

Here is the o/p for uncommented download line(this fails since nothing is copied):

2020-07-02 13:57:15,186 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 13:57:15,202 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 13:57:15,357 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 13:57:15,896 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 13:57:17,690 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[25a6944c](port=22)-nio2-thread-1] authenticating: u660221 password: changeit
2020-07-02 13:57:17,695 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 13:57:17,696 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22

Here is the o/p for uncommented upload line:

2020-07-02 14:14:08,034 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 14:14:08,044 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 14:14:08,175 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 14:14:08,598 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 14:14:10,412 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[77888435](port=22)-nio2-thread-3] authenticating: u660221 password: changeit
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22
Exception in thread "main" java.io.EOFException: readAck - EOF before ACK
    at org.apache.sshd.common.scp.ScpHelper.readAck(ScpHelper.java:849)
    at org.apache.sshd.common.scp.ScpHelper.sendPaths(ScpHelper.java:456)
    at org.apache.sshd.client.scp.AbstractScpClient.lambda$upload$1(AbstractScpClient.java:158)
    at org.apache.sshd.client.scp.DefaultScpClient.runUpload(DefaultScpClient.java:145)
    at org.apache.sshd.client.scp.AbstractScpClient.upload(AbstractScpClient.java:158)
    at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:119)
    at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:115)
    at TestSSH.main(TestSSH.java:29)

It seems it is unable to read from the InputStream but I dont know what I am doing wrong, BTW this is a windows machine. do I need to have scp installed in windows for this?

On enabling debug logging, these logs can be seen:

2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Executing command scp -r -d -p -t -- u660221@127.0.0.1:/destination
2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Unknown flag ('-') in command=scp -r -d -p -t -- u660221@127.0.0.1:/destination

but this is being constructed by the ScpClient class only what am I supposed to do?

vkp
  • 91
  • 4
  • 17
  • Did it work for you? For me nothing works like this.I dont get any error but files are not being uploaded. – Dungeon_master Nov 05 '20 at 21:26
  • Yes it does work for me. I will add complete working code for the server and the client if you want. – vkp Nov 07 '20 at 03:05
  • yes can you please add working code. It doesnt show any error but also doesnt tranfer the file. Also the following piece of code doesn't work for me: ``` sshClient.setFileSystemFactory(new VirtualFileSystemFactory() { @Override //shows no possible override public Path getUserHomeDir(SessionContext session) throws IOException { return Paths.get("C:/Users/u660221"); } }); ``` Also it is neccessary to add this line to the server setup: "sshServer.setCommandFactory(new ScpCommandFactory());" – Dungeon_master Nov 09 '20 at 13:55
  • I hope you have modified the file paths according to your system, the code mentioned in the question works for me. you need to use file paths based on your system. to see errors you need to enable debug mode for sshd lib in your logger, there are errors its just that you are not able to see them. – vkp Nov 10 '20 at 04:52
  • thanks, it works after some tweaks :) – Dungeon_master Nov 13 '20 at 13:10

1 Answers1

1

I found the answer.

replace the upload and download lines with the lines below

scpClient.upload(
   Paths.get("C:\\Users\\u660221\\source"),
   "/destination",
   ScpClient.Option.Recursive,
   ScpClient.Option.PreserveAttributes,
   ScpClient.Option.TargetIsDirectory  );
scpClient.download(
   "/source",
   Paths.get("C:\\Users\\u660221\\destination"),
   ScpClient.Option.Recursive,
   ScpClient.Option.PreserveAttributes,
   ScpClient.Option.TargetIsDirectory  );

There was no need to specify the remote again in the method.

This I found using pscp to copy to/from the sshServer and logging the commands that are being executed in the server side in that I found it was unnecessary to include the remote and it was plain wrong.

Aubin
  • 14,617
  • 9
  • 61
  • 84
vkp
  • 91
  • 4
  • 17