将 Discourse 用作身份提供商(SSO、DiscourseConnect)时发生的登录错误

我正在尝试遵循此帖子:https://meta.discourse.org/t/use-discourse-as-an-identity-provider-sso-discourseconnect/32974/1,并使用 Python 代码。下面的 Python 代码打印了一个 URL,据我所见,该 URL 应该已正确签名,可以访问 Discourse 实例上的 https://forum.embeetle.com/session/sso_provider,但它只显示文本“Login Error”。

https://forum.embeetle.com/logs 的日志中没有错误,所以我不知道如何解决这个问题。这是否意味着签名不正确?还有其他建议吗?

顺便说一句,别担心:一旦这个问题解决,我就会更改 SSO 密钥。

import secrets
import base64
import urllib.parse
import hmac
import hashlib

forum_url = 'https://forum.embeetle.com'
target_url = 'https://embeetle.com/#account'
sso_secret = b'JCLSVcqbAnEPXz2p2xBY'

nonce = secrets.token_urlsafe()
payload = f'nonce={nonce}&return_sso_url={target_url}'
payload_base64 = base64.b64encode(payload.encode('utf-8')).decode()
payload_for_url = urllib.parse.quote(payload_base64)
signature = hmac.new(
    sso_secret, payload_for_url.encode('utf-8'), hashlib.sha256
).hexdigest()

print(f'{forum_url}/session/sso_provider?sso={payload_for_url}&sig={signature}')

此代码生成的链接类似于下面的 curl 命令:

johan@morla:~/sa> curl 'https://forum.embeetle.com/session/sso_provider?sso=bm9uY2U9bExhRUZjRGFVd0NrNTFkMEVOeGc5dUtKZ0kwNHZNYng5VkpFR0RqRUg0OCZyZXR1cm5fc3NvX3VybD1odHRwczovL2VtYmVldGxlLmNvbS8jYWNjb3VudA%3D%3D&sig=70e647a1baad2e09ef6cdc6d87fae70bc27c6823369be20fd1b11ea536180343'
Login Errorjohan@morla:~/sa>

这是网站上设置的屏幕截图:

有什么问题,或者我该如何调试?

更进一步:如果我为 DiscourseConnect 打开详细日志记录,我确实会在日志中看到一个错误:

image

详细 SSO 日志:签名解析错误 载荷 sso 的签名无效:bm9uY2U9YklKeEU1WWw2OFhjSkJydGlwSU15UTRZeVlMeWd6ZzQyUU9mOFo0SWF5QSZyZXR1cm5fc3NvX3VybD1odHRwczovL2VtYmVldGxlLmNvbS8jYWNjb3VudA= 

日志中提到的载荷未进行 URL 编码(注意末尾的 ‘=’),并且缺少 URL 编码数据的第二个 ‘=’(注意原始载荷末尾重复的 %3D)。

明白了:HMAC-SHA256 签名必须从 base64 编码的数据计算得出,而不是从 URL 编码的数据计算得出。因此,正确的代码是:

import secrets
import base64
import urllib.parse
import hmac
import hashlib

forum_url = 'https://forum.embeetle.com'
target_url = 'https://embeetle.com/#account'
sso_secret = b'JCLSVcqbAnEPXz2p2xBY'

nonce = secrets.token_urlsafe()
payload = f'nonce={nonce}&return_sso_url={target_url}'
payload_base64 = base64.b64encode(payload.encode('utf-8')).decode()
payload_for_url = urllib.parse.quote(payload_base64)

signature = hmac.new(
    sso_secret, payload_base64.encode('utf-8'), hashlib.sha256
).hexdigest()

print(f'{forum_url}/session/sso_provider?sso={payload_for_url}&sig={signature}')

现在是其余的工作:处理重定向、检查 nonce 等。待续……

1 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.