SSO externe incapable d'obtenir une correspondance de signature

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

Avez-vous réussi à faire fonctionner cela ? Sinon, vous devriez pouvoir identifier où les choses tournent mal en examinant ce code :

https://github.com/bennylope/pydiscourse/blob/master/pydiscourse/sso.py#L39

Bien qu’il existe quelques différences dans la préparation de la charge utile pour la fonction HMAC, ce code échoue avec le même problème : les signatures ne correspondent pas.