Accueil > OpenID Connect OAuth Serveur dédié > Développer > OpenID Connect > OpenID Connect Session Management

OpenID Connect Session Management Draft 28 de 2020

Nota : il s’agit d’une version périmée mais des serveurs sont fondés dessus (Publik par exemple).
Cette proposition de spécification répond au besoin de connaître l’état réel de connexion de l’utilisateur et de gérer la déconnexion unique.
Dans l’état actuel, ce document présente de multiples défauts. DnC suit l’évolution de cette spécification et OAuthSD devra intégrer les spécifications qui seront finalement approuvées.

Sans attendre, le serveur OAuthSD répond aux fonctionnalités évoquées avec la technique de la connexion unique et de la déconnexion unique qui en découle ainsi que le monitoring.

Traduction du document OpenID Connect Session Management 1.0 - draft 28

...

Cette spécification définit le terme suivant :

Session

Période continue pendant laquelle un utilisateur final accède à un RP (Relying Party) en s’appuyant sur l’authentification de l’utilisateur final effectuée par le fournisseur OpenID.

2. Découverte du point de terminaison

Pour prendre en charge la gestion de session OpenID Connect, le RP doit obtenir les URL de point de terminaison associées à la gestion de session. Ces URL sont normalement obtenues via la réponse à la découverte de l’OP, comme décrit dans OpenID Connect Discovery 1.0 [OpenID.Discovery], ou PEUVENT être apprises via d’autres mécanismes.

2.1. Métadonnées de découverte du fournisseur OpenID

Ces paramètres de métadonnées de fournisseur OpenID DOIVENT être inclus dans les réponses de découverte du serveur lorsque la gestion de session et la découverte sont prises en charge :

check_session_iframe

CHAMPS OBLIGATOIRES. URL d’un iframe de l’OP qui prend en charge les communications entre origines croisées pour les informations d’état de session avec le client RP, à l’aide de l’API postMessage de HTML5. La page est chargée à partir d’un iframe invisible incorporé dans une page du RP afin de pouvoir s’exécuter dans le contexte de sécurité de l’OP. Il accepte les requêtes postMessage en provenance de l’iframe du RP concerné et utilise postMessage pour renvoyer le statut de connexion de l’utilisateur final vers l’OP.

end_session_endpoint

CHAMPS OBLIGATOIRES. URL de l’OP sur laquelle un RP peut effectuer une redirection pour demander à l’utilisateur final d’être déconnecté de l’OP.

3. Création et mise à jour de sessions

Dans OpenID Connect, la session du RP commence généralement lorsque le RP valide le jeton d’identification de l’utilisateur final. Reportez-vous à la spécification OpenID Connect Core 1.0 [OpenID.Core] pour savoir comment obtenir un jeton ID et le valider. Lorsque l’OP prend en charge la gestion de session, il DOIT également renvoyer l’état de session en tant que paramètre supplémentaire session_state dans la réponse d’authentification. La réponse d’authentification OpenID Connect est spécifiée dans la Section 3.1.2.5 d’OpenID Connect Core 1.0.

Ce paramètre est :

session_state
Etat de session. Chaîne JSON [RFC7159] représentant l’état de connexion de l’utilisateur final sur l’OP. Il NE DOIT PAS contenir le caractère espace (""). Cette valeur est opaque pour le RP. Ceci est OBLIGATOIRE si la gestion de session est prise en charge.

La valeur de l’état de session est initialement calculée sur le serveur. La même valeur d’état de session est également recalculée par l’iframe dans le navigateur du client. La génération de valeurs appropriées pour l’état de session est spécifiée dans la section 4.2 et est basée sur un hachage cryptographique salé de l’ID client, de l’URL d’origine et de l’état du navigateur OP. Pour l’URL d’origine, le serveur peut utiliser l’URL d’origine de la réponse d’authentification, conformément à l’algorithme spécifié à la section 4 de la RFC 6454 [RFC6454].

4. Notification de changement d’état de session

Un jeton d’identité vient généralement avec une date d’expiration. Le RP PEUT s’y fier pour expirer la session du RP. Cependant, il est tout à fait possible que l’utilisateur final se soit déconnecté de l’OP avant la date d’expiration. Par conséquent, il est hautement souhaitable de pouvoir connaître le statut de connexion de l’utilisateur final à l’OP.

Pour ce faire, il est possible de répéter la demande d’authentification avec prompt = none [1]. Cependant, cela entraîne un trafic réseau, ce qui est problématique sur les appareils mobiles qui deviennent de plus en plus populaires. Par conséquent, une fois que la session est établie avec la demande d’authentification et la réponse, il est souhaitable de pouvoir vérifier l’état de la connexion sur l’opérateur sans générer de trafic sur le réseau en interrogeant un OP iframe caché à partir d’un RP iframe avec un postMessage à origine restreinte, comme suit.

4.1. RP iframe

Le RP charge un iframe invisible à partir de lui-même. Cette iframe DOIT connaître l’ID de l’OP iframe, comme décrit à la section 4.2, afin de pouvoir envoyer un message à l’OP iframe. L’iframe RP interroge l’OP iframe avec postMessage à un intervalle approprié [2] pour l’application RP. Avec chaque postMessage, il envoie l’état de session défini dans la section 4.2.

Le postMessage de l’iframe RP fournit la concaténation suivante en tant que données :

ID client + " " + état de session

Il doit également pouvoir recevoir le postMessage de l’OP iframe. Les données reçues seront soit ’changed’, soit ’unchanged’, sauf si la syntaxe du message envoyé est déterminée par le terminal opérateur comme étant malformée, auquel cas les données reçues seront erronées. Dès réception de la modification, le RP DOIT effectuer une nouvelle authentification avec prompt = none pour obtenir l’état de la session en cours sur le terminal opérateur. À la réception d’une erreur, le RP NE DOIT PAS effectuer de nouvelle authentification avec prompt = none, afin de ne pas causer de boucles infinies potentielles générant un trafic réseau vers le terminal opérateur.

Voici un exemple de pseudo-code non normatif pour l’iframe RP :

Javascript

  1. var stat = "unchanged";
  2.   var mes = client_id + " " + session_state;
  3.  
  4.   function check_session()
  5.   {
  6.     var targetOrigin = "https://server.example.com";
  7.     var win = window.parent.document.getElementById("op").
  8.                 contentWindow;
  9.     win.postMessage( mes, targetOrigin);
  10.   }
  11.  
  12.   function setTimer()
  13.   {
  14.     check_session();
  15.     timerID = setInterval("check_session()",3*1000);
  16.   }
  17.  
  18.   window.addEventListener("message", receiveMessage, false);
  19.  
  20.   function receiveMessage(e)
  21.   {
  22.     var targetOrigin = "https://server.example.com";
  23.     if (e.origin !== targetOrigin ) {return;}
  24.     stat = e.data;
  25.  
  26.     if stat == "changed" then take the actions below...
  27.   }

Télécharger

4.2. OP iframe

Le RP charge également un OP iframe invisible à partir de check_session_iframe de l’OP. Le RP DOIT assigner un attribut id à l’iframe afin qu’il puisse l’adresser, comme décrit ci-dessus. L’OP iframe DOIT imposer que l’appelant ait la même origine que son cadre parent. Il DOIT rejeter les demandes postMessage de toute autre source.

Comme spécifié dans la section 4.1, le postMessage de l’iframe RP fournit la concaténation suivante en tant que données :

ID client + " " + session_state

L’op iframe a accès à l’état du navigateur dans l’OP (dans un cookie ou dans un stockage HTML5) qu’il utilise pour calculer et comparer l’état de session OP passé par le RP. L’OP iframe DOIT le recalculer à partir de l’ID client précédemment obtenu, de l’URL d’origine de la source (à partir de postMessage) et de l’état actuel du navigateur OP. L’état de session inclut toutes ces informations pour des raisons de confidentialité, de sorte que différents clients actifs dans le même navigateur ont des valeurs d’état de session distinctes.

Si le postMessage reçu est syntaxiquement incorrect, de sorte que l’ID client publié et l’URL d’origine ne peuvent pas être déterminés ou sont incorrects sur le plan syntaxique, l’OP iframe DOIT poster (postMessage) à la source la chaîne d’erreur. Si la valeur reçue et la valeur calculée ne correspondent pas, l’OP iframe DOIT poster à la source la chaîne modifiée. S’il y a correspondance, alors il DOIT poster la chaîne inchangée.

Voici un exemple non normatif de pseudo-code pour l’OP iframe :

Javascript

  1. window.addEventListener("message", receiveMessage, false);
  2.  
  3.   function receiveMessage(e){ // e.data has client_id and session_state
  4.  
  5.     // Validate message origin
  6.     var client_id = e.data.split(' ')[0];
  7.     var session_state = e.data.split(' ')[1];
  8.     var salt = session_state.split('.')[1];
  9.  
  10.     // if message syntactically invalid
  11.     //     postMessage('error', e.origin) and return
  12.  
  13.     // get_op_browser_state() is an OP defined function
  14.     // that returns the browser's login status at the OP.
  15.     // How it is done is entirely up to the OP.
  16.     var opbs = get_op_browser_state();
  17.  
  18.     // Here, the session_state is calculated in this particular way,
  19.     // but it is entirely up to the OP how to do it under the
  20.     // requirements defined in this specification.
  21.     var ss = CryptoJS.SHA256(client_id + ' ' + e.origin + ' ' +
  22.       opbs + ' ' + salt) + "." + salt;
  23.  
  24.     var stat = '';
  25.     if (session_state == ss) {
  26.       stat = 'unchanged';
  27.     } else {
  28.       stat = 'changed';
  29.     }
  30.  
  31.     e.source.postMessage(stat, e.origin);
  32.   };

Télécharger

L’état du navigateur OP sera généralement stocké dans un cookie ou dans un stockage local HTML5. Il a pour origine le serveur d’autorisations. Il capture des événements significatifs tels que les connexions, les déconnexions, le changement d’utilisateur, le changement de statut d’authentification pour les clients utilisés par l’utilisateur final, etc. Ainsi, l’OP DEVRAIT mettre à jour la valeur de l’état du navigateur en réponse à de tels événements significatifs. En conséquence, le prochain appel à check_session () après un tel événement renverra la valeur modifiée. Il est RECOMMANDÉ que le terminal opérateur ne mette pas à jour l’état du navigateur trop fréquemment en l’absence d’événements significatifs, afin d’éviter un trafic réseau excessif sur le client en réponse à des événements erronés.

Le calcul de l’état de session renvoyé en réponse à des demandes d’authentification infructueuses DEVRAIT, en plus de l’état du navigateur, incorporer suffisamment d’aléa sous la forme d’un sel afin d’empêcher l’identification d’un utilisateur final lors d’appels successifs au point de terminaison d’autorisation de l’OP.

Dans le cas d’un client autorisé (réponse d’authentification réussie), l’OP DEVRAIT changer la valeur de l’état de session renvoyé au client à l’occurrence de l’un des événements suivants :

- L’ensemble des utilisateurs authentifiés auprès du navigateur change (connexion, déconnexion, ajout de session).

- Le statut d’authentification des clients utilisés par l’utilisateur final change.

De plus, l’état du navigateur utilisé pour vérifier l’état de la session DEVRAIT changer avec de tels événements. Les appels à check_session() renverront les modifications apportées par rapport aux versions antérieures de l’état de session après de tels événements. Il est RECOMMANDÉ que l’état du navigateur NE DEVRAIT PAS varier trop souvent en l’absence de tels événements afin de minimiser le trafic sur le réseau causé par la réponse du client aux notifications modifiées.

Dans le cas d’une demande d’authentification infructueuse, la valeur de l’état de session renvoyée DEVRAIT varier avec chaque demande. Cependant, l’état de la session du navigateur n’a pas besoin de changer sauf si un événement significatif se produit. En particulier, de nombreuses valeurs d’état de session peuvent être simultanément valides, par exemple en introduisant un sel aléatoire dans les états de session émis en réponse à des demandes d’authentification infructueuses.

Si un cookie est utilisé pour conserver l’état du navigateur OP, l’indicateur HttpOnly ne peut probablement pas être défini pour ce cookie car il doit être accessible à partir de JavaScript. Par conséquent, les informations pouvant être utilisées pour identifier l’utilisateur ne doivent pas être placées dans le cookie, car elles pourraient être lues par du JavaScript non associé.

Dans certaines implémentations, les notifications modifiées ne se produiront que lorsque la session de l’utilisateur final sera modifiée, alors que dans d’autres implémentations, elles pourront également survenir à la suite de modifications apportées à d’autres sessions entre l’agent d’utilisateur et le terminal opérateur. Les PR doivent être préparés à toute éventualité, en gérant en silence tous les faux positifs susceptibles de se produire.

5. Déconnexion initiée par le RP

Un RP peut notifier à l’OP que l’utilisateur final s’est déconnecté du site et peut également vouloir se déconnecter de l’OP. Dans ce cas, le RP, après avoir déconnecté l’utilisateur final du RP, redirige l’agent utilisateur de l’utilisateur final vers l’URL du point de terminaison de déconnexion de l’OP. Cette URL est normalement obtenue via l’élément end_session_endpoint de la réponse à la découverte de l’OP ou peut être apprise via d’autres mécanismes.

Cette spécification définit également les paramètres suivants qui sont transmis en tant que paramètres de requête dans la demande de déconnexion :

id_token_hint

CONSEILLÉ [3]. Le jeton d’ID précédemment émis a été transmis au point de terminaison de la déconnexion en tant qu’indication de la session authentifiée actuelle de l’utilisateur final avec le client. Ceci est utilisé comme indication de l’identité de l’utilisateur final que le RP demande à être déconnecté par l’OP. L’OP n’a pas besoin d’être répertorié en tant que public du jeton ID lorsqu’il est utilisé en tant que valeur id_token_hint.

post_logout_redirect_uri

OPTIONNEL. URL à laquelle le RP demande que l’agent utilisateur de l’utilisateur final soit redirigé après la déconnexion. La valeur DOIT avoir déjà été enregistrée auprès de l’OP, soit à l’aide du paramètre d’enregistrement post_logout_redirect_uris, soit via un autre mécanisme. S’il est fourni, l’OP DEVRAIT honorer cette demande après la déconnexion.

state

OPTIONNEL. Valeur opaque utilisée par le RP pour maintenir l’état entre la demande de déconnexion et le rappel au noeud final spécifié par le paramètre de requête post_logout_redirect_uri. S’il est inclus dans la demande de déconnexion, l’OP retransmet cette valeur au RP en utilisant le paramètre de requête d’état lors de la redirection de l’agent d’utilisateur vers le RP.

Au point de terminaison de la déconnexion, l’OP DEVRAIT demander à l’utilisateur final s’il souhaite également se déconnecter de l’OP. Si l’utilisateur final dit "oui", alors l’OP DOIT déconnecter l’utilisateur final.

5.1. Redirection vers RP après la déconnexion

Dans certains cas, le RP demande à ce que l’agent d’utilisateur de l’utilisateur final soit redirigé vers le RP après la déconnexion. La redirection post-déconnexion n’est effectuée que lorsque la déconnexion est lancée par le RP, auquel cas la cible de la redirection est la valeur du paramètre de requête post_logout_redirect_uri utilisée par le RP initiateur ; sinon ce n’est pas fait. Cette spécification définit ce paramètre d’enregistrement dynamique à cette fin, conformément à la section 2.1 d’OpenID Connect Dynamic Client Registration 1.0 [OpenID.Registration].

5.1.1. Métadonnées d’inscription du client

Ce paramètre de métadonnées client PEUT être inclus dans les informations d’enregistrement du client lorsque la gestion de session et l’enregistrement dynamique sont pris en charge :

post_logout_redirect_uris

OPTIONNEL. Tableau d’URL fournies par le RP auquel il PEUT demander que l’agent d’utilisateur de l’utilisateur final soit redirigé à l’aide du paramètre post_logout_redirect_uri après la déconnexion [4].

6. Validation

Si l’une des procédures de validation définies dans la présente spécification échoue, les opérations nécessitant des informations qui n’ont pas été correctement validées DOIVENT être annulées et les informations qui n’ont pas été validées NE DOIVENT PAS être utilisées.

7. Considérations de mise en œuvre

Cette spécification définit les fonctionnalités utilisées par les parties utilisatrices et les fournisseurs OpenID ayant choisi d’implémenter la gestion de session. Toutes ces parties utilisatrices et fournisseurs OpenID DOIVENT implémenter les fonctions listées dans cette spécification comme étant "REQUIRED" ou décrites avec un "MUST". Aucune autre considération d’implémentation pour les implémentations de Session Management n’est définie par cette spécification.

8. Considérations de sécurité

L’OP iframe DOIT imposer que l’appelant ait la même origine que son cadre parent. Il DOIT rejeter les demandes postMessage provenant de toute autre source, afin d’empêcher les attaques de script entre sites.

Le paramètre id_token_hint associé à une demande de déconnexion peut être utilisé pour déterminer quel RP a lancé la demande de déconnexion. Les demandes de déconnexion sans valeur id_token_hint valide constituent un moyen de déni de service potentiel ; par conséquent, les opérateurs peuvent vouloir demander une confirmation explicite de l’utilisateur avant d’agir.

...

Critique raisonnée de la méthode et solution pour OAuthSD

Rappelons tout d’abord que la méthode des iframes n’est pas celle que préconise OAuthSD, voyez : Monitoring de l’état de l’authentification et SLO et Implémentation du monitoring avec Javascript : exemples pour SPIP et WordPress. OAuthSD met en œuvre la méthode présentée précédemment à des fins d’expérimentation et de suivi de la norme OpenID Connect.

Cependant, ce document présente des erreurs de principe conduisant à des complications inutiles, résultant en une méthode de monitoring inefficace. En particulier, de très nombreux événements hors sujet nécessitent d’interroger l’OP sur la réalité de la connexion, ce qui entraîne un trafic important.

De toutes façons, les erreurs, omissions et imprécisions de ce document conduisent à un non fonctionnement du système tel que décrit.

1. Se concentrer sur notre sujet : un utilisateur et une application donnée

"L’état du navigateur ... capture des événements significatifs tels que les connexions, les déconnexions, le changement d’utilisateur, le changement de statut d’authentification pour les clients utilisés par l’utilisateur final, etc. Ainsi, l’OP DEVRAIT mettre à jour la valeur de l’état du navigateur en réponse à de tels événements significatifs."

Dans cette phrase, l’expression "les connexions, les déconnexions, le changement d’utilisateur, le changement de statut d’authentification pour les clients utilisés par l’utilisateur final, etc." est un galimatias redondant, encore embrouillé par "des événements tels que" (il y aurait encore d’autres événements à prendre en compte ?) et par le "etc." final. Le texte qui suit "Dans le cas d’un client autorisé (réponse d’authentification réussie), l’OP DEVRAIT changer la valeur de l’état de session renvoyé au client à l’occurrence de l’un des événements suivants : - L’ensemble des utilisateurs authentifiés auprès du navigateur change (connexion, déconnexion, ajout de session). - Le statut d’authentification des clients utilisés par l’utilisateur final change." n’est qu’une redite du précédent. Passons sur le fait que l’authentification n’est pas relative au client mais à l’utilisateur final : on n’est pas à une approximation près.

"De plus, l’état du navigateur utilisé pour vérifier l’état de la session DEVRAIT changer avec de tels événements."

"Il est RECOMMANDÉ que l’état du navigateur NE DEVRAIT PAS varier trop souvent en l’absence de tels événements afin de minimiser le trafic sur le réseau causé par la réponse du client aux modifications notifiées". C’est une absurdité : s’il n’y a pas d’événement, il n’y a pas de notification de changement.

Il apparaît que les changements d’états relatifs à toutes les applications et tous les utilisateurs donnent lieu à notification d’un changement d’état.

La seule chose qui nous intéresse est de savoir si l’utilisateur de l’application ouverte sur le navigateur considéré est connecté ou non.

2. Obtenir directement l’état de connexion, et non l’indication d’un changement

"Les appels à check_session() renverront les modifications apportées par rapport aux versions antérieures de l’état de session après de tels événements.

Dès réception de la modification, le RP DOIT effectuer une nouvelle authentification avec prompt = none pour obtenir l’état de la session en cours sur le terminal opérateur..

L’idée est de notifier un changement d’état, et de réinterroger le serveur pour savoir si l’utilisateur est toujours vu connecté.

Solution OAuthSD : L’état de connexion est relatif à une application et à un utilisateur. Il est traduit par la validité du jeton d’accès.

Notes

[1Cette solution a notre préférence, voir la note suivante.

[2Il est donc inexact d’affirmer, comme indiqué au paragraphe précédent, que la connaissance de l’état de session peut être effectué "sans générer de trafic sur le réseau". Pour réduire le trafic, il conviendra d’augmenter l’intervalle d’interrogation de l’OP. Chez DnC, nous préférons tester la connexion avec prompt = none, le serveur OAuthSD étant optimisé pour répondre très rapidement à une requête de type XMLHttpRequest.

[3Obligatoire pour OAuthSD

[4Nous considérons cette fonctionnalité comme très dangereuse, car elle permet à un malware de rediriger l’utilisateur final sur une page étrangère à l’application initiale, favorisant ainsi le physing.