Discourse를 신원 제공자(SSO, DiscourseConnect)로 사용하려는 중 로그인 오류 발생

다음 게시글을 따라 하고 있습니다: Use Discourse as an identity provider (SSO, DiscourseConnect) 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

Verbose SSO log: Signature parse error Bad signature for payload sso: bm9uY2U9YklKeEU1WWw2OFhjSkJydGlwSU15UTRZeVlMeWd6ZzQyUU9mOFo0SWF5QSZyZXR1cm5fc3NvX3VybD1odHRwczovL2VtYmVldGxlLmNvbS8jYWNjb3VudA= 

논란의 여지가 있는 점은 로그에 언급된 페이로드가 URL 인코딩되어 있지 않다는 것입니다(끝의 ‘=’ 참고). 또한 URL 인코딩된 데이터의 두 번째 '='가 누락되어 있습니다(원본 페이로드 끝의 반복된 %3D 참고).

알겠습니다: HMAC-SHA256 서명은 URL 인코딩된 데이터가 아니라 base64 인코딩된 데이터로부터 계산되어야 합니다. 따라서 올바른 코드는 다음과 같습니다:

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 확인 등은 계속 진행할 예정입니다 …