1

Our team has an application where a file is fetched and handled once per day from a remote server using Spring Integration SFTP. Right now, I am migrating from Spring Boot 2.7 to Spring Boot 3.

After migrating to Spring Boot 3, I have noticed that the following is logged (on WARN level) every minute:

2023-08-15T15:00:48.427+02:00  WARN 21256 --- []-nio2-thread-3] i.DefaultSftpClient$SftpChannelSubsystem : handleUnknownChannelRequest(SftpChannelSubsystem[id=0, recipient=0]-ClientSessionImpl[<username>@<host>/<ip>:<port>][sftp]) Unknown channel request: keepalive@openssh.com[want-reply=true]
2023-08-15T15:01:48.430+02:00  WARN 21256 --- [-nio2-thread-13] i.DefaultSftpClient$SftpChannelSubsystem : handleUnknownChannelRequest(SftpChannelSubsystem[id=0, recipient=0]-ClientSessionImpl[<username>@<host>/<ip>:<port>][sftp]) Unknown channel request: keepalive@openssh.com[want-reply=true]

I assume that this is the Keepalive request sent from the server to the client. Why can't our application handle that request? The warning message was not shown before migrating to Spring Boot 3.

Even though the client can't handle the keepalive requests from the server, it still fetches files as it should. The problem is that the log file will be full of all these unnecessary warning messages, and we will not be able to see other important logs.

This is our Spring Bean for the SessionFactory

@Bean
public SessionFactory<SftpClient.DirEntry> sftpSessionFactory() {
    final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
    factory.setHost(sftpHost);
    factory.setPort(sftpPort);
    factory.setUser(sftpUser);

    if (sftpPrivateKey != null) {
        factory.setPrivateKey(sftpPrivateKey);
        factory.setPrivateKeyPassphrase(sftpPrivateKeyPassphrase);
    } else {
        factory.setPassword(sftpPassword);
    }

    factory.setAllowUnknownKeys(true);

    return new CachingSessionFactory<>(factory);
}

1 Answers1

0

Looks like you are facing exactly this situation: https://issues.apache.org/jira/browse/SSHD-1237.

According to their recommendation it is possible to inject an externally configured SshClient:

SshClient client = SshClient.setupDefaultClient();
List<RequestHandler<ConnectionService>> oldHandlers = client.getGlobalRequestHandlers();
List<RequestHandler<ConnectionService>> handlers = new ArrayList<>();
if (GenericUtils.isNotEmpty(oldHandlers)) {
   handlers.add(oldHandlers);
}
handlers.add(KeepAliveHandler.INSTANCE);
client.setGlobalRequestHandlers(handlers);

and then use this ctor:

/**
 * Instantiate based on the provided {@link SshClient}, e.g. some extension for HTTP/SOCKS.
 * @param sshClient the {@link SshClient} instance.
 * @param isSharedSession true if the session is to be shared.
 */
public DefaultSftpSessionFactory(SshClient sshClient, boolean isSharedSession) {
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • thanks for your answer! I have tried the suggestion, but it only works for global requests. The keepalive requests that is sent to my application are channel requests. I have tried to find a setter method on SshClient for setting channel requests handlers, similar to setGlobalRequestHandlers, but haven't found any. Do you know if there exists such a method or if it's possible to add the KeepAliveHandler for channel requests in any other way? – Albin Friedner Aug 17 '23 at 12:44
  • Looks like a `DefaultSftpClient` has this method `protected ChannelSubsystem createSftpChannelSubsystem(ClientSession clientSession) {` you can override and add it using that `ChannelSubsystem.addRequestHandler()`. – Artem Bilan Aug 17 '23 at 13:46
  • Sounds like a good way to do it, but I don't know how. I know that I can create a custom class that extends `DefaultSftpClient` and override `createSftpChannelSubsystem()`, but I don't understand how I can make `DefaultSftpSessionFactory` use my custom class instead of the instance created at [Github - DefaultSftpSessionFactory Line 283](https://github.com/spring-projects/spring-integration/blob/main/spring-integration-sftp/src/main/java/org/springframework/integration/sftp/session/DefaultSftpSessionFactory.java#L283). Is there a way to do that? – Albin Friedner Aug 21 '23 at 14:46
  • I see what you mean. Please, raise a GH issue and we will think how to expose that option on a SessionFactory. I think something like protected method as a factory for the client to override should be enough. – Artem Bilan Aug 22 '23 at 18:39
  • Thanks Artem! I have now created a [GH issue](https://github.com/spring-projects/spring-integration/issues/8713) – Albin Friedner Aug 23 '23 at 13:19