DiscourseConnect est une fonctionnalité centrale de Discourse qui vous permet de configurer l’« Authentification Unique (SSO) » pour déléguer entièrement l’inscription et la connexion des utilisateurs de Discourse vers un autre site. Proposé à nos clients hébergés Pro, Business et Entreprise.
(Février 2021) « Discourse SSO » est désormais « DiscourseConnect ». Si vous exécutez une ancienne version de Discourse, les paramètres ci-dessous seront nommés
sso_...au lieu dediscourse_connect_....
Le problème
De nombreux sites souhaitant s’intégrer à un site Discourse préfèrent conserver toutes les inscriptions d’utilisateurs sur un site distinct. Dans une telle configuration, toutes les opérations de connexion doivent être déléguées à ce site différent.
Que faire si je souhaite utiliser le SSO en conjonction avec une authentification existante ?
L’objectif de DiscourseConnect est de remplacer l’authentification de Discourse. Si vous souhaitez ajouter un nouveau fournisseur, consultez les plugins existants tels que : Discourse VK Authentication (vkontakte)
Activer DiscourseConnect
Pour activer DiscourseConnect, vous devez remplir trois paramètres :
enable_discourse_connect : doit être activé, c’est l’interrupteur global.
discourse_connect_url : l’URL externe vers laquelle les utilisateurs seront redirigés lorsqu’ils tenteront de se connecter.
discourse_connect_secret : une chaîne secrète utilisée pour hacher les charges utiles SSO. Cela garantit que les charges utiles sont authentiques.
Une fois enable_discourse_connect défini sur true :
- Cliquer sur la connexion ou sur l’avatar vous redirigera vers
/session/sso, qui redirigera ensuite les utilisateurs versdiscourse_connect_urlavec une charge utile signée. - Les utilisateurs ne pourront pas « modifier le mot de passe ». Ce champ est supprimé du profil utilisateur.
- Les utilisateurs ne pourront plus utiliser l’authentification Discourse (nom d’utilisateur/mot de passe, Google, etc.).
Que faire si vous cochez cette option par erreur ?
Voir : Log back in as admin after locking yourself out with read-only mode or an invalid SSO configuration
Implémenter DiscourseConnect sur votre site
Discourse utilise les adresses e-mail pour mapper les utilisateurs externes aux utilisateurs Discourse et suppose que les e-mails externes sont sécurisés. SI VOUS NE VALIDEZ PAS LES ADRESSES E-MAIL AVANT DE LES ENVOYER À DISCOURSE, VOTRE SITE SERA EXTRÊMEMENT VULNÉRABLE !
Alternativement, si vous insistez pour envoyer des e-mails non validés, ASSUREZ-VOUS de définir require_activation=true. Cela forcera la validation de tous les e-mails par Discourse. NOUS DÉCONSEillons FORTEMENT CETTE PRATIQUE. Si vous choisissez de procéder avec ce paramètre activé, vous assumez un risque considérable.
Discourse redirigera les clients vers discourse_connect_url avec une charge utile signée (par exemple, si discourse_connect_url est https://somesite.com/sso) :
Vous recevrez du trafic entrant avec la structure suivante :
https://somesite.com/sso?sso=PAYLOAD&sig=SIG
La charge utile est une chaîne encodée en Base64 comprenant un nonce et un return_sso_url. La charge utile est toujours une chaîne de requête valide.
Par exemple, si le nonce est ABCD, la charge utile brute sera :
nonce=ABCD&return_sso_url=https%3A%2F%2Fdiscourse_site%2Fsession%2Fsso_login. Cette charge utile brute est encodée en base 64.
Le point de terminaison appelé doit :
- Valider la signature : s’assurer que le HMAC-SHA256 de
PAYLOAD(en utilisantdiscourse_connect_secretcomme clé) est égal àsig(sigsera encodé en hexadécimal). - Effectuer l’authentification requise.
- Créer une nouvelle charge utile encodée en URL contenant au moins nonce, email et external_id. Vous pouvez également fournir des données supplémentaires. Voici la liste de toutes les clés que Discourse comprend :
- nonce doit être copié depuis la charge utile d’entrée.
- email doit être une adresse e-mail vérifiée. Si l’adresse e-mail n’a pas été vérifiée, définissez require_activation sur « true ».
- external_id est une chaîne unique pour l’utilisateur qui ne changera jamais, même si son e-mail, son nom, etc. changent. La valeur suggérée est le numéro de ligne « id » de votre base de données.
- username deviendra le nom d’utilisateur sur Discourse si l’utilisateur est nouveau ou si
SiteSetting.auth_overrides_usernameest défini. - name deviendra le nom complet sur Discourse si l’utilisateur est nouveau ou si
SiteSetting.auth_overrides_nameest défini. - avatar_url sera téléchargé et défini comme avatar de l’utilisateur si l’utilisateur est nouveau ou si
SiteSetting.discourse_connect_overrides_avatarest défini. - avatar_force_update est un champ booléen. S’il est défini sur true, il forcera Discourse à mettre à jour l’avatar de l’utilisateur, que
avatar_urlait changé ou non. - bio deviendra le contenu de la biographie de l’utilisateur si l’utilisateur est nouveau, si sa biographie est vide ou si
SiteSetting.discourse_connect_overrides_bioest défini. - title définira le titre de l’utilisateur.
- website définira le site web de l’utilisateur sur son profil.
- location définira la localisation de l’utilisateur sur son profil.
- profile_background_url sera téléchargé et défini comme arrière-plan du profil de l’utilisateur si l’utilisateur est nouveau ou si
SiteSetting.discourse_connect_overrides_profile_backgroundest défini. - card_background_url sera téléchargé et défini comme arrière-plan de la carte de l’utilisateur si l’utilisateur est nouveau ou si
SiteSetting.discourse_connect_overrides_card_backgroundest défini. - locale définira la localisation de l’utilisateur si l’utilisateur est nouveau et si
SiteSetting.allow_user_localeest activé. - locale_force_update est un champ booléen. S’il est défini sur true avec locale, il forcera la mise à jour de la localisation pour les utilisateurs existants (nécessite
SiteSetting.allow_user_locale). - Les champs booléens supplémentaires (« true » ou « false ») sont : admin, moderator, suppress_welcome_message, logout.
- Encoder la charge utile en Base64.
- Calculer un hachage HMAC-SHA256 de la charge utile en utilisant
discourse_connect_secretcomme clé et la charge utile encodée en Base64 comme texte. - Rediriger vers l’URL
return_sso_urlavec les paramètres de requêtessoetsig(http://discourse_site/session/sso_login?sso=payload&sig=sig).
Discourse validera que le nonce est valide. S’il l’est, il l’expirera immédiatement afin qu’il ne puisse pas être réutilisé. Ensuite, il tentera de :
- Connecter l’utilisateur en recherchant un external_id déjà associé dans le modèle
SingleSignOnRecord. - Connecter l’utilisateur en utilisant l’e-mail fourni (en mettant à jour l’external_id) (sauf si require_activation = true).
- Créer un nouveau compte pour l’utilisateur en fournissant (e-mail, nom d’utilisateur, nom) et en mettant à jour l’external_id.
Problèmes de sécurité
Le nonce (jeton à usage unique) expirera automatiquement après 30 minutes. Cela signifie que dès que l’utilisateur est redirigé vers votre site, il dispose de 30 minutes pour se connecter ou créer un nouveau compte.
Le protocole est sûr contre les attaques par rejeu car le nonce ne peut être utilisé qu’une seule fois. Le nonce est lié à la session du navigateur actuelle pour se protéger contre les attaques CSRF.
Spécifier l’appartenance aux groupes
Si l’option discourse connect overrides groups est spécifiée, Discourse prendra en compte la liste séparée par des virgules des groupes passés dans groups.
Outre groups, vous pouvez également spécifier l’appartenance aux groupes dans votre charge utile SSO en utilisant les attributs add_groups et remove_groups, indépendamment de l’option discourse connect overrides groups.
add_groups est une liste séparée par des virgules de noms de groupes dont nous nous assurerons que l’utilisateur est membre.
remove_groups est une liste séparée par des virgules de noms de groupes dont nous nous assurerons que l’utilisateur n’est pas membre.
Implémentation de référence
Discourse contient une implémentation de référence de la classe SSO :
Une implémentation triviale serait :
class DiscourseSsoController < ApplicationController
def sso
secret = "MY_SECRET_STRING"
sso = DiscourseApi::SingleSignOn.parse(request.query_string, secret)
sso.email = "user@email.com"
sso.name = "Bill Hicks"
sso.username = "bill@hicks.com"
sso.external_id = "123" # identifiant unique pour chaque utilisateur de votre application
sso.sso_secret = secret
redirect_to sso.to_url("http://l.discourse/session/sso_login")
end
end
Transition vers et depuis l’authentification unique.
Tant que le paramètre require_activation n’est pas défini sur true dans la charge utile de la requête, le système fait confiance aux e-mails fournis par le point de terminaison SSO. Cela signifie que si vous aviez un compte existant par le passé sur Discourse avec DiscourseConnect désactivé, DiscourseConnect le réutilisera simplement et évitera de créer un nouveau compte.
Si vous désactivez DiscourseConnect, les utilisateurs pourront réinitialiser leurs mots de passe et retrouver l’accès à leurs comptes.
Exemple concret :
Compte tenu des paramètres suivants :
Domaine Discourse : http://discuss.example.com
URL DiscourseConnect : http://www.example.com/discourse/sso
Secret DiscourseConnect : d836444a9e4084d5b224a60c208dce14
E-mail validé : Non (ajoutez require_activation=true à la charge utile)
Tentative de connexion de l’utilisateur
-
Un nonce est généré :
cb68251eefb5211e58c00ff1395f0c0b -
Une charge utile brute est générée :
nonce=cb68251eefb5211e58c00ff1395f0c0b -
La charge utile est encodée en Base64 :
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI= -
La charge utile est encodée en URL :
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D -
Un HMAC-SHA256 est généré sur la charge utile encodée en Base64 :
1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
Enfin, le navigateur est redirigé vers :
http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D&sig=1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
À l’autre bout
- La charge utile est validée à l’aide de HMAC-SHA256. Si la signature ne correspond pas, le processus s’arrête.
- En inversant les étapes ci-dessus, le nonce est extrait.
L’utilisateur se connecte :
name: sam
external_id: hello123
email: test@test.com
username: samsam
require_activation: true
Une charge utile non signée est générée :
nonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123&require_activation=true
L’ordre n’a pas d’importance, les valeurs sont encodées en URL.
La charge utile est encodée en Base64 :
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ==
La charge utile est encodée en URL :
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D
La charge utile encodée en Base64 est signée :
3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Le navigateur redirige vers :
http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D&sig=3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Synchronisation des enregistrements DiscourseConnect
Vous pouvez utiliser le point de terminaison POST /admin/users/sync_sso pour synchroniser un enregistrement DiscourseConnect. Passez-lui le même enregistrement que vous passeriez au point de terminaison DiscourseConnect ; le nonce n’a pas d’importance.
Si vous appelez admin/users/sync_sso depuis un autre site, vous devrez inclure une api_key admin valide et un api_username valide dans les en-têtes de la requête. Consultez Sync DiscourseConnect user data with the sync_sso route pour plus de détails sur la structure de la requête.
Effacer les enregistrements DiscourseConnect
Si vos valeurs external_id provenant de votre fournisseur DiscourseConnect ont changé (peut-être avez-vous modifié l’algorithme de génération, peut-être s’agit-il d’un point de terminaison différent), vous pouvez supprimer en toute sécurité tous les enregistrements existants en utilisant la console Rails :
SingleSignOnRecord.destroy_all
Déconnexion des utilisateurs
Vous pouvez utiliser le point de terminaison POST /admin/users/{USER_ID}/log_out pour déconnecter n’importe quel utilisateur du système si nécessaire.
Pour configurer le point de terminaison vers lequel Discourse redirige lors de la déconnexion, recherchez le paramètre logout redirect. Si aucune URL n’est définie ici, vous serez redirigé vers l’URL configurée dans discourse connect url.
Rechercher des utilisateurs par external_id
Les données de profil utilisateur peuvent être consultées via le point de terminaison /users/by-external/{EXTERNAL_ID}.json. Cela retournera une charge utile JSON contenant les informations de l’utilisateur, y compris le user_id qui peut être utilisé avec le point de terminaison log_out.
Implémentations existantes
-
Le gem
discourse_apipeut être utilisé pour le SSO. Consultez le code SSO dans son répertoire d’exemples pour voir une implémentation de base. -
Notre plugin WordPress facilite la configuration du SSO entre WordPress et Discourse. Les détails sur sa configuration se trouvent dans l’onglet SSO de la page des options du plugin.
Travaux futurs
- Nous souhaitons rassembler davantage d’implémentations de référence pour le SSO sur d’autres plateformes. Si vous en avez une, veuillez publier dans la catégorie Dev / SSO.
Fonctionnalités avancées
- Vous pouvez transmettre des champs personnalisés pour l’utilisateur en préfixant le nom du champ par
custom. Par exemple,custom.user_field_1peut être utilisé pour définir la valeur deUserCustomFielddont le nom estuser_field_1. - Vous pouvez transmettre
avatar_urlpour remplacer l’avatar de l’utilisateur (SiteSetting.discourse_connect_overrides_avatardoit être activé). Les avatars sont mis en cache, donc passezavatar_force_update=truepour forcer leur mise à jour si l’URL est identique. Pour l’instant, vous ne pouvez pas transmettre une URL vide pour désactiver l’avatar des utilisateurs. - Par défaut, le message de bienvenue est envoyé à tous les nouveaux utilisateurs créés via SSO. Si vous souhaitez le supprimer, vous pouvez passer
suppress_welcome_message=true. - Pour configurer votre instance Discourse en tant que fournisseur DiscourseConnect, consultez : Utiliser DiscourseConnect comme fournisseur d’identité.
Dépannage de votre fournisseur DiscourseConnect
Pour faciliter le débogage de DiscourseConnect, vous pouvez activer le paramètre du site verbose_discourse_connect_logging. En activant ce paramètre, des diagnostics détaillés apparaîtront dans YOURSITE.com/logs. Assurez-vous de cocher la case warnings en bas de YOURSITE.com/logs.
Nous enregistrerons un avertissement dans les journaux avec un vidage complet de la charge utile SSO :
-
Chaque fois que le processus DiscourseConnect est lancé, nous enregistrerons un avertissement dans le journal avec un vidage complet de la charge utile DiscourseConnect.
-
Chaque fois qu’un utilisateur échoue à compléter DiscourseConnect (en raison de l’expiration du nonce ou d’un blocage IP).
Besoin d’automatiser les inscriptions d’utilisateurs ? Consultez Auto-provisioning user accounts when SSO is enabled

