Bonjour à tous,
Nous essayons de faire fonctionner Discourse avec un point de terminaison SSO externe, mais nous n’arrivons pas à faire correspondre la signature.
Les journaux montrent :
[2020-12-23 21:10:50 +0000] [7] [DEBUG] 2d9c3e07e2e7551e51af471ca3b50e83d06411b2c75e443f96def5b6a257d141
[2020-12-23 21:10:50 +0000] [7] [DEBUG] ad02fdc5bd85adce7722bc264352cca9b931392735ed72474966c4461f188b8c
[2020-12-23 21:10:50 +0000] [7] [DEBUG] compare_digest est différent
Où est l’erreur ? La préparation du HMAC semble-t-elle correcte ?
endpoint:
@app.route(/discourse)
def discourse():
try:
cookie = request.cookies['__session']
except KeyError:
logging.error("Le cookie de session était absent")
return redirect(login_url)
try:
decoded_token = verify_session_cookie(cookie, check_revoked=True)
except ValueError:
return {"message": "Le cookie de session était présent mais n'est pas une chaîne valide ou est vide"}, 400
except ExpiredSessionCookieError:
return {"message": "Le cookie de session était présent mais a expiré."}, 400
try:
uid = decoded_token['uid']
except KeyError:
return {"message": "L'identifiant utilisateur n'a pas pu être lu dans le jeton décodé"}, 500
try:
payload = request.args['sso']
except KeyError:
return {"message": "Le paramètre de charge utile était absent"}, 400
try:
sig = request.args['sig']
except KeyError:
return {"message": "Le paramètre sig était absent"}, 400
try:
nonce = validate_sso_and_generate_nonce(payload, sig, sso_secret)
except DiscourseError as e:
current_app.logger.error("Échec de la validation SSO : " + str(e))
return redirect(login_url)
user = get_user(uid)
sso_url = generate_sso_redirect_url(forum_url, nonce, sso_secret, user.email, uid, user.display_name, user.display_name)
current_app.logger.debug("Point de terminaison Discourse terminé")
return redirect(sso_url)
Voici comment nous générons la signature :
def validate_sso_and_generate_nonce(payload, signature, secret):
"""
payload : fourni par l'appel HTTP de Discourse vers votre point de terminaison SSO en tant que paramètre GET sso
signature : fourni par l'appel HTTP de Discourse vers votre point de terminaison SSO en tant que paramètre GET sig
secret : la clé secrète que vous avez entrée dans Discourse sso secret
valeur de retour : Le nonce utilisé par Discourse pour valider l'URL de redirection
"""
if None in [payload, signature]:
raise DiscourseError('Aucune charge utile ou signature SSO.')
if not secret:
raise DiscourseError('Secret invalide..')
if not payload:
raise DiscourseError('Charge utile invalide..')
payload = bytes(parse.unquote(payload), encoding='utf-8')
decoded = base64.decodestring(payload).decode('utf-8')
if len(payload) == 0 or 'nonce' not in decoded:
raise DiscourseError('Charge utile invalide..')
h = hmac.new(base64.b64encode(bytes(secret, encoding='utf-8')), payload, digestmod=hashlib.sha256)
this_signature = h.hexdigest()
current_app.logger.debug(this_signature)
current_app.logger.debug(signature)
#if this_signature != signature:
# raise DiscourseError('La charge utile ne correspond pas à la signature.')
if not hmac.compare_digest(this_signature, signature):
current_app.logger.debug("compare_digest est différent")
nonce = decoded.split('=')[1]
return nonce