Accueil > OpenID Connect OAuth Serveur dédié > Développer > OpenID Connect > Méthodes alternatives pour le monitoring de la session OpenID Conect et le (...)

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

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