如何解决Rails通过unixODBC用externalbrowser认证连接Snowflake SSO失败问题?
我搭建了一个Rails 7.0.4应用,使用ruby-odbc、sequel及sequel-snowflake连接器对接Snowflake数据库,采用SSO登录Snowflake,因此在DSN配置中将认证方式设置为externalbrowser。前端由React处理,同时使用rack-cors。该应用在Windows上运行正常,但部署到AlmaLinux 9系统中后出现问题。
我选择使用unixODBC,已配置好DSN,通过isql可正常连接:浏览器窗口打开,重定向到localhost并携带SAML token,提示认证成功,且能在isql shell中正常执行SQL命令。但启动Rails应用时,在重定向到localhost环节失败,提示"This site can't be reached / localhost refused to connect"。
我尝试了多种方法但均无效:
- 更换不同浏览器(Firefox、Chrome、Brave)
- 在
cors.rb中添加URL到origins配置项 - 关闭浏览器中的HSTS
- 在
application.rb中设置config.force_ssl为false - 使用Passenger替代Puma
对比正常工作的isql日志与Rails日志,发现Rails在浏览器认证启动前一切正常,但出现如下错误:
2023-01-31T13:12:17Z.699 [thread-7067] Info Connection #0 to host xxxxx.west-europe.azure.snowflakecomputing.com left intact. 2023-01-31T13:12:17.699 INFO 7067 sf::RestRequest::httpPerform: http request headers: Content-Type: application/json Accept: application/json 2023-01-31T13:12:17.699 TRACE 7067 sf::CurDesc::reset: cleanup 0 2023-01-31T13:12:17.699 TRACE 7067 sf::CurDesc::reset: curl_easy_reset 0x42b2d50 2023-01-31T13:12:17.699 TRACE 7067 sf::CurlDescPool::freeCurlDesc: Free curl descriptor 0x42b1bf0(curl=0x42b2d50) back to subpool 0x428de20 2023-01-31T13:12:17.699 TRACE 7067 sf::RestRequest::~RestRequestState: Freed descriptor to pool 2023-01-31T13:12:17.699 DEBUG 7067 sf::AuthenticatorExternalBrowser::getSSOUrl: SSO URL: https://login.microsoftonline.com/52d....7e/saml2?SAMLRequest=nZJB....%2FkL&RelayState=58393 Initiating login request with your identity provider. A browser window should have opened for you to complete the login. If you can't see it, check existing browser windows, or your OS settings. Press CTRL+C to abort and try again... 2023-01-31T13:12:17.822 ERROR 7067 sf::AuthWebServer::startAccept: Failed to receive SAML token. Could not accept a request. err: Interrupted system call 2023-01-31T13:12:17.822 TRACE 7067 Simba::Snowflake::SFConnection::connect: Simba::Support::ErrorExceptionUnformatted ErrorException: {MessageKey="SFAuthWebBrowserFailed" ComponentID=102' RowNumber=UNKNOWN ColumnNumber=UNKNOWN DiagState=63 MessageParameters=["Permission denied"]} 2023-01-31T13:12:17.823 TRACE 7067 Simba::Snowflake::SFConnection::SetProperty: Setting property (167) with type 2 /home/mwinter/.rvm/gems/ruby-3.1.2/gems/sequel-5.64.0/lib/sequel/adapters/odbc.rb:17:in `drvconnect': ODBC::Error: S1000 (38) [Snowflake][Snowflake] (38) (Sequel::DatabaseConnectionError) Failed to authenticate a user by external browser: Permission denied.
请问是否有办法让Rails像isql一样通过unixODBC连接数据库?
1. 检查端口权限与本地回环规则
日志中的Permission denied和Interrupted system call指向Rails进程无权限监听本地端口,或本地回环通信被阻止:
- 确认Rails运行用户(如部署用的nginx、Passenger用户)有权限绑定大于1024的非特权端口(Snowflake驱动默认使用这类端口)。
- 检查firewalld规则,确保允许本地回环接口通信:
firewall-cmd --add-interface=lo --permanent firewall-cmd --reload - 临时关闭防火墙测试:
systemctl stop firewalld,若能正常认证,再调整规则而非长期关闭。
2. 显式指定回调端口与地址
修改ODBC配置文件(/etc/odbc.ini或用户目录下的.odbc.ini),添加固定回调参数,避免驱动随机选端口时触发权限问题:
[YourSnowflakeDSN] AUTHENTICATOR=externalbrowser BROWSER_REDIRECT_PORT=8080 BROWSER_REDIRECT_HOST=127.0.0.1 # 其他原有配置...
3. 同步进程环境变量
isql能正常运行,说明环境变量配置正确,但Rails进程可能缺失关键配置:
- 确保Rails进程能读取ODBC配置文件,设置环境变量:
ODBCINI=/etc/odbc.ini - 检查
LD_LIBRARY_PATH包含unixODBC和Snowflake驱动的库路径,比如:export LD_LIBRARY_PATH=/usr/lib64:/opt/snowflake/snowflakeodbc/lib64:$LD_LIBRARY_PATH - 若用systemd启动Rails,在服务配置文件中显式添加这些环境变量,避免环境继承不全。
4. 切换无浏览器依赖的认证模式(备选)
如果externalbrowser认证始终无法适配服务器环境,可改用更适合服务器部署的认证方式:
- OAuth认证:预先获取OAuth token,在DSN中配置
AUTHENTICATOR=oauth和TOKEN=your_oauth_token - JWT密钥认证:生成密钥对,配置
AUTHENTICATOR=JWT、PRIVATE_KEY_FILE=/path/to/key.p8等参数,无需浏览器交互
内容的提问来源于stack exchange,提问作者Marc W

