你好!我们编写了一个自定义的 SSO 插件,将公司的登录信息打包,以便 Discourse 用于处理登录和创建账户。从 v2.7.0beta4 版本开始,我们遇到了错误,提示我们未提供一个新的参数 secure_session。我在任何地方都找不到关于该参数的格式及其应包含内容的详细信息。关于此次更新,是否有其他文档可供参考?
谢谢!
你好!我们编写了一个自定义的 SSO 插件,将公司的登录信息打包,以便 Discourse 用于处理登录和创建账户。从 v2.7.0beta4 版本开始,我们遇到了错误,提示我们未提供一个新的参数 secure_session。我在任何地方都找不到关于该参数的格式及其应包含内容的详细信息。关于此次更新,是否有其他文档可供参考?
谢谢!
你知道你看到的具体错误信息吗?据我了解,Discourse 现在将 SSO 的 nonce 参数与用户的会话绑定。这意味着,如果某个应用是通过向 /session/sso 发起后台请求来生成 nonce 的,那么该 nonce 将无效。这可能就是你所遇到的问题。
当然!这是我们在 APM 中看到的错误堆栈:
ArgumentError: missing keyword: :secure_session
…r/www/discourse/app/models/discourse_single_sign_on.rb: 28:in `initialize'
/var/www/discourse/lib/single_sign_on.rb: 65:in `new'
/var/www/discourse/lib/single_sign_on.rb: 65:in `parse'
…ourse_account_auth/lib/service_gateway_current_user.rb: 72:in `upsert_sso_record'
…ourse_account_auth/lib/service_gateway_current_user.rb: 53:in `create_sso_record'
…ourse_account_auth/lib/service_gateway_current_user.rb: 28:in `current_user'
/var/www/discourse/lib/current_user.rb: 36:in `current_user'
service_gateway_current_user.rb 是我们插件的一部分,用于根据“Service Gateway”(这是我们公司内部用于判断用户是否已登录的结构)的头部信息构建发送给 DiscourseSingleSignOn 的有效载荷。
以下是该堆栈部分的说明:
current_user 函数使用头部信息查找 SingleSignOnRecord,其中 external_id 与头部中的用户 ID 匹配。如果不匹配,则进入 create_sso_record 部分。create_sso_record 创建一个哈希值 – { external_id: sg_headers[:user_id], email: sg_headers[:email] } – 并将其发送到我们的 upsert_sso_record 函数。upsert_sso_record 接收该哈希值(在下方上下文中称为 payload),并尝试创建 DiscourseSingleSignOn 对象:def upsert_sso_record(payload)
encoded_query = Base64.encode64(payload.to_query)
sig = OpenSSL::HMAC.hexdigest('sha256', ENV['SSO_SECRET'], encoded_query)
sso = DiscourseSingleSignOn.parse({ sso: encoded_query, sig: sig }.to_query)
if SiteSetting.verbose_sso_logging
Rails.logger.warn("Verbose SSO log: Started SSO process\n\n#{sso.diagnostics}")
Rails.logger.warn("SSO Payload:\n\n#{payload}")
end
begin
user = sso.lookup_or_create_user(@request.ip)
rescue ActiveRecord::RecordInvalid => ex
Rails.logger.error "Unable to find/create sso user #{ex}"
end
user
end
该函数第 3 行的 parse 调用似乎是问题所在。一旦它尝试 initialize 对象,它期望的 secure_session 值就不存在。
顶一下!我也对此很好奇!
我想知道将新的 discourse_connect_csrf_protection 站点设置设为 false 是否能解决您的问题。该站点设置是隐藏的,因此需要通过 Rails 控制台进行设置。您可以在该主题的回复中找到相关详情:https://meta.discourse.org/t/discourseconnect-flow-no-longer-functions/182844。
不幸的是,我认为仅靠这个新设置可能无法解决问题——代码内部仍然需要传入一个 secure_session 对象,即使它实际上并未被使用。
通常,我们建议使用官方钩子来开发认证插件,而不是覆盖核心的 DiscourseConnect 实现。
在不查看整个插件的情况下很难确定,但您可以尝试为 secure_session 传入 nil 值。这样做,同时开启新的站点设置,或许能让情况更接近正常运行。
在进一步深入研究 v2.7.0.beta4 的代码后,我发现 ApplicationController 中有一个 secure_session 定义。将我们的插件代码修改为以下内容,似乎在我们的 Staging 环境中可以正常工作:
sso = DiscourseSingleSignOn.parse({ sso: encoded_query, sig: sig }.to_query, secure_session: secure_session)
……真的就这么简单吗?![]()
听起来应该可行——安全会话通常来自 ApplicationController 中的那个方法。![]()
太棒了!谢谢你让我帮你梳理这个问题。
![]()