GH-3211: Add DefSftpSF.setKnownHosts(Resource) (#3212)

* GH-3211: Add DefSftpSF.setKnownHosts(Resource)

Fixes https://github.com/spring-projects/spring-integration/issues/3211

* Add `DefaultSftpSessionFactory.setKnownHosts(Resource)` to
allow to configure externally any resource for file with known_hosts content
* Deprecate an existing method in favor of new one
* The new method makes it aligned with the `setPrivateKey(Resource)`
* Fix tests do not use a deprecated method any more

**Cherry-pick to 5.2.x**

* * Rename to `setKnownHostsResource()` to avoid XML parser confusion
* Change `sftp.adoc` to reflect a new property
This commit is contained in:
Artem Bilan
2020-03-10 16:50:00 -04:00
committed by GitHub
parent 36f96ec2c6
commit 6b82681cc0
12 changed files with 51 additions and 47 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.integration.sftp.session;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
@@ -27,6 +28,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.file.remote.session.SharedSessionCapable;
@@ -81,7 +83,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
private String password;
private String knownHosts;
private Resource knownHosts;
private Resource privateKey;
@@ -191,8 +193,21 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
* false (default).</b>
* @param knownHosts The known hosts.
* @see JSch#setKnownHosts(String)
* @deprecated since 5.2.5 in favor of {@link #setKnownHostsResource(Resource)}
*/
@Deprecated
public void setKnownHosts(String knownHosts) {
setKnownHostsResource(new FileSystemResource(knownHosts));
}
/**
* Specifies the filename that will be used for a host key repository.
* The file has the same format as OpenSSH's known_hosts file.
* @param knownHosts the resource for known hosts.
* @see JSch#setKnownHosts(InputStream)
* @since 5.2.5
*/
public void setKnownHostsResource(Resource knownHosts) {
this.knownHosts = knownHosts;
}
@@ -323,7 +338,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
* implementation must respond to Jsch calls in a suitable way.
* <p>
* Jsch calls {@link UserInfo#promptYesNo(String)} when connecting to an unknown host,
* or when a known host's key has changed (see {@link #setKnownHosts(String)
* or when a known host's key has changed (see {@link #setKnownHostsResource(Resource)}
* knownHosts}). Generally, it should return false as returning true will accept all
* new keys or key changes.
* <p>
@@ -347,7 +362,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
/**
* When no {@link UserInfo} has been provided, set to true to unconditionally allow
* connecting to an unknown host or when a host's key has changed (see
* {@link #setKnownHosts(String) knownHosts}). Default false (since 4.2).
* {@link #setKnownHostsResource(Resource) knownHosts}). Default false (since 4.2).
* Set to true if a knownHosts file is not provided.
* @param allowUnknownKeys true to allow connecting to unknown hosts.
* @since 4.1.7
@@ -380,8 +395,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
freshJschSession = true;
}
sftpSession = new SftpSession(jschSession);
JavaUtils.INSTANCE
.acceptIfNotNull(this.channelConnectTimeout, sftpSession::setChannelConnectTimeout);
JavaUtils.INSTANCE.acceptIfNotNull(this.channelConnectTimeout, sftpSession::setChannelConnectTimeout);
sftpSession.connect();
if (this.isSharedSession && freshJschSession) {
this.sharedJschSession = jschSession;
@@ -408,8 +422,8 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
if (this.port <= 0) {
this.port = 22;
}
if (StringUtils.hasText(this.knownHosts)) {
this.jsch.setKnownHosts(this.knownHosts);
if (this.knownHosts != null) {
this.jsch.setKnownHosts(this.knownHosts.getInputStream());
}
// private key
@@ -467,6 +481,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
* sensible defaults if null. As the password is configured in this Factory, the
* wrapper will return the factory's configured password and only delegate to the
* UserInfo if null.
*
* @since 4.1.7
*/
private class UserInfoWrapper implements UserInfo, UIKeyboardInteractive {
@@ -548,7 +563,7 @@ public class DefaultSftpSessionFactory implements SessionFactory<LsEntry>, Share
}
else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No UserInfo provided - " + message + ", returning:"
LOGGER.debug("No UserInfo provided - " + message + ", returning: "
+ DefaultSftpSessionFactory.this.allowUnknownKeys);
}
return DefaultSftpSessionFactory.this.allowUnknownKeys;

View File

@@ -16,7 +16,7 @@
<beans:bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<beans:property name="host" value="loclahost"/>
<beans:property name="knownHosts" value="local, foo.com, bar.foo"/>
<beans:property name="knownHostsResource" value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<beans:property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftp_rsa"/>
<beans:property name="privateKeyPassphrase" value="ghj"/>
<beans:property name="password" value="hello"/>

View File

@@ -3,25 +3,17 @@
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tool https://www.springframework.org/schema/tool/spring-tool.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/integration/sftp https://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<channel id="requestChannel"/>
<beans:bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<beans:property name="host" value="loclahost"/>
<beans:property name="knownHosts" value="local, foo.com, bar.foo"/>
<beans:property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<beans:property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<beans:property name="privateKeyPassphrase" value="ghj"/>
<beans:property name="password" value="hello"/>
@@ -30,17 +22,17 @@
</beans:bean>
<sftp:inbound-channel-adapter id="sftpAdapterNoAutoCreate"
channel="requestChannel"
session-factory="sftpSessionFactory"
filter="filter"
remote-directory="/foo"
local-directory="file:foo"
auto-create-local-directory="false"
delete-remote-files="false">
channel="requestChannel"
session-factory="sftpSessionFactory"
filter="filter"
remote-directory="/foo"
local-directory="file:foo"
auto-create-local-directory="false"
delete-remote-files="false">
<poller fixed-rate="1000"/>
</sftp:inbound-channel-adapter>
<beans:bean id="filter" class="org.springframework.integration.sftp.filters.SftpPatternMatchingFileListFilter">
<beans:bean id="filter" class="org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter">
<beans:constructor-arg value="."/>
</beans:bean>

View File

@@ -21,7 +21,7 @@
<beans:bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.SimpleSftpSessionFactory">
<beans:property name="host" value="loclahost"/>
<beans:property name="knownHosts" value="local, foo.com, bar.foo"/>
<beans:property name="knownHostsResource" value="local, foo.com, bar.foo"/>
<beans:property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<beans:property name="privateKeyPassphrase" value="ghj"/>
<beans:property name="password" value="hello"/>

View File

@@ -22,7 +22,8 @@
<beans:bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<beans:property name="host" value="loclahost"/>
<beans:property name="knownHosts" value="local, foo.com, bar.foo"/>
<beans:property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<beans:property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftp_rsa"/>
<beans:property name="privateKeyPassphrase" value="ghj"/>
<beans:property name="password" value="hello"/>

View File

@@ -3,25 +3,17 @@
xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tool https://www.springframework.org/schema/tool/spring-tool.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/integration/sftp https://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">
<channel id="inboundFilesChannel"/>
<beans:bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<beans:property name="host" value="loclahost"/>
<beans:property name="knownHosts" value="local, foo.com, bar.foo"/>
<beans:property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<beans:property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<beans:property name="privateKeyPassphrase" value="ghj"/>
<beans:property name="password" value="hello"/>

View File

@@ -9,7 +9,8 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<property name="privateKeyPassphrase" value="ghj"/>
<property name="password" value="hello"/>

View File

@@ -9,7 +9,7 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.SimpleSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="knownHostsResource" value="local, foo.com, bar.foo"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<property name="privateKeyPassphrase" value="ghj"/>
<property name="password" value="hello"/>

View File

@@ -9,7 +9,8 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<property name="privateKeyPassphrase" value="ghj"/>
<property name="password" value="hello"/>

View File

@@ -9,7 +9,8 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="localhost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftpTest"/>
<property name="privateKeyPassphrase" value="ghj"/>
<property name="password" value="hello"/>

View File

@@ -9,7 +9,8 @@
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="loclahost"/>
<property name="knownHosts" value="local, foo.com, bar.foo"/>
<property name="knownHostsResource"
value="#{ new org.springframework.core.io.ByteArrayResource('local, foo.com, bar.foo'.bytes)}"/>
<property name="privateKey" value="classpath:org/springframework/integration/sftp/config/sftp_rsa"/>
<property name="privateKeyPassphrase" value="ghj"/>
<property name="password" value="hello"/>

View File

@@ -111,7 +111,7 @@ Required.
`hostKeyAlias`::Sets the host key alias, which is used when comparing the host key to the known hosts list.
`knownHosts`::Specifies the filename that used for a host key repository.
`knownHostsResource`::Specifies the file resource that used for a host key repository.
The file has the same format as OpenSSH's `known_hosts` file and is required and must be pre-populated if `allowUnknownKeys` is false.
`password`::The password to authenticate against the remote host.
@@ -163,7 +163,7 @@ If `false`, a pre-populated `knownHosts` file is required.
In particular, `promptYesNo()` is invoked when an unknown (or changed) host key is received.
See also <<sftp-unk-keys,`allowUnknownKeys`>>.
When you provide a `UserInfo`, the `password` and private key `passphrase` are obtained from it, and you cannot set discrete
`password` and `privateKeyPassprase` properties.
`password` and `privateKeyPassphrase` properties.
[[sftp-proxy-factory-bean]]
=== Proxy Factory Bean