Sftp fileupload not working with Apache MINA SSHD and JIMFS in Docker Container

1.8k Views Asked by At

I'm dealing with a tough one:

For testing purposes I use Apache Mina SSHD and JIMFS to mock a remote sftp server - only locally and in test environment. Never in production.

In my Spring Boot application I start a Apache Mina sshd during application startup. I create a virtual filesystem with jimfs (tried unix and osX) for the FileSystemFactory. My business code calls a remote sftp server in production and in test environment it calls the mina sshd server on localhost instead. It does nothing else than uploading a file to the sftp server.

This works very well on my machine locally but i get a "file or directory not found" error message when I run this in our test environment (a docker container).

com.jcraft.jsch.SftpException: No such file or directory
    at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)
    at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:594)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:475)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:365)
    at our.service.core.client.sftp.SftpClient.upload(SftpClient.java:89)

Creation of JIMFS file system during Application startup:

public class MockSftpServerInitializer implements ApplicationListener<ApplicationReadyEvent> {

  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    
    SshServer sshd = SshServer.setUpDefaultServer();

    sshd.setHost("localhost");
    sshd.setPort(1234);
    sshd.setCommandFactory(new ScpCommandFactory());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("host-key.ser")));
    sshd.setPublickeyAuthenticator(getPublickeyAuthenticator());
    sshd.setFileSystemFactory(getInMemoryFileSystemFactory());
    List<NamedFactory<Command>> sftpCommandFactory = new ArrayList<>();
    sftpCommandFactory.add(new SftpSubsystemFactory());
    sshd.setSubsystemFactories(sftpCommandFactory);
    
    try {
      sshd.start();
    } catch (Exception e) {
      throw new RuntimeException("Unable to start sshd", e);
    }
  }
  
  private FileSystemFactory getInMemoryFileSystemFactory() {
    return session -> getInMemoryFileSystem();
  }

  private FileSystem getInMemoryFileSystem() {
    return Jimfs.newFileSystem(
        Configuration.osX()
            .toBuilder()
            .setWorkingDirectory("/")
            .setMaxSize(1024*1024*4)
            .setDefaultAttributeValue("posix:permissions", "rwxrw-rw-")
            .setAttributeViews("basic", "owner", "posix", "unix", "acl", "user")
            .build());
  }
  

}

File upload:

public class SftpClient {

  public boolean upload(String source, String destination) {

    Session session = null;
    ChannelSftp sftpChannel = null;

    try {
      sftpProvider.addIdentity("Identity", privateKey.getBytes(), publicKey.getBytes(), null);
      session = sftpProvider.getSession(username, host, port);
      session.setConfig("StrictHostKeyChecking", "no");

      session.connect();

      Channel channel = session.openChannel("sftp");
      channel.connect();

      sftpChannel = (ChannelSftp) channel;
      sftpChannel.put(source, destination);

      log.info("Successful upload of file {} to SFTP server {}.", source, host);

      return true;
    } catch (SftpException | JSchException ex) {
      log.error("Failed upload of file {} to SFTP server {}.", source, host);
      log.error("{}", ex);
      return false;
    } finally {
      if (sftpChannel != null) {
        sftpChannel.disconnect();
      }
      if (session != null) {
        session.disconnect();
      }
    }
  }
}

I'm grateful for any hint on why this works locally but not in our docker container.

0

There are 0 best solutions below