Andrea Cosentino created CAMEL-25886:
----------------------------------------

             Summary: camel-ftp/mina-sftp - resolve listed symbolic links for 
jailStartingDirectory
                 Key: CAMEL-25886
                 URL: https://issues.apache.org/jira/browse/CAMEL-25886
             Project: Camel
          Issue Type: Improvement
          Components: camel-ftp, camel-mina-sftp
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino
             Fix For: 4.24.0, 4.22.3, 4.18.6


The SFTP consumers ({{sftp}} in camel-ftp and {{mina-sftp}}) apply 
{{jailStartingDirectory}} to the path built from each listed name only: 
{{RemoteFileConsumer.isWithinStartingDirectory()}} (camel-ftp-common) compacts 
that path and compares it with the starting directory as text. The 4.23 upgrade 
guide note of CAMEL-25412 states that the remote file consumers keep this 
lexical check. A listed entry that the server reports as a symbolic link is 
therefore handled like any other entry:

* {{SftpRemoteFile}} has no accessor for the link flag of the listing 
attributes, so {{SftpRemoteFileJCraft}} ({{ChannelSftp.LsEntry}}) and 
{{MinaSftpRemoteFile}} ({{SftpClient.DirEntry}}) do not expose it.
* {{AbstractSftpConsumer.doPollDirectory()}} (camel-ftp-common, shared by both 
consumers) treats every entry that is not a directory as a file.
* The retrieval ({{ChannelSftp.get()}} in {{SftpOperations}}, 
{{SftpClient.read()}} in {{MinaSftpOperations}}) is resolved by the server, 
which follows the link to its target wherever that is.

camel-file resolves symbolic links for {{jailStartingDirectory}} since 
CAMEL-25412, and the ftp consumer ignores entries that the server lists as 
links ({{FtpConsumer}}, "Ignoring unsupported remote file type"). This change 
gives the SFTP consumers the same semantics as camel-file.

h3. Behaviour after the change

With {{jailStartingDirectory}} enabled (the default):
* A listed entry that the server reports as a symbolic link is resolved on the 
server before it is accepted. If its target is outside the starting directory, 
the entry is skipped and logged by {{GenericFileConsumer.isValidFile()}} as for 
the existing lexical check (WARN the first time, DEBUG on later polls).
* A link whose target cannot be resolved (a dangling link) is skipped.
* Links that resolve inside the starting directory, and a starting directory 
that is itself a link, work as before, so {{MinaSftpSymlinkIT}} and the 
"Symbolic Links" section of the mina-sftp documentation stay valid.

With {{jailStartingDirectory=false}} the consumers keep following every link, 
as today. No new option is added, so the endpoint metadata does not change.

h3. Proposed change

* {{SftpRemoteFile}} (camel-ftp-common): add {{default boolean 
isSymbolicLink()}} returning {{false}}, so {{SftpRemoteFileSingle}} and other 
implementations stay compatible. {{SftpRemoteFileJCraft}} returns 
{{entry.getAttrs().isLink()}} and {{MinaSftpRemoteFile}} returns 
{{entry.getAttributes().isSymbolicLink()}}.
* A small interface in camel-ftp-common that resolves a link on the server, 
implemented by {{SftpOperations}} ({{ChannelSftp.realpath()}} and 
{{readlink()}}) and {{MinaSftpOperations}} ({{SftpClient.canonicalPath()}} and 
{{readLink()}}), instead of a new method on the public {{RemoteFileOperations}} 
interface, which {{FtpOperations}} implements too. It uses realpath. Where the 
server's realpath does not resolve links (it returns the link's own path, as 
Apache MINA SSHD does), it resolves the target itself with lstat and readlink, 
component by component, relative to the link's directory and up to a fixed 
number of links. The starting directory is resolved the same way, once per poll.
* {{AbstractSftpConsumer}}: check an entry flagged as a link right after the 
existing lexical check, either through a protected overload of the 
{{GenericFileConsumer.isWithinStartingDirectory()}} hook that also receives the 
listed entry (defaulting to the String variant), or in {{AbstractSftpConsumer}} 
itself.
* Only entries that the server reports as links are resolved, and no entry is 
required to be a regular file. CAMEL-1247 removed an earlier check that skipped 
the entries listed as links, because on Windows it skipped regular files too; 
the current {{SftpATTRS.isLink()}} compares the whole file type field.
* camel-4.18.x has no camel-ftp-common: there {{SftpConsumer}} and 
{{MinaSftpConsumer}} each have their own polling loop, so the change goes into 
both, and the CAMEL-1247 comment in {{SftpConsumer}} is replaced.

h3. Documentation

* {{sftp-component.adoc}}: a "Symbolic links and the starting directory" 
section, as in {{file-component.adoc}}.
* {{mina-sftp-component.adoc}}: amend "Symbolic Links": links resolving outside 
the starting directory are skipped unless {{jailStartingDirectory=false}}.
* Regenerate the catalog copies of both pages.
* Upgrade guide notes on main, since links to files outside the starting 
directory are no longer consumed: {{camel-4x-upgrade-guide-4_24.adoc}}, plus 
the "Upgrading from 4.22.2 to 4.22.3" section of the 4_22 guide and the 
"Upgrading from 4.18.5 to 4.18.6" section of the 4_18 guide. While there, add 
the CAMEL-25412 notes that main's 4_22 and 4_18 guides do not have yet.

h3. Tests

* {{RemoteFileConsumerStartingDirectoryJailTest}} (camel-ftp): with stubbed 
listing entries, a link resolving outside the starting directory is skipped and 
a link resolving inside is accepted.
* New {{SftpConsumerJailStartingDirectorySymlinkIT}} (camel-ftp) and 
{{MinaSftpConsumerJailStartingDirectorySymlinkIT}} (camel-mina-sftp): a link 
resolving inside is consumed; a link resolving outside is skipped, and consumed 
when {{jailStartingDirectory=false}}; a dangling link is skipped. The embedded 
SFTP server (Apache MINA SSHD with its default settings) lists a link as a 
link, as OpenSSH does, so the tests run against it unchanged.
* {{MinaSftpSymlinkIT}} stays green.

h3. Notes

* Whether a listing reports an entry as a link depends on the server. OpenSSH 
and Apache MINA SSHD (with its default settings) list a link with its own 
attributes, so the listing is enough there. A server that reports the target's 
attributes in its listings hides the link; recognising such entries too would 
need an LSTAT per listed entry, one more round trip per file and poll. The 
proposal relies on the listing attributes, and the documentation says so.
* The check and the retrieval that follows are not atomic (an SFTP open follows 
links on the server), so the permissions and link settings of the SFTP server 
still matter.
* Backport to camel-4.22.x and camel-4.18.x, as for CAMEL-25412.

----
_Claude Code on behalf of [~acosentino]_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to