Apache Mina SFTP Server Side channel Listener for

2020-07-30 03:46发布

问题:

I am trying to figure out how to implement Server side listeners for a Java based SFTP server to alert me to an incoming file transfer. I'm using the latest version of Apache Mina. My scenario is for my server to simply receive a file from a client and do "something" to the file before storing it. That something could be error checking / rules validation / forwarding the contents elsewhere. The thing is I want to do that before it is saved on my system. I'm having difficulty with the documentation and can't find a working example that shows a listener implemented with access to the incoming file stream. I have a very simple server taken from a guide:

 public void setupServer() throws IOException {

    sshd = SshServer.setUpDefaultServer();
    sshd.setFileSystemFactory(new NativeFileSystemFactory() {
        @Override
        public FileSystemView createFileSystemView(final Session session) {
            return new NativeFileSystemView(session.getUsername(), false) {
                @Override
                public String getVirtualUserDir() {
                    return testFolder.getRoot().getAbsolutePath();
                }
            };
        };
    });
    sshd.setPort(8001);
    sshd.setSubsystemFactories(Arrays
            .<NamedFactory<Command>> asList(new SftpSubsystem.Factory()));
    sshd.setCommandFactory(new ScpCommandFactory());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(testFolder
            .newFile("hostkey.ser").getAbsolutePath()));
    sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
        public boolean authenticate(final String username, final String password,
                final ServerSession session) {

            return StringUtils.equals(username, USERNAME)
                    && StringUtils.equals(password, PASSWORD);
        }
    });

    // SessionListener event = new SessionListener();

    sshd.start();
}

That server is capable of receiving a file and storing it on the virtual file system. I can read the file / verify the contents but only after the file is received and stored. Basic authentication is fine for now, the authentication mechanisms are really well documented thankfully!

So my question is:

  • Is there a means to check dynamically when a connection is being made / when the contents are being transferred and to intercept that as it is happening i.e. before the file is actually committed to a directory.

or

  • Will I need to setup a listener to simply watch a directory for new files as they appear and process it accordingly?

Thanks in advance! Leigh.

回答1:

You seem to have an idea that the SFTP is similar protocol to an HTTP. I.e. the client opens a connection with "write" request (like HTTP PUT), sends a file contents of request body, disconnects and that's it.

That's not how the SFTP works.

The SFTP is like a remote file system. The client connects to the SSH/SFTP server and keeps the connection open. During the session, the client sends an "open" file request (with either read or write or both privileges) and gets a handle to the opened file. Then it sends a sequence of read/write-block requests using the file handle. And finally it closes the handle. During a single session, the client can (and typically does) read/write or both any number of files it likes. It can even have several files opened in parallel, accessing them in a completely random order. It is very similar to a way an application works with a local file system.

Implications:

  • You cannot reject connection when you do not like a file, because the connection request itself is not associated with a specific file. All you can is reject the file "open" (or "create") request.

    One way to intercept a file open/create request:

    • Derive NativeFileSystemView.
    • Derive NativeSshFile.
    • Override NativeFileSystemView.createNativeSshFile to create your NativeSshFile
    • Override NativeFileSystemView.isWritable()
  • You cannot redirect an SFTP connection. SSH/SFTP does not support connection "redirect" (unlike HTTP)

  • There's not a single moment where you have a complete file in a memory at once, so that you can inspect it somehow. Instead the client sends the file in chunks. You can of course reimplement the MINA SFTP "input stream" in a way that it keeps the file contents in a memory and inspect a complete contents once you get a "close" request; saving the file to a disk only once you are happy with the file. Beware of DOS attacks though.