Créer un lien de connexion DiscourseConnect

:bookmark: Cette documentation explique comment créer des liens sur un site fournisseur DiscourseConnect qui connectent les utilisateurs à Discourse et les redirigent vers une URL Discourse spécifique.

:person_raising_hand: Niveau d’utilisateur requis : Administrateur

Les sites utilisant DiscourseConnect peuvent ajouter des liens sur leur site fournisseur DiscourseConnect qui connecteront les utilisateurs à Discourse et les redirigeront vers une URL Discourse spécifique. Ceci est réalisé en créant des liens qui pointent vers la route /session/sso et qui ont un paramètre return_path défini sur le chemin de la page Discourse sur laquelle vous souhaitez que les utilisateurs arrivent.
La propriété href du lien doit avoir la forme ci-dessous, avec le chemin sur lequel vous souhaitez que les utilisateurs arrivent substitué à <chemin_relatif> :

https://forum.example.com/session/sso?return_path=<chemin_relatif>

Un exemple de balise d’ancre qui connectera un utilisateur et le redirigera vers la page d’accueil d’un site Discourse :

<a href="https://forum.example.com/session/sso?return_path=/">Communauté</a>

Un exemple de balise d’ancre qui connectera un utilisateur et le redirigera vers la page des sujets populaires :

<a href="https://forum.example.com/session/sso?return_path=/top">Sujets populaires</a>

Comment le return_path est stocké sur Discourse

Discourse stocke la valeur du paramètre return_path dans la session du serveur, indexée par le nonce SSO qui est généré lorsqu’un utilisateur visite la route /session/sso. À la fin du processus d’authentification DiscourseConnect, Discourse recherche le return_path en utilisant le nonce et redirige les utilisateurs vers ce chemin.

Rendre le processus transparent pour les utilisateurs authentifiés

Lorsqu’un utilisateur visite la route /session/sso de Discourse, il est redirigé vers l’URL définie par le réglage de site discourse connect url. Le fournisseur DiscourseConnect gérera alors le processus d’authentification de la même manière qu’il le ferait si l’utilisateur avait cliqué sur le bouton Connexion de Discourse.

Pour que le processus d’authentification soit transparent pour les utilisateurs déjà connectés sur le site du fournisseur d’authentification, le code DiscourseConnect du fournisseur d’authentification doit vérifier si l’utilisateur est connecté ou non. Si l’utilisateur n’est pas connecté, il doit suivre le processus de connexion du fournisseur d’authentification. Si l’utilisateur est déjà connecté, il doit ignorer le processus de connexion sur le site du fournisseur d’authentification.

Voici un exemple commenté, utilisant le code du plugin WP Discourse. Il démontre comment les utilisateurs authentifiés peuvent être traités différemment des utilisateurs non authentifiés :

public function sso_parse_request( $wp ) {
    // Vérifier si l'authentification unique (SSO) est activée dans les options du plugin
    if ( empty( $this->options['enable-sso'] ) ) {
        return null;
    }

    // Gérer toute demande de déconnexion avant de procéder au SSO
    $this->handle_logout_request();

    // Vérifier si les paramètres 'sso' et 'sig' existent dans les variables de requête
    if ( array_key_exists( 'sso', $wp->query_vars ) && array_key_exists( 'sig', $wp->query_vars ) ) {
        // Nettoyer la charge utile 'sso' et la signature pour s'assurer qu'elles sont sûres à utiliser
        $payload = sanitize_text_field( $wp->query_vars['sso'] );
        $sig     = sanitize_text_field( $wp->query_vars['sig'] );

        // Si l'utilisateur n'est pas connecté à WordPress, rediriger vers la page de connexion
        // Ceci garantit que les utilisateurs sans session active sont invités à se connecter d'abord à WordPress
        if ( ! is_user_logged_in() ) {
            // Construire une URL pour rediriger après la connexion
            $redirect = add_query_arg( $payload, $sig );
            // Générer l'URL de connexion WordPress avec le paramètre de redirection
            $login    = wp_login_url( esc_url_raw( $redirect ) );

            // Déclencher une action avant la redirection de connexion (facultatif pour la journalisation ou les actions personnalisées)
            do_action( 'wpdc_sso_before_login_redirect', $redirect, $login );

            // Rediriger vers la page de connexion WordPress
            return $this->redirect_to( $login );
        } else {
            // Si l'utilisateur est déjà authentifié dans WordPress, contourner le processus de connexion
            // et procéder à la validation de la charge utile et de la signature SSO.
            $sso_secret = $this->options['sso-secret'];
            $sso        = new SSO( $sso_secret );
            
            // Valider la charge utile et la signature en utilisant le secret SSO
            if ( ! ( $sso->validate( $payload, $sig ) ) ) {
                // Gérer les requêtes SSO invalides
                return $this->handle_error( 'parse_request.invalid_sso' );
            }

            // Obtenir l'utilisateur WordPress actuellement connecté
            $current_user = wp_get_current_user();
            // Préparer les paramètres SSO en utilisant les données de l'utilisateur connecté
            $params       = $this->get_sso_params( $current_user );

            try {
                // Générer un nonce à partir de la charge utile et construire la chaîne de connexion SSO
                $params['nonce'] = $sso->get_nonce( $payload );
                $q               = $sso->build_login_string( $params );
            } catch ( \Exception $e ) {
                // Gérer les exceptions en cas de problème lors de la génération des paramètres SSO
                return $this->handle_error( 'parse_request.invalid_sso_params', array( 'message' => esc_html( $e->getMessage() ) ) );
            }

            // Déclencher une action avant de rediriger l'utilisateur pour la connexion SSO (utile pour la journalisation)
            do_action( 'wpdc_sso_provider_before_sso_redirect', $current_user->ID, $current_user );

            // Journaliser le succès du SSO si la journalisation verbeuse est activée
            if ( ! empty( $this->options['verbose-sso-logs'] ) ) {
                $this->logger->info( 'parse_request.success', array( 'user_id' => $current_user->ID ) );
            }

            // Rediriger l'utilisateur authentifié vers l'URL de connexion DiscourseConnect avec la chaîne de connexion SSO
            return $this->redirect_to( $this->options['url'] . '/session/sso_login?' . $q );
        }
    }

    // Retourner null si aucun paramètre SSO n'est trouvé dans la requête
    return null;
}

Définir le chemin de retour vers des URL non-Discourse

Discourse vous permet de connecter un utilisateur et de le rediriger vers une URL non-Discourse. Notez que pour que cela fonctionne, vous devez ajouter le domaine au réglage de site discourse connect allowed redirect domains. Par défaut, ce réglage est vide - empêchant les redirections vers des URL non-Discourse. Vous pouvez également utiliser * comme caractère générique pour autoriser tous les domaines. Si vous l’activez, assurez-vous d’utiliser l’URL absolue dans le paramètre return_path pour toute URL non-Discourse vers laquelle vous souhaitez diriger les utilisateurs.

21 « J'aime »

J’utilise cette méthode mais à chaque fois je dois me connecter via sso.

Comment pouvons-nous rendre cela transparent, c’est-à-dire que si je me suis déjà connecté à Discourse, il n’y aurait plus besoin d’aller sur la page sso pour se connecter à nouveau ?

1 « J'aime »

Sauf si quelque chose a changé, c’est ainsi que le lien est censé fonctionner. Par exemple, si vous êtes connecté à Discourse et que vous cliquez sur un lien du site fournisseur sso qui pointe vers https://forum.example.com/session/sso?return_path=/t/some-slug/23, vous devriez être redirigé de manière transparente vers /t/some-slug/23 sans avoir à visiter la page de connexion au préalable.

1 « J'aime »

Je suis déjà sur la dernière mise à jour de Discourse et voici comment le SSO fonctionne pour moi :

Comme vous pouvez le voir, je suis déjà connecté, mais lorsque j’entre une URL comme https://forum.example.com/session/sso?return_path=/t/some-slug/23, je serais à nouveau redirigé vers la page de connexion SSO.

Je pense que ce qui se passe, c’est que lorsque vous visitez une route comme https://forum.example.com/session/sso?return_path=/t/some-slug/23, Discourse vous redirige vers l’url de connexion discourse, que vous soyez connecté ou non à Discourse. Cela se produit ici :

Le site fournisseur d’SSO est alors censé gérer le cas des utilisateurs qui sont déjà connectés au site. Voici comment le plugin WP Discourse le gère :

Ce code (ce qui suit l’instruction else) gère le cas des utilisateurs qui sont déjà connectés à WordPress. Ils sont redirigés vers l’URL fournie par le paramètre de requête return_path. Ainsi, du point de vue de l’utilisateur, il est dirigé directement vers l’URL du chemin de retour, mais ce qui se passe en réalité, c’est qu’il est redirigé vers le site du fournisseur d’SSO, puis de retour vers Discourse.

Je pense que le problème sur votre site est que votre code d’SSO ne gère pas le cas des utilisateurs qui sont déjà connectés au site.

Je n’ai pas la possibilité de tester cela pour le moment. Il est possible que je lise mal le code. Avant de regarder le code, je pensais qu’une vérification était effectuée du côté de Discourse pour voir si l’utilisateur était déjà connecté à Discourse, mais il semble que ce ne soit pas ainsi que cela fonctionne.

3 « J'aime »

Merci beaucoup pour votre explication.

Oui, c’est une chose que nous allons corriger dans notre sso.

Cependant

Je pense qu’avoir cela vérifié du côté de Discourse aurait créé une meilleure expérience utilisateur.

1 « J'aime »

J’ai modifié le message initial pour ajouter des détails sur le fonctionnement du processus et sur la manière de gérer le cas des utilisateurs déjà authentifiés sur le site du fournisseur SSO. C’est une question qui est revenue plusieurs fois.

Une version moins détaillée de ce sujet pourrait éventuellement être intégrée dans Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #482. Le paramètre de requête return_path n’est pas mentionné dans ce sujet.