帮我排查 Discourse SSO 问题

您好,希望能得到一些指导。我的 SSO 本周停止工作了,我本以为昨天已经修复了所有问题(当时确实可以工作,我发誓 :slight_smile: 注意:我查看了昨天和今天的“新用户”记录,这两天都有新用户注册(在我修复之后),但现在又出问题了……)。不幸的是,我今天所做的更新并未生效。

问题:用户无法创建新账户,已登出的用户也无法重新登录。

我注意到我的 Discourse 服务器在以下路由上出现了 400 错误:

403GETdiscourse-url/users/by-external/USER-ID.json?
注意:我最近在 API 文档中发现该路由似乎不存在?(尽管它之前可以工作),看起来正确的路由应该是:https://discourse.example.com/u/by-external/{external_id}.json

404POSTdiscourse-url/admin/users/sync_sso?

末尾的 ? 是因为我在生成 URL 的函数中有一个可选参数字段,而对于这两个路由,所有数据都是通过表单体或请求头发送的。

我使用的是 以下库

我所做的更新(以及我以为能解决问题的操作):

此前,我在所有请求中都是通过查询参数发送 Api-KeyApi-Username 的。过去几个月,我在管理面板中注意到一条警告,提示我使用了过时的请求头。该警告链接到了这篇帖子,关键信息如下:

:warning: 弃用警告!
自 2020 年 4 月 6 日起,我们已不再支持所有非基于 HTTP 请求头的身份验证方式(部分 RSS、邮件接收和 ICS 路由除外)。 这意味着,如果 API 请求中的 api_keyapi_username 出现在查询参数或 HTTP 请求体中,这些请求将很快失效。请参阅下方的 cURL 请求示例,了解如何将 API 请求更新为使用 HTTP 请求头进行身份验证。

我已更新所有请求,现在所有请求中的 Api-KeyApi-Username 都放在请求头中,并且内容类型设置为 multipart form data。

如果有任何人能提供一些指导,告诉我该从哪些方面入手来调试此问题,我将不胜感激。我几乎可以肯定,昨天工作结束前一切正常,我当时能够登录和登出账户,也能创建新账户。

如果需要更多信息,请随时告知。谢谢!

header 字段需要使用连字符(-),而不是下划线(_)。请尝试将字段名更改为 Api-KeyApi-Username

我不确定这是否能解决用户无法登录您网站的问题,但这将解决您遇到的 400 错误问题。

@simon,谢谢你的回复!不幸的是,我之前的帖子没有写清楚,我在请求中已经使用的是 - 而不是 _

要开始调试此问题,请访问您的 Discourse 站点设置页面,搜索“sso”以获取所有 SSO 设置。请确保 enable ssosso urlsso secret 设置正确。然后启用 verbose sso logging 站点设置。启用该设置后,您的站点错误日志(位于“管理 / 日志 / 错误日志”)中将添加一些额外的日志条目。

尝试通过 SSO 登录。然后查看您的错误日志,看看它们是否提供了有关问题的详细信息。如果您没有看到任何有用的信息,请打开浏览器的网络检查器,切换到“网络”选项卡,并勾选“保留日志”复选框。查看正在发出的请求。

如果在尝试修复问题时将自己锁在站点之外,作为管理员用户,您可以通过访问 /u/admin-login 并在表单中输入您的电子邮件地址来绕过 SSO。系统将向您发送一封包含登录链接的电子邮件。

@simon,谢谢你的提示!我一直在查看日志,但我对解读日志还不够熟悉。我遇到了两种不同的警告和一个错误:

这是我频繁收到的警告:

Verbose SSO log: Started SSO process add_groups: admin: moderator: avatar_force_update: avatar_url: bio: card_background_url: email: external_id: groups: locale: locale_force_update: logo

这是错误信息:

Job exception: The difference between the request time and the current time is too large.

当我尝试在我网站上登出 Discourse 的测试用户重新登录时,在我的网络面板中看到了以下内容:

503 服务不可用: GET- https://my-site/auth/discourse_sso?sso=XXXX&sig=xxxx

不幸的是,我卡住了,不知道接下来该怎么办。

我认为该错误消息来自 Amazon S3。此主题中可能包含有关如何解决该问题的有用详细信息:https://meta.discourse.org/t/backups-have-started-failing-due-to-server-time-being-wrong/108802。这里还有更多信息:https://stackoverflow.com/questions/4770635/s3-error-the-difference-between-the-request-time-and-the-current-time-is-too-la。

@simon 感谢您的帮助!我的服务器时间不同步,我已经更新了时间设置,现在备份又可以正常工作了!

现在我偶尔会遇到一个新的错误:

在日志部分,我会随机看到以下警告(目前只出现了两次):

MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-City.mmdb) 未找到:No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-City.mmdb

以及

MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-ASN.mmdb) 未找到:No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-ASN.mmdb

我正在查找如何解决这个问题。我尝试重新构建我的应用,但还不确定重新构建是否成功。除了之前遇到的 400 错误和 503 错误外,我现在仍然随机收到 MaxMindDB 未找到的错误。

我一大早就一直在处理这个问题,但进展不大。我认为 MaxMindDB 错误已经排除了(之前这些错误是零星且不稳定的,过去 3 小时我一直无法复现),并且我已经成功多次重新构建了我的应用。

SSO 管道在此处中断:

  • 用户访问 Discourse
  • 由于没有活跃会话,用户被重定向到 discourse/session/sso_login
  • 用户被重定向到 my-site/discourse_sso?sso=XXXX&sig=XXXX
  • 当触发我之前站点的路由时,我向 /users/by-external/userId.json 发送 GET 请求
    • 该请求返回 403 Forbidden
  • 紧接着向 /admin/users/sync_sso 发送 POST 请求
    • 该请求返回 404 "No route matches [POST] /admin/users/sync_sso
  • 最终,我的站点返回 503 Forbidden 错误(我需要清理一下我站点端的错误信息)

我觉得问题出在 Rails 应用端(如果我理解有误请纠正我)。我之所以这么认为,是因为上周五下班时一切正常,有证据表明周五晚上到周六之间有一些新用户注册(而登录或创建新用户正是当时出问题的地方)。正如我在之前的帖子中提到的,我以为当时已经修复了所有问题,但当我周六开始工作时,发现它又坏了。

我不确定你为什么要向 /users/by-external/<external_id>.json/admin/users/sync_sso 发送请求。正常的流程应该是直接将用户重定向到 /session/sso_login,并将 SSO 负载作为 URL 的查询参数设置。关于 sync_sso 路由的用途,详情可参考:https://meta.discourse.org/t/sync-sso-user-data-with-the-sync-sso-route/84398。

/users/by-external/<external_id> 发送请求时,如果 external_id 尚未与任何 Discourse 用户关联,应返回 404(未找到)错误。如果该 external_id 已关联到某个 Discourse 用户,则应返回该用户信息。

@simon,请求 /users/by-external/USER-ID.json 是为了检查用户是否已在我的 Discourse 中拥有账户。如果找到具有该 ID 的用户,则通过向 /admin/groups/groupId/members.json 发送 PUT 请求,将其添加或移除出与我站点相关的 Discourse 群组,然后重定向到 my-discourse/session/sso_login

如果用户没有账户,则通过向 /admin/users/sync_sso 发送 POST 请求来创建账户。在用户创建完成(并添加到其对应的 Discourse 群组)后,将其重定向到 my-discourse/session/sso_login

我会跟进并重新阅读你列出的文档(谢谢!)。该流程自 2015 年初以来一直运行顺畅,没有任何问题(Discourse 及其 SSO 选项对我们来说是非常有价值的工具!),奇怪的是它突然在上周停止工作了。

@simon 非常感谢你的所有帮助!我已经解决了问题。我们之前使用的 Api-Username 上周某个时候因“不活动”而被“停用”。我最初推测这可能就是问题所在。我在周五重新激活了该用户,很可能正是这一操作在周五解决了所有问题(我原本以为是把 Api-UsernameApi-Key 移入请求头导致的)。

Discourse 在周六早上再次停用了同一个用户,这就解释了为什么一切正常后又突然停止工作。我没想到该用户会因不活动而在如此短的时间内再次被停用。

现在我将 Api-Username 更改为“system”,以防止未来再次出现此类问题。再次感谢你的帮助!在调试过程中,我的备份日志功能也恢复了,我也确实学到了很多东西!