i-TegoDocumentationAuthentification > OpenID Connect OAuth Serveur dédié > Développer > OpenID Connect > OpenID Connect : SSO, management de session etc.

Gestion de la session OIDC : Fonctionnalités

  publié le par i-Tego WM

SSO, SLI, SLO, SRA : ces fonctionnalités offertes par OAuthSD simplifient la gestion des sessions et des connexions pour les utilisateurs, en garantissant une expérience fluide et sécurisée lors de l’utilisation d’applications multiples compatibles avec OpenID Connect.

Avant de détailler comment OAuthSD met en œuvre ces fonctionnalités, assurons-nous de bien les distinguer :

SSO (Single Sign-On) : Il s’agit d’un mécanisme qui permet à un utilisateur de se connecter une seule fois pour accéder à plusieurs applications, sans avoir à se reconnecter à chaque fois. Avec OAuthSD, le SSO est mis en place pour offrir une authentification unique pour un groupe d’applications, évitant ainsi à un même internaute de devoir s’authentifier plusieurs fois pour accéder à des applications différentes.

SLI (Single Login In)  : Le SLI est un concept similaire au SSO, mais il se concentre sur le fait qu’une fois connecté, un utilisateur peut accéder à plusieurs applications sans avoir à se reconnecter. OAuthSD utilise le SLI pour faciliter la navigation et l’échange de données au sein d’une application multiple.

SLO (Single Log-Out)  : Le SLO est le pendant du SSO, mais pour la déconnexion. Il permet à un utilisateur de se déconnecter une seule fois pour se déconnecter de toutes les applications auxquelles il est connecté. Cela garantit une déconnexion globale et renforce la sécurité en cas de départ de l’utilisateur de son poste de travail.

SRA (Single Re-Authentication)  : Le SRA est un mécanisme qui permet à un utilisateur de se ré-authentifier de manière transparente lorsqu’un cookie d’authentification n’est plus valide. Cela garantit une sécurité renforcée en cas de besoin de ré-authentification.

Cet article a été écrit à l’aide de i-Tego ChatBot, en réponse à la question : "Dans le contexte d’OAuthSD, expliquer SSO, SLI, SLO, SRA."

SSO et connexion unique (Single Login Identification, SLI)

  publié le par i-Tego WM

Une fonctionnalité attendue de la délégation d’autorisation, que l’on associe naturellement à l’inscription unique (Single Sign On, SSO) est la capacité donnée à l’utilisateur final de ne se connecter qu’une seule fois pour accéder à différentes applications (Single Login Identification, SLI).

De façon standard, les flux d’OpenID Connect ne permettent pas de réaliser directement le SLI, mais des possibilités existent. On est là sur une technique peu divulguée, qui nécessite des développement significatifs du côté des applications.

A côté de ces méthodes standard, OAuthSD offre l’option de gérer le SLI et la ré-authentification silencieuse sans nécessiter de code spécifique du côté des applications clientes. Ceci est traité dans cet article : SLI, SSO, SLO et SRA sont dans un bateau : OAuthSD.

SSO et SLI

Le SSO n’implique pas automatiquement le SLI
Lorsque l’on évoque SSO ( Single Sign On ), on englobe souvent deux fonctionnalités :
- le fait de ne s’enregistrer (sign on [1]) qu’une seule fois sur un serveur d’identité et de pouvoir se connecter (entrer son login et son mot de passe) sur différentes applications sans avoir à s’enregistrer sur chacune d’elle. C’est à proprement parler le SSO.
- le fait de se connecter à une application ( sign in ) et de naviguer vers une autre sans avoir à entrer à nouveau son login et son mot de passe. Il s’agit de la Connexion Unique Single Connection, Single Login Identification (SLI).

Si le SSO est dans la nature même de OAuth 2 et OpenID Connect, il n’en est pas de même pour le SLI. En revanche, OpenID Connect offre "tout ce qu’il faut" pour le réaliser. Sans pour autant présenter de flux particulier pour cela : c’est donc une fonctionalité à développer du côté des applications (voir : OpenID Connect Session Management), ou bien une nouvelle fonctionnalité à ajouter [2] à OpenID Connect. C’est ce qu’offre OAuthSD, voir : SLI, SSO, SLO et SRA sont dans un bateau : OAuthSD .

Bien entendu, le SLI n’est possible que dans un ensemble d’applications liées à un même serveur d’identité, c’est à dire dans un espace de réseau et d’applications contrôlé par une même entité (corporate realm).

Applications situées dans le même domaine

Dans le cas d’applications situées dans le même domaine (par exemple dans diférents sous-domaines d’un domaine principal, en plus de ce domaine lui-même), une solution simple est de partager le cookie de session entre les applications. Pour cela, le concepteur des applications enregistrera le cookie pour le domaine principal au lieu de l’enregistrer pour le sous-domaine des applications (paramètres cookie_domain et cookie_path).

Cependant, les scopes sont particuliers aux applications. L’application cible doit donc ré-interroger le serveur d’autorisation pour obtenir un JWT qui lui soit propre.

Applications situées dans des domaines différents

Dans le cas d’applications situées dans des domaines différents le problème est un peu plus complexe.
La transmission d’autorisation est réputée sans solution sûre avec les flux OpenID Connect standard. En effet, l’application cible doit obtenir la certitude de l’origine du jeton reçu, et donc de l’identité de l’utilisateur final, sans pouvoir lui imposer une nouvelle demande d’identification. C’est à cela que sert la demande d’authentification silencieuse.

Demande d’authentification silencieuse (Silent Re-Authentication, SRA)

Le protocole OpenID Connect prend en charge un paramètre prompt = none sur la demande d’authentification qui permet aux applications d’indiquer que le serveur d’autorisations ne doit afficher aucune interaction de l’utilisateur (telle que l’authentification, le consentement). OAuthSD renverra la réponse demandée à l’application ou renverra une erreur si l’utilisateur n’est pas déjà authentifié, ou si un type de consentement ou une invite est requis avant de continuer.

Erreurs et suites

Les valeurs possibles pour ERROR_CODE sont définies par la spécification OpenID Connect :

- login_required : l’utilisateur n’était pas connecté à OAuthSD, l’authentification silencieuse n’est pas possible.
L’utilisateur doit être redirigé vers la page de connexion OAuthSD (sans le paramètre prompt =’none’) afin de s’authentifier.

- consent_required : l’utilisateur était connecté à OAuthSD, mais l’application attend son consentement (pour lequel il faudrait afficher une invite, ce qui est exclu par prompt=’none’).
D’après la norme, l’utilisateur devrait être redirigé vers la page de connexion OAuthSD comme précédemment.

- interaction_required : l’utilisateur était connecté à OAuthSD et a autorisé l’application, mais doit être redirigé ailleurs avant que l’authentification ne puisse être complétée, par exemple, lors de l’utilisation d’une règle de redirection.
D’après la norme, l’utilisateur devrait être redirigé vers la page de connexion OAuthSD.

En cas d’échec de l’authentification, il serait donc nécessaire de présenter un dialogue à l’utilisateur final. Mais c’est précisément ce que nous ne voulons pas.
Puisqu’il faut respecter la norme OIDC, il faut s’accommoder du fonctionnement du serveur et traiter les différents cas du côté de l’application, ou plus exactement au niveau du module d’interface (plugin) OIDC.

Première méthode (sans ID Token, avec cookie SLI) : dans un espace contrôlé par une même organisation (corporate realm), la technique du cookie SLI offert par OAuthSD devrait être mis en œuvre pour toutes les applications clientes. Il est alors possible de vérifier la connexion de l’utilisateur auprès du serveur puis de décider ce qui doit être fait en cas de non-connexion, ce qui peut conduire à rester silencieux. Cette méthode est celle que nous pratiquons dans le cadre du monitoring.

Deuxième méthode (avec ID Token) : On interroge Authorize avec prompt = ’none’ et id_token_hint, voir : id_token_hint : ré-authentification silencieuse du sujet avec l’ID Token.

SLI, SSO, SLO et SRA sont dans un bateau : OAuthSD

  publié le par i-Tego WM

Dans le cadre des flux OpenID Connect, outre la fonction d’inscription unique (Single Sign On, SSO) le serveur OAuthSD implémente la fonction d’identification unique (Single Login Identification, SLI), la déconnexion unique (Single Login Out, SLO) ainsi que la ré-authentification silencieuse (Silent Re-Authentication, SRA) [1]. Ceci sans modification du code d’interface des applications avec OIDC, tout étant pris en compte au niveau du contrôleur authorize.

Le code du serveur OAuthSD peut être paramétré pour implémenter (ou non) le SLI. La déconnexion unique (SLO) et la ré-authentification silencieuse (SRA) découlent du SLI.

Identification unique (Single Login Identification, SLI)

Lorsque le SLI est autorisé (ENABLE_SLI = true) ET que l’application cliente a été enregistrée sur le serveur avec le scope ’sli’, le contrôleur authorize traite une demande d’autorisation sans paramètre prompt comme ceci :

- La présence d’un cookie SLI enregistré sur l’agent est testée,
- si le cookie SLI est présent, non périmé et validé, il est utilisé pour l’authentification (le formulaire de login n’est pas présenté à l’utilisateur), le contrôleur retournant les jetons au client (le code d’autorisation dans le cas du flux d’autorisation avec code). A ce moment, la validité du cookie SLI est rafraichie à sa valeur initiale.
- En cas d’échec : soit il y a retour standard au client avec une erreur, soit le contrôleur présente le formulaire de login si la constante REAUTHENTICATE_NO_ROUNDTRIP est true. Dans un cas comme dans l’autre, le cookie SLI est d’abord détruit.

- Si le cookie SLI est absent :

  • si l’application cliente ne présente pas le scope ’sli’, le contrôleur agit de façon standard.
  • si l’application cliente autorise le SLI, et si l’authentification mentionnée précédemment réussit, un cookie SLI est enregistré sur l’agent dans le domaine du serveur. C’est le seul cas où le cookie SLI est créé.

Notes :
- Toute erreur "technique" (autre que les erreurs non-répétées de l’utilisateur dans l’entrée de son login ou de son mot de passe) conduit à la destruction du cookie SLI afin de protéger l’application contre les tentatives d’intrusion. Dans un tel cas le serveur ne répond pas pour ne pas orienter l’attaquant.
- Une tentative de connexion sous un identifiant d’utilisateur différent provoque également la destruction du cookie SLI, et conduit à la présentation du formulaire d’identification.
- Une tentative de se connecter depuis un poste de travail différent a le même effet.
- La fonctionnalité SLI est active dans les trois flux OpenID Connect, donc avec le plus sécurisé : Autorisation avec code. Ceci est un avantage par rapport à des solutions souvent présentées utilisant le flux Implicite.
- Le comportement des demandes avec prompt = ’none’, ’login’ et ’consent’ reste conforme au standard.
- Lorsque l’utilisateur change d’application et bénéficie du SLI, de nouvelles demandes de consentement pourraient lui être présentées.

Déconnexion unique (Single Login Out, SLO)

Le serveur expose un point de terminaison logout, permettant de déconnecter l’utilisateur de toutes les applications clientes.

La demande de déconnexion unique se fait comme une demande d’introspection en fournissant le jeton d’identité.

Lorsque la déconnexion est effectuée, tous les jetons d’accès enregistrés sur le serveur pour le sujet considéré sont effacés. De ce fait, les cookies SLI éventuellement présents sur les agents de l’utilisateur seront détruits si une tentative de connexion est effectuée.

Notez que les application clientes doivent gérer la déconnexion à leur niveau, il n’y a pas de miracle !

Si on souhaite connaître l’état actuel de connexion d’une application, il suffit de répéter la demande d’authentification avec prompt = ’none’. Si la déconnexion a eu lieu, le serveur répondra avec ’login_required’. Cette solution a l’avantage de répondre totalement à la norme OpenID Connect dans son état définitif.

Ré-authentification silencieuse (Silent Re-Authentication, SRA)

Dans le cadre du serveur OAuthSD, cette fonctionnalité résulte directement du SLI [2].

S’agissant des applications n’autorisant pas le SLI, elles ne bénéficient pas du SRA. Mais il est probable que les raisons qui ont conduit à ne pas autoriser le SLI conduiraient à ne pas autoriser le SRA.

Notons :
- qu’il est toujours possible de Rafraîchir (actualiser) un jeton d’accès,
- l’existence de la méthode id_token_hint : ré-authentification silencieuse du sujet avec l’ID Token.

Le Cookie SLI

Le cookie SLI est un concept propre à DnC permettant au serveur OAuthSD d’offrir toutes les fonctionnalités de la connexion unique (SLI, SLO, SRA, SLO) sans modification des applications clientes pourvu qu’elles soient déjà interfacées avec OpenID Connect. Compte-tenu de la complexité et de la diversité des solutions proposées par ailleurs, qui n’ont pas fait à ce jour (début 2019) de spécification définitive, c’est une contribution majeure d’OAuthSD à OpenID Connect.

Le cookie SLI est créé par le contrôleur Authorize si le SLI est autorisé pour l’application cliente (scope ’sli’).

Le cookie SLI est doublement sécurisé :
- Le cookie SLI est chiffré par un algorithme symétrique fort dont la clé est connue du seul serveur.
- Il est enregistré dans le domaine du serveur, n’est disponible qu’à travers une connexion sécurisée par HTTPS et pour le protocole HTTP seulement (il n’est pas accessible par les scripts côté user-agent).

Il existe des informations complémentaires, connectez vous pour les voir.

Notes

[1Ces fonctionnalités sont souvent comprises comme faisant partie du SSO, mais en toute rigueur le SSO ne signifie que "inscription unique".

[2D’autres implémentations font appel à de nombreux développements du côté des applications . La solution offerte par OAuthSD a l’énorme avantage de ne pas nécessiter de modification à l’application cliente. Cependant, la solution n’est pas standard. Le management de session OpenID Connect faisant l’objet d’une proposition de standard (voir OpenID Connect Session Management), OAuthSD offre également cette dernière méthode.

SRA et durée de la session de l’utilisateur

  publié le par i-Tego WM

La ’durée de la session locale’ est définie par le concepteur de l’application cliente. Dans le cadre d’OAuthSD, avec les flux entrant sur le contrôleur OpenID Authorize, comment définir en rapport les durées de vie des jetons et du cookie SLI ?

Durée de la session locale

La ’durée de la session locale’ est définie par l’application. Généralement, après authentification, une application définit une durée de validité de la connexion qui en résulte, ou "durée de la session". Lorsque celle-ci a dépassé sa fin de vie ("la session a expiré"), une nouvelle authentification est demandée à l’utilisateur s’il tente une nouvelle action nécessitant l’authentification.

L’utilisateur perçoit la durée de la session locale en ayant la mauvaise surprise de se voir présenter une nouvelle demande de connexion. L’objet de la ré-authentification silencieuse est de prolonger la session de façon transparente.

Ré-authentification silencieuse (Silent Re-Authentication, SRA)

Avec OAuthSD, si l’application a autorisé le SLI, et si la demande d’authentification est effectuée sans définir le paramètre prompt, il y a ré-authentification silencieuse (SRA) : plutôt que présenter un dialogue d’authentification, le contrôleur OpenID Authorize :
- vérifie l’existence d’un cookie SLI valide,
- vérifie que le jeton d’accès associé à l’authentification n’a pas expiré
pour répondre immédiatement avec un nouveau code d’accès [1].

L’application cliente poursuit normalement avec une demande de jetons.

Les effets de bord sont les suivants :
- le serveur rafraîchit le cookie SLI dont la durée de vie est étendue de SLI_COOKIE_LIFETIME [2] secondes,
- le jeton d’accès (Access Token) est renouvelé avec une durée de vie étendue de ACCESS_TOKEN_LIFETIME secondes,
- le jeton d’identité (ID Token) est renouvelé avec une durée de vie étendue de ID_TOKEN_LIFETIME secondes.

Rapport entre les durées de vie

Le contrôleur Authorize considère que l’utilisateur final est connecté si le jeton d’accès n’a pas expiré. On en déduit une première règle :
- Le SRA ne peut fonctionner que si ACCESS_TOKEN_LIFETIME > ’durée de la session locale’.

Si l’utilisateur n’effectue plus d’action nécessitant l’authentification (sur une des applications authentifiées avec SLI), le cookie SLI expirera SLI_COOKIE_LIFETIME après le dernier SRA, ce qui est un terme mal déterminé pour l’utilisateur [3]. Ceci incite à :
- fixer une durée de vie du cookie SLI assez importante, typiquement plusieurs fois la ’durée de la session locale’.

Pour ce qui est de la durée de vie du jeton d’identité (ID Token), qui joue le même rôle que le jeton d’accès, il parait adéquat de :
- fixer la durée de vie ID_TOKEN_LIFETIME égale à celle du jeton d’accès.

Valeurs par défaut de la configuration d’OAuthSD

Le valeurs suivantes sont adoptées par défaut dans le fichier configure.php :
ACCESS_TOKEN_LIFETIME : 7200s
ID_TOKEN_LIFETIME : 7200s
SLI_COOKIE_LIFETIME : 7200s x 3
Une ’durée de la session locale’ de 3600s serait cohérente avec ces valeurs.

Notons que le SRA sondera le contrôleur Authorize au rythme de ’durée de la session locale’ tant que l’utilisateur effectue des actions nécessitant l’authentification.

Considérations relatives à la sécurité

Si l’utilisateur n’effectue plus d’action nécessitant l’authentification sur une application donnée, celle-ci se déconnectera localement après ’durée de la session locale’. En effet, le SRA ne fonctionne que sur une demande d’authentification, elle-même déclenchée par une action de l’utilisateur après la fin de vie de la session locale. Pour autant, le serveur considérera l’utilisateur comme connecté tant que le jeton d’accès n’a pas expiré, et effectuera une reconnexion silencieuse à la première action nécessitant l’authentification. Dans ce cas, il est important de se rendre compte que la déconnexion locale n’est qu’apparente.

On pourrait donc considérer que le SRA ne va pas dans le sens de la sécurité. En effet, la limitation de durée des sessions a pour objet de déconnecter automatiquement les applications ouvertes sur un un poste de travail abandonné par son utilisateur.
Cependant, même les durées de session les plus courte sont rarement inférieures à 15mn. Ce temps est largement suffisant pour permettre une compromission.
Ce n’est donc pas tant le SRA qui est en cause, mais le fait d’abandonner sans surveillance une session ouverte.

La seule bonne parade est de déconnecter systématiquement toutes les applications avant de quitter son poste de travail, c’est le but de la Déconnexion unique (Single LogOut, SLO).

Que faire si la durée de session locale est mal connue ou non maîtrisée ?

Il arrive que la durée de la session locale soit variable ou extensible. C’est par exemple le cas lorsque le dialogue de connexion à l’application comporte une option du genre "Conserver ma connexion" ou "Se souvenir de moi" etc.
Dans ce cas, la ’durée de la session locale’ peut être beaucoup plus grande que la durée de vie fixée pour les jetons et le mécanisme SRA ne fonctionne pas, ou n’a pas vraiment d’objet.

Si malgré tout on veut absolument faire fonctionner le SRA, y compris sur de très longues ’durée de la session locale’, il est toujours possible de programmer l’application cliente pour qu’elle rafraîchisse systématiquement le jeton d’accès. Cela doit être fait avant qu’il n’arrive à péremption, sinon la déconnexion unique ne fonctionnera pas pour cette application.

Du point de vue de la sécurité, notons que le mécanisme SLI + SRA fera en sorte que toutes les applications pour lesquelles le SLI est autorisé, et auxquelles l’utilisateur sera connecté à partir du même poste de travail, hériteront de cette extension de la durée de vie apparente de leur session.

Notes

[1Dans le cas contraire, le dialogue d’identification est présenté, ce qui différencie le SRA de l’appel à Authenticate avec prompt = ’none’.

[2Voir le fichier /oidc/includes/configure.php.

[3Sauf à ce que l’application cliente vérifie fréquemment la connexion (monitoring) et signale l’approche de l’échéance.

Monitoring de l’état de l’authentification et SLO

  (publié initialement le vendredi 5 avril 2019) par i-Tego WM

Le monitoring de l’état de l’authentification a pour but de synchroniser la connexion locale d’une application avec le jeton d’accès correspondant.

OAuthSD, suivant en cela OAuth 2.0, considère que l’utilisateur final est connecté à une application tant que le jeton d’accès associé est valide.

Il n’y a pas "naturellement" de relation directe entre ce jeton et l’état de connexion local d’une application. Chaque application devra donc mettre en place un monitoring, côté client, dans le but de :
- surveiller la validité du jeton d’accès,
- réaliser la ré-authentification silencieuse et la connexion automatique,
- compléter le mécanisme de déconnexion unique (Single Logout, SLO) en provoquant la déconnexion locale de l’application lorsque le jeton d’accès a expiré.

Plusieurs solutions se présentent pour assurer le suivi de la session OIDC :

1. La communauté se voit proposer une "norme" de gestion de la session OpenID Connect (voir : OpenID Connect Session Management ) qui s’appuie sur des iframes du côté du serveur et du côté de l’application.

Dans sa version 30 publiée en août 2020, le paragraphe 5, encore présent dans la version 28, intitulé "Back-Channel Logout", disparait.
En effet, une nouvelle proposition "OpenID Connect Back-Channel Logout" évite les dysfonctionnements prévus au paragraphe "User Agents Blocking Access to Third-Party Content" :

Notez qu’au moment de la rédaction de cet article, certains agents utilisateurs (navigateurs) commencent à bloquer l’accès au contenu tiers par défaut pour bloquer certains mécanismes utilisés pour suivre l’activité de l’utilisateur final sur les sites. Plus précisément, le contenu tiers bloqué est un contenu de site Web avec une origine différente de l’origine de la fenêtre de l’agent utilisateur ciblée. Les données du site incluent les cookies et toutes les API de stockage Web (sessionStorage, localStorage, etc.).

Cela peut empêcher la capacité des notifications de l’OP au niveau du RP d’accéder à l’état de l’agent utilisateur du RP pour mettre en œuvre des actions de déconnexion locale. En particulier, les cookies et les API de stockage Web peuvent ne pas être disponibles dans le cadre OP chargé dans le contexte RP. L’effet secondaire ici est que, selon le mécanisme utilisé (cookies ou stockage Web), les données nécessaires pour recalculer session_state peuvent ne pas être disponibles. Les implémentations basées sur les cookies peuvent alors renvoyer des modifications pour chaque appel, ce qui entraîne des boucles infinies de ré-authentifications. Par conséquent, les déploiements de cette spécification sont recommandés pour inclure un code défensif pour détecter cette situation et, si possible, informer l’utilisateur final que les déconnexions RP demandées n’ont pas pu être effectuées. Les détails du code défensif nécessaire dépassent le cadre de cette spécification ; il peut varier selon l’agent utilisateur et peut varier dans le temps, car la situation de prévention du suivi de l’agent utilisateur est fluide et continue d’évoluer. ".

Une proposition de spécification qui a connu 30 modifications mais qui n’évolue plus depuis août 2020, et qui de plus se termine sur un constat de dysfonctionnement, est morte !

De plus, il ne s’agit là que d’un procédé de communication entre une application et le serveur OIDC, communication qui peut être réalisée par d’autres moyens, et notamment par interrogation régulière du contrôleur Authorize avec prompt = ’none’. Nous pensons (peut-être à tort ?) qu’une "norme" concernant une couche ISO de niveau protocole ne doit pas introduire à ce niveau un procédé de communication particulier.

2. Notre solution est présentée ici : Implémentation du monitoring avec Javascript : exemples pour SPIP et WordPress interroge donc le contrôleur Authorise avec le paramètre display=’none’.
Une implémentation côté client s’appuyant sur la norme OpenID Connect telle qu’elle existe actuellement est bien préférable à une nouvelle complication des applications clientes et permet d’éviter la violation du principe d’indépendance des couches ISO.

Avertir de la fin de session OIDC et la prolonger

  publié le par i-Tego WM

Le monitoring de l’état de l’authentification permet à l’utilisateur final de visualiser l’état de la session OIDC. Voici comment avertir l’utilisateur de l’imminence de la fin de session et lui permettre de la prolonger.

Le monitoring sera complet si l’utilisateur est averti de la fin imminente de la session OIDC et si il lui est proposé de la prolonger.

Lorsque l’on interroge Authorize avec prompt = ’none’, une particularité d’OAuthSD est de retourner dans le corps de la réponse le temps restant avant la fin de session (variable ’timeleft’, en secondes).

Toujours dans l’exemple du plugin OIDC Client pour SPIP, l’avertissement est implémenté en modifiant le code de l’objet ’200’ pour proposer à l’utilisateur de prolonger la session :

jQuery

  1. 200 : function ( data, textStatus, jqXHR){
  2.     // Signaler la connexion
  3.     $('#oidc').css('background-color', '#8f8');
  4.     $('#oidc').text(' OIDC ');
  5.     var timeleft = data['timeleft'];
  6.     if ( timeleft < 600 ) {  //[dnc28d]
  7.         // La fin de session approche
  8.         var retVal = confirm( "<?php echo _T('oidcclient:session_expire'); ?>" );
  9.         if( retVal == true ) {
  10.             // étendre la session
  11.             $.ajax({
  12.                 type : "get",
  13.                 url : "<?php echo OIDC_AUTHORIZATION_ENDPOINT; ?>",
  14.                 data : { 'response_type' : 'code',
  15.                     'client_id' : "<?php echo OIDC_CLIENT_ID; ?>",
  16.                     'user_id' : login,
  17.                     'state' :  state,
  18.                     'scope' : 'openid sli',
  19.                 }
  20.             });
  21.         }
  22.     }
  23. },

Télécharger

Les jetons sont rafraîchis en utilisant notre mécanisme de SLI, et non un jeton de rafraîchissement. Voyez ici pourquoi : Rafraîchir (actualiser) un jeton d’accès : § "Bonnes pratiques pour la sécurité".

Méthodes alternatives pour le monitoring de la session OpenID Conect et le SLO

  (publié initialement le dimanche 17 novembre 2019) par i-Tego WM

Pour synchroniser l’état de connexion de chaque application utilisée par un même utilisateur, nous avons utilisé un code javascript pour interroger régulièrement le serveur d’authentification.

S’agissant de déconnecter les sessions de toutes les applications de l’utilisateur final (SLO), il existe des alternatives.

Les trois premières alternatives font l’objet de propositions de spécification émises en 2020. OAuthSD ne met en œuvre que OpenID Connect Session Management.
La troisième solution est plus ancienne et ne devrait pas l’emporter sur ces définitions plus récentes.

Quoiqu’il en soit, la solution de monitoring implémentée par OAuthSD fonctionne parfaitement et est extrêmement simple, ne nécessitant pas de modification du serveur. Elle a l’avantage de permettre également de signaler à l’utilisateur l’approche de la fin de la session OIDC et de lui offrir de la prolonger.

Nous ne sommes donc pas très motivés pour appliquer l’une ou l’autre de ces méthodes.

OpenID Connect Front-Channel Logout

Voir : OpenID Connect Front-Channel Logout 1.0 - draft 04 (août 2020).

OpenID Connect Back-Channel Logout

Voir : OpenID Connect Back-Channel Logout 1.0 - draft 06 (août 2020).

OpenID Connect Session Management

Nous avons décrit cette méthode ici : OpenID Connect Session Management. Son principe et sa complexité sont assez semblables aux deux précédentes.
OAuthSD met en œuvre cette méthode à des fins d’expérimentation et de suivi de la norme OpenID Connect.

Solution utilisée par Drupal et Google Accounts

Voir : https://www.drupal.org/project/openid_connect_sso

Après la connexion de l’utilisateur sur le serveur ou la déconnexion de l’un des sites du réseau, le module démarre une chaîne de redirection qui visite le script SSO de chaque site du réseau.
Le script SSO définit ensuite un cookie informant le site parent de la connexion/déconnexion en attente.
Lorsque l’utilisateur visite le site réel, le cookie est lu et l’utilisateur se connecte/déconnecte automatiquement.

Cette approche est identique à celle utilisée par les comptes Google.

Le but des redirections est de donner à chaque site la possibilité de définir un cookie valide pour son domaine contournant ainsi la politique de même origine qui interdit à un site de définir un cookie pour un autre domaine.

Les redirections sont rapides et imperceptibles, car le script SSO est autonome ... et ne définit que le cookie.

  1. <?php
  2.  
  3. /**
  4.  * @file
  5.  * Creates cookies for each of the network sites to signal a login/logout.
  6.  */
  7.  
  8. if (empty($_SERVER['HTTP_HOST'])) {
  9.   // Some pre-HTTP/1.1 clients will not send a Host header.
  10.   // We can't work around this.
  11.   exit;
  12. }
  13.  
  14. // The collection of SSO script addresses which form the redirection network.
  15. // Don't include the protocol (http://, https://).
  16. // Example url (SSO script on subdomain): "a.firstsite.com"
  17. // Example url (SSO script in the Drupal directory): "firstsite.com/sso.php"
  18. $network = array(
  19.   'a.firstsite.com',
  20.   'a.shop.secondsite.com',
  21. );
  22.  
  23. // An array of network domain names. The keys are potential origin host names
  24. // which do not appear in the list above, and each value is the cookie domain
  25. // name for that host.
  26. // $domains = array();
  27.  
  28. // Enable HTTPS for all redirect URLs.
  29. // $https = true;
  30.  
  31. // Enable adding the domain name to the cookie name.
  32. // $cookie_name_strict = true;
  33.  
  34. // Validate the query parameters and network size.
  35. if (!sso_validate_query_params() || count($network) < 2) {
  36.   exit;
  37. }
  38.  
  39. // $_SERVER['HTTP_HOST'] is lowercased here per specifications.
  40. $host = strtolower($_SERVER['HTTP_HOST']);
  41.  
  42. $origin_host = $_GET['origin_host'];
  43. $origin_domain = isset($domains[$origin_host]) ? $domains[$origin_host] : $origin_host;
  44.  
  45. // Find the next site that needs to be visited in the $network, by removing
  46. // the origin site re-keying the array.
  47. foreach ($network as $delta => $site) {
  48.   if (strpos($site, $origin_domain) === 0 || strpos($site, 'a.' . $origin_domain) === 0) {
  49.     unset($network[$delta]);
  50.   }
  51. }
  52. $network = array_values($network);
  53.  
  54. if (ltrim($host, 'a.') == $origin_domain) {
  55.   // We are on the site which has started the process.
  56.   // No need to create the cookie, the site already handled its login / logout.
  57.   // Start from the beginning of the redirect list.
  58.   $redirect_destination = sso_redirect_url($network[0], !empty($https));
  59. }
  60. else {
  61.   sso_create_cookie($_GET['op']);
  62.  
  63.   foreach ($network as $delta => $site) {
  64.     if (strpos($site, $host) === 0 || strpos($site, 'a.' . $host) === 0) {
  65.       $current_site_delta = $delta;
  66.       break;
  67.     }
  68.   }
  69.  
  70.   if (!isset($current_site_delta)) {
  71.     trigger_error('Current site not found in network', E_USER_ERROR);
  72.     exit;
  73.   }
  74.  
  75.   $next_site_delta = $current_site_delta + 1;
  76.   if (isset($network[$next_site_delta])) {
  77.     // Redirect to the next network site.
  78.     $redirect_destination = sso_redirect_url($network[$next_site_delta], !empty($https));
  79.   }
  80.   else {
  81.     // We are at the last network site. In these scenarios, we need to
  82.     // redirect to the destination, or to the original host in case of a logout.
  83.     if ($_GET['op'] == 'login') {
  84.       $redirect_destination = $_GET['destination'];
  85.     }
  86.     else {
  87.       $redirect_destination = ($https ? 'https://' : 'http://') . $_GET['origin_host'];
  88.     }
  89.   }
  90. }
  91.  
  92. // Redirect the user. We need to prevent the redirect from being cached.
  93. header('Cache-Control: max-age=0', TRUE);
  94. header('Expires: Sun, 09 Aug 1987 22:00:00 +0100', TRUE);
  95. header('Pragma: no-cache', TRUE);
  96. header('Location: ' . $redirect_destination, TRUE, 302);
  97.  
  98. /**
  99.  * Validates the query parameters.
  100.  *
  101.  * Required parameters:
  102.  * - op: Tells us what the current operation is: login or logout.
  103.  * - origin_host: Indicates which site initiated the login/logout.
  104.  * Additional required parameter when the operation is "login":
  105.  * - destination: The url to redirect the user to after all redirects are done.
  106.  */
  107. function sso_validate_query_params() {
  108.   if (empty($_GET['op']) || empty($_GET['origin_host'])) {
  109.     return FALSE;
  110.   }
  111.   if (!in_array($_GET['op'], array('login', 'logout'))) {
  112.     return FALSE;
  113.   }
  114.   if ($_GET['op'] == 'login' && !isset($_GET['destination'])) {
  115.     return FALSE;
  116.   }
  117.  
  118.   return TRUE;
  119. }
  120.  
  121. /**
  122.  * Creates a cookie signaling the required operation.
  123.  *
  124.  * Removes any conflicting cookies.
  125.  *
  126.  * @param $operation
  127.  *   The operation to signal, login or logout.
  128.  */
  129. function sso_create_cookie($operation) {
  130.   if ($operation == 'login') {
  131.     $remove = 'Drupal.visitor.SSOLogout';
  132.     $create = 'Drupal.visitor.SSOLogin';
  133.   }
  134.   else {
  135.     $remove = 'Drupal.visitor.SSOLogin';
  136.     $create = 'Drupal.visitor.SSOLogout';
  137.   }
  138.  
  139.   $secure = !empty($GLOBALS['https']);
  140.  
  141.   $domain = ltrim(strtolower($_SERVER['HTTP_HOST']), 'a.');
  142.  
  143.   if (!empty($GLOBALS['cookie_name_strict'])) {
  144.     $remove .= '_' . $domain;
  145.     $create .= '_' . $domain;
  146.   }
  147.  
  148.   setcookie($remove, '', time() - 3600, '/', $domain, $secure);
  149.   // The expiration should be less than the Drupal session duration.
  150.   // The most common Drupal `session.gc_maxlifetime` value is 200000 seconds,
  151.   // so we define the expiration to half a minute before that, accordingly.
  152.   setcookie($create, 1, time() + 200000 - 30, '/', $domain, $secure);
  153. }
  154.  
  155. /**
  156.  * Returns an URL to which redirection can be issued.
  157.  *
  158.  * @param string $host
  159.  * @param bool $https
  160.  * @return string
  161.  */
  162. function sso_redirect_url($host, $https) {
  163.   if (!strpos($host, '//')) {
  164.     $host = ($https ? 'https://' : 'http://') . $host;
  165.   }
  166.   $args = array(
  167.     'op' => $_GET['op'],
  168.     'origin_host' => $_GET['origin_host'],
  169.   );
  170.   if ($_GET['op'] == 'login') {
  171.     $args['destination'] = $_GET['destination'];
  172.   }
  173.   return $host . '/?' . http_build_query($args);
  174. }

Télécharger

OpenID Connect Session Management Draft 28 de 2020

  publié le par i-Tego WM

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.

Management de session OpenID Connect avec iFrames

  publié le par i-Tego WM

Cet article décrit l’implémentation dans OAuthSD du monitoring au moyen d’iFrames tel que décrit ici : OpenID Connect Session Management.

Point d’extrémité de gestion de session

https://oa.dnc.global/check_session

Processus

Pour déterminer le statut de connexion d’un utilisateur, l’application cliente (RP) charge une iframe dont la cible src est définie sur le point d’extrémité de la gestion de session du serveur OAuthSD (OP).

Le point de terminaison de gestion de session a accès à un cookie qui stocke l’état de connexion ou l’état du navigateur d’un utilisateur. Ce cookie d’état du navigateur est mis à jour lorsqu’un utilisateur se déconnecte de l’OP.

Le RP peut ensuite utiliser un script côté client pour appeler la fonction Window.postMessage () de l’OP iframe, en envoyant l’ID client et l’état de session actuellement connu dans le texte du message.
Si le RP reçoit en retour un postMessage du bloc OP avec la valeur "changed", alors le statut de connexion de l’utilisateur sur le PO a changé et le RP peut décider de déconnecter l’utilisateur ou non.
Si la valeur "unchanged" est renvoyée, l’utilisateur est toujours connecté à l’OP.

Etat OP du navigateur (OP Browser State)

Bien que l’on parle de l’ "état de connexion de l’utilisateur final sur l’OP", le management de session dont il est question ici considère en réalité l’état de "connexion du navigateur" de l’utilisateur.

On notera que différents RP lancés sur le même navigateur partageront la même session de navigateur fondée sur le même cookie opbs.

Paramètre session_state

Le contrôleur authorize envoie la valeur session_state dans la réponse d’authentification, conjointement au code d’autorisation.

La valeur est calculée comme suit :

session_state= hash( client_id + OP Browser State + origin url )

Ce paramètre est opaque pour le RP. Il doit le stocker d’une façon ou d’une autre, pourvu qu’il puisse en récupérer la valeur

Adaptation de l’application cliente

iFrame "côté client" : nous devons créer une ressource Web dans l’application cliente (RP) capable de charger une iframe ayant pour id "iframeOP" qui cible le point de terminaison de gestion de session de l’OP.
La ressource Web doit également avoir accès à la valeur d’état de session renvoyée dans le paramètre session_state de la réponse d’autorisation. La valeur d’état de session peut avoir été stockée dans un cookie, par exemple, ou de toute autre manière permettant au script côté client dans la ressource Web de connaître sa valeur.

Voici un exemple d’extrait de code HTML pour l’iframe "côté client" :

HTML

   <iframe id = "iframeOP" src =
       "https://oa.dnc.global/check_session"
       frameborder = "0" width = "0" height = "0">
   </ iframe>

Pour vérifier l’état de connexion d’un utilisateur, il faut appeler la fonction Window.postMessage () de l’op iframe, en transmettant l’ID client et l’état de session en tant que paramètre de message au format ID client + "" + État de session et nom d’hôte du serveur OP comme paramètre d’origine cible.

Dans l’exemple de fonction JavaScript suivant, le script s’attend à ce que la valeur de l’état de session soit stockée dans un cookie nommé session_state :

Javascript

  1.     var targetOP = "https://oa.dnc.global";
  2.     function check_session() {
  3.                var client = "<id_du_client>";  // ID du client (client_id) enregistré sur le serveur
  4.                var sessionState = $COOKIES["session_state"];
  5.                var mes = client + " " + sessionState;
  6.                var iframe = window.parent.document.getElementById ("iframeOP");
  7.                iframe.contentWindow.postMessage (mes, targetOP);
  8.     }

Télécharger

Configurez la ressource Web pour écouter les postMessages de l’OP transmettant l’état de connexion de l’utilisateur. L’application devrait déconnecter l’utilisateur ( mettre fin à la session locale ) si la valeur retournée indique la déconnexion.

L’exemple JavaScript suivant montre comment ajouter un écouteur d’événement à la ressource Web pour écouter de tels messages :

Javascript

  1.    
  2.     var targetOP = "https://oa.dnc.global";
  3.    
  4.     window.addEventListener ("message", receiveMessage, false);
  5.    
  6.     function receiveMessage (e) {
  7.  
  8.                if (e.origin! == targetOP) {
  9.                          // L'origine ne vient pas de l'OP; ce message doit être rejeté.
  10.                          return;
  11.                }
  12.                if (e.data === "connected") {
  13.                          // L'utilisateur est toujours connecté à l'OP
  14.                          ...
  15.                } else{
  16.                          // l'utilisateur s'est déconnecté de l'OP
  17.                          ...
  18.                }
  19.     }

Télécharger

Notes :
- Le RP doit s’assurer que l’origine du postMessage correspond au nom d’hôte OP attendu. Tous les messages qui ne correspondent pas doivent être rejetés.
- Proxy : si l’application doit passer par un proxy pour accéder à OAuthSD (l’OP), la valeur qui doit être indiquée pour toute URL liée à l’OP doit contenir l’hôte et le port du proxy, et non l’hôte et le port de l’OP externe.

Offline Access

  publié le par i-Tego WM

Dans le cadre du flux Authorization Code d’OpenID Connect, "offline_access" est défini comme valeur de portée (scope) dans une demande d’autorisation. L’objectif serait de permettre à une application d’effectuer des opérations au nom d’un utilisateur final alors que celui-ci est hors ligne.

Ceci mérite un éclaircissement.

Spécification de la demande "offline_access"

Traduction du document OpenID Connect Core 1.0 incorporating errata set 1 § 11 :

11. Accès hors ligne
OpenID Connect définit la valeur de portée suivante pour demander un accès hors ligne :

offline_access

OPTIONNEL. Cette valeur de portée demande qu’un jeton d’actualisation OAuth 2.0 soit émis et puisse être utilisé pour obtenir un jeton d’accès qui accorde un accès au point de terminaison UserInfo [1] de l’utilisateur final même lorsque l’utilisateur final n’est pas présent (non connecté).

Lorsqu’un accès hors connexion est demandé, une valeur de paramètre d’invite de consentement DOIT être utilisée [2], sauf si d’autres conditions de traitement de la demande permettant un accès hors connexion aux ressources demandées sont en place. L’OP DOIT toujours obtenir l’autorisation de renvoyer un jeton d’actualisation permettant un accès hors ligne aux ressources demandées. Un consentement de l’utilisateur préalablement enregistré ne suffit pas toujours pour accorder un accès hors connexion [3].

À la réception d’un paramètre d’étendue contenant la valeur offline_access, le serveur d’autorisations :

- DOIT s’assurer que le paramètre prompt contient un consentement sauf si d’autres conditions de traitement de la demande permettant un accès hors ligne aux ressources demandées sont en place ; sauf si l’une de ces conditions ou les deux sont remplies, il DOIT alors ignorer la demande offline_access,
- DOIT ignorer la demande offline_access sauf si le client utilise une valeur response_type qui entraînerait le renvoi d’un code d’autorisation,
- DOIT explicitement recevoir ou avoir le consentement de tous les clients lorsque le type d’application enregistré est Web,
- DEVRAIT recevoir explicitement ou avoir le consentement de tous les clients lorsque le type d’application enregistré est natif.

L’utilisation des jetons d’actualisation n’est pas exclusive au cas d’utilisation offline_access. Le serveur d’autorisations PEUT accorder des jetons d’actualisation dans d’autres contextes qui ne relèvent pas de la portée de cette spécification [4].

Cas d’usage

L’objectif est de permettre à une application d’effectuer des opérations au nom d’un utilisateur final alors que celui-ci est hors ligne (le jeton d’accès n’est plus valide).

Un exemple est une sauvegarde périodique de certaines données chaque nuit.

Lors de la connexion, l’application cliente demandera le consentement de l’utilisateur en appelant le contrôleur Authorize avec la valeur ’offline_access’ dans le paramètre scope.

L’application devra enregistrer le jeton de rafraîchissement obtenu de façon persistante pour l’utiliser ultérieurement, même si l’utilisateur est déconnecté.

OAuthSD accorde une acception générale au jeton d’actualisation et en assure un contrôle serré

Certaines implémentations distinguent le jeton d’actualisation obtenu avec le consentement de l’utilisateur en réponse à la demande "offline_access" du jeton d’actualisation "ordinaire" (fourni sans ce consentement). Il est alors nommé "jeton hors ligne".

Nous ne voyons rien de tel dans les spécifications ni dans les tests de certification. Nous nous en tiendrons à l’interprétation de Brent Shaffer matérialisée dans la librairie OAuth 2.0 Server PHP :

Les demandes OpenID Connect incluent le jeton d’actualisation (refresh token) uniquement si la portée offline_access a été demandée et accordée.

Autrement dit : dans le cadre d’OpenID Connect, le jeton d’actualisation a une portée générale. Qu’il soit utilisé pour un scénario "hors ligne" ou pour tout autre usage ne dépend que du concepteur de l’application [5].

Bonnes pratiques pour la sécurité

Nous sommes d’avis que permettre l’actualisation du jeton d’accès affaiblit la sécurité des flux OpenID Connect (comme toute forme de délivrance de jeton en dehors du flux d’autorisation avec code).
Si vous mettez en œuvre le jeton d’actualisation, voyez les recommandations de cet article : Rafraîchir (actualiser) un jeton d’accès.

Notes

[1Seulement UserInfo ? L’examen de différents codes et documentations montre qu’un jeton retourné n’a pas un usage prédéfini. Un point à éclaircir.

[2Autrement dit un appel à Authorize avec prompt=consent.

[3C’est assez curieux : on voit mal comment une application "hors connexion" pourrait demander le consentement de l’utilisateur sans avoir pré-enregistré ce consentement quand l’utilisateur était connecté à l’application.

[4La sécurité requiert de contrôler l’usage du jeton d’actualisation, OAuthSD ne fournit ce jeton que si offline_access a été demandé.

[5On retrouve le principe général selon lequel la signification d’une portée d’autorisation (scope) ne dépend que de l’usage qui en est fait par l’application.