无法通过Apache Camel连接本地SFTP:密钥协商及密钥文件问题求助
问题概述
接手的项目使用Apache Camel进行SFTP文件传输,核心路由代码:
from(fromFtpUrl) .to("file:/Users/sa/myfolder?doneFileName=${file:name}.done");
遇到两个本地SFTP连接问题:
1. 密码认证时密钥交换算法协商失败
配置URL:
fromFtpUrl = "sftp://localhost:22/myproject?username=sa&useUserKnownHostsFile=false&StrictHostKeyChecking=no&doneFileName=done&delete=true&streamDownload=true&delay=6000&password=RAW(mypassword)";
异常信息:
org.apache.camel.component.file.GenericFileOperationFailedException: Cannot connect to sftp://anonymous@localhost:22
Caused by: com.jcraft.jsch.JSchAlgoNegoFailException: Algorithm negotiation fail: algorithmName="server_host_key"
手动SSH连接正常,但本地Mac/Ubuntu 20.04 OpenSSH服务器连接失败,外部Ubuntu服务器正常。
2. 公钥认证时私钥文件找不到
配置URL:
fromFtpUrl = "sftp://localhost:22/myproject?username=sa&useUserKnownHostsFile=false&StrictHostKeyChecking=no&doneFileName=done&delete=true&streamDownload=true&delay=6000&privateKeyFile=/Users/sa/.ssh/id_rsa";
异常信息:
org.apache.camel.component.file.GenericFileOperationFailedException: Cannot connect to sftp://sa@localhost:22
Caused by: com.jcraft.jsch.JSchException: java.io.FileNotFoundException: /Users/kryan/Downloads/id_rsa (No such file or directory)
手动公钥认证正常,且用户对密钥文件有读写权限。
解决方案
针对密钥交换算法协商失败问题
该问题源于Camel依赖的JSch库默认支持的主机密钥算法,与本地新版OpenSSH服务器的默认算法不匹配(比如新版OpenSSH默认使用ssh-ed25519,旧版JSch未支持),可通过以下方式解决:
方式1:在SFTP URL中指定兼容的主机密钥算法
在URL参数中添加serverHostKeyAlgorithms,列出服务器支持的算法,示例:
fromFtpUrl = "sftp://localhost:22/myproject?username=sa&useUserKnownHostsFile=false&StrictHostKeyChecking=no&doneFileName=done&delete=true&streamDownload=true&delay=6000&password=RAW(mypassword)&serverHostKeyAlgorithms=ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa";
可通过执行ssh -Q key命令查看本地OpenSSH服务器支持的主机密钥算法,按需调整列表。
方式2:升级JSch库版本
如果使用的是旧版JSch,升级到com.jcraft:jsch:0.1.55及以上版本,新版已添加对ssh-ed25519等现代算法的支持。
针对公钥认证时私钥文件找不到问题
异常显示的路径与配置路径不符,说明配置可能被覆盖或存在环境路径问题,可按以下步骤处理:
1. 排查配置是否被覆盖
检查代码中是否有其他逻辑修改fromFtpUrl变量,导致私钥路径被替换为/Users/kryan/Downloads/id_rsa。
2. 验证路径与进程权限
确保配置的私钥路径为绝对路径,且Camel运行进程的用户对该路径有读取权限(若为容器或服务运行,需确认密钥文件已正确映射,或调整进程用户权限)。
3. 直接传入私钥内容替代文件路径
若文件路径问题无法排查,可将私钥内容通过privateKey参数直接传入(用RAW包裹避免转义),示例:
fromFtpUrl = "sftp://localhost:22/myproject?username=sa&useUserKnownHostsFile=false&StrictHostKeyChecking=no&doneFileName=done&delete=true&streamDownload=true&delay=6000&privateKey=RAW(-----BEGIN RSA PRIVATE KEY-----\n...完整私钥内容...\n-----END RSA PRIVATE KEY-----)";
内容的提问来源于stack exchange,提问作者creas443

