Accueil > OpenID Connect OAuth Server par DnC > Développer > OpenID Connect > Drupal et Google Accounts : méthode alternative pour le monitoring

Drupal et Google Accounts : méthode alternative pour le monitoring

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.
Il existe une alternative 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