Authentification SAML 2.0 avec Drupal

SAML ... c'est quoi ?

SAML (Security Assertion Markup Language) est un "open standard" pour échanger des données d'authentification et d'autorisation entre différentes parties, et plus particulièrement entre un serveur d'identité (Identity Server, IdP) et un fournisseur de service (Service Provider, SP).

La version 2.0 est un protocole basé sur des échanges XML qui contiennent des assertions pour transmettre des informations sur un utilisateur entre l'autorité SAML (IdP) et le consommateur SAML (SP).

Le protocole SAML 2.0 permet d'effectuer des connections SSO.

SSO redirect POST

Source : https://en.wikipedia.org/wiki/SAML_2.0

Pour résumer, lorsqu'une demande d'authentification est initiée, le Service Provider (SP) redirige la requête vers l'Identity Provider (IdP) qui va afficher le formulaire de connexion. Lorsque l'utilisateur sera authentifié, l'Identity Provider (IdP) va alors rediriger la requêtes vers le Service Provider (SP) en lui fournissant une réponse SAML contenant toutes les informations de l'utilisateur (les attributs)

Pré-requis

HTTPS

Tous les échanges entre le Service Provider (SP) et l'Identity Provider (IdP) contiennent des données sensibles, il est obligatoire que les requêtes soient effectuées en HTTPS.

Et pour Drupal, comment ça se passe ?

Coté Drupal, il faut :

  • la librairie "simplesamlphp" qui permet de définir un Service Provider
  • le module Drupal "simplesamlphp_auth" qui permet d'authentifier les utilisateurs via le Service Provider définit par la librairie

La librairie simplesamlphp permet de définir à la fois un Identity Provider et un Service Provider. Ici seule la définition d'un Service Provider sera abordée.

1ère étape : définir le service provider (SP)

Installation de simplesamlphp

simplesamlphp

Sur un projet Drupal dont les dépendances sont gérées via composer, d'exécuter la commande

$ composer require "simplesamlphp/simplesamlphp" "^1.15"

Arborescence

Pour fonctionner, cette librairie à besoin de fichiers de configuration, de certificats ou encore de fichier de métadonnées qui doivent être présents dans un répertoire dont l'arborescence est configurable.

Ce répertoire ne doit pas être accessible publiquement.

Si par exemple le répertoire DOCROOT du serveur web est /var/www/html/web, il faut créer un répertoire en dehors de cette arborescence, comme par exemple /var/www/html/simplesamlphp

Exemple d'une arborescence.

- simplesamlphp
  |- cert       <-- contient les certificats
  |- config     <-- contient les fichiers de configuration
  |- metadata   <-- contient les fichiers de metadonnées

Configuration du serveur HTTP

Le Service Provider (SP) étant la cible d'une redirection en provenance de l'Identity Provider (IdP), il est est donc nécessaire que la librairie simplesamlphp soit accessible en HTTP.

Pour cela il faut modifier la configuration du vhost.

Modification d'un vhost apache :

SetEnv SIMPLESAMLPHP_CONFIG_DIR /var/www/html/simplesamlphp/config
Alias /simplesaml /var/www/html/vendor/simplesamlphp/simplesamlphp/www

<Directory /var/www/html/vendor/simplesamlphp/simplesamlphp/www>
    <IfModule !mod_authz_core.c>
        # For Apache 2.2:
        Order allow,deny
        Allow from all
    </IfModule>
    <IfModule mod_authz_core.c>
        # For Apache 2.4:
        Require all granted
    </IfModule>
</Directory>

Modification d'un vhost nginx :

location ^~ /simplesaml {
    alias /var/simplesamlphp/www;
    location ~ \.php(/|$) {
        root             /var/simplesamlphp/www;
        fastcgi_pass     127.0.0.1:9000;
        fastcgi_index    index.php;
        fastcgi_param    SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        fastcgi_param    PATH_INFO $fastcgi_path_info;
        include          fastcgi_params;
    }
}

La page https://my-web-site.example.org/simplesaml/index.php doit être accessible.

Configuration de simplesamlphp

Dans le répertoire de configuration, il faut créer 2 fichiers :

  • config.php : configuration de la librarie simplesamlphp
  • authsources.php : définition du Service Provider (SP)

config.php

Ce fichier contient toute la configuration de la librairie.

<?php  

$config = [
  'baseurlpath' => '/simplesaml/',
  'auth.adminpassword' => 'admin',
  'admin.protectindexpage' => TRUE,
  'admin.protectmetadata' => TRUE,
  'secretsalt' => 'defaultsecretsalt',
  'timezone' => 'Europe/Paris',
  'certdir' => dirname(__DIR__) . '/cert',
  'metadatadir' => dirname(__DIR__) . '/metadata',
  'technicalcontact_name' => 'Marcel Dupont',
  'technicalcontact_email' => 'marcel.dupont@example.org',
];
ParamètreDéfinition
'baseurlpath'C'est le chemin web permettant d'accéder à la librairie. Ce chemin est totalement libre, mais s'il est modifié, il faut aussi penser à modifier les Alias dans la configuration du serveur HTTP (c.f. Configuration serveur HTTP)
'auth.adminpassword'Mot de passe pour l'interface d'administration.
'admin.protectindexpage'Permet de définir si les pages publiques de l'interface simplesamlphp sont accessibles sans authentification. Même si la configuration n'est pas accessible, il est préférable de tout protéger.
'admin.protectmetadata'Permet de définir si le fichier de métadonnées est protégé ou non.
'secretsalt'Chaine de caractère aléatoire utilisé pour générer des clés de hachage sécurisées.
Un "secret salt" peut être généré avec la commande `$ tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom
dd bs=32 count=1 2>/dev/null;echo`
'timezone'
'certdir'Répertoire dans lequel sont stockés les certificats
'metadatadir'Répertoire dans lequel sont stockés les métadonnées
'technicalcontact_name'Nom du contact technique
'technicalcontact_email'Adresse email du contact technique

Un exemple de fichier config.php est disponible ici. Il contient toute la configuration possible.

Cache HTTP

Si le serveur est derrière un serveur de cache HTTP (Varnish par exemple), il est absolument nécessaire d'interdire le cache des pages /simplesaml/*.

Pour cela il faut ajouter dans le fichier config.php la ligne :

setcookie('NO_CACHE', '1');

authsources.php

C'est dans ce fichier que sont définies toutes les sources d'authentification, c'est donc dans ce fichier que sont définis les Service Provider (SP) ou les Identity Provider (IdP).

<?php  

$config = [
  'my-sp1' => [
    'saml:SP',
    'entityID' => 'https://my-sp.example.org',
    'idp' => 'https://idp-server.com',
    'privatekey' => 'saml.pem',
    'certificate' => 'saml.crt',
    'sign.authnrequest' => TRUE,
    'sign.logout' => TRUE,
    'redirect.sign' => TRUE,
    'redirect.validate' => TRUE,
  ],
  'my-sp2' => [...],
];

En détail, ça veut dire :

'my-sp1' / 'my-sp2' : C'est le nom de la configuration. Ce nom est totalement libre. Il est possible de définir autant de Service Provider (SP) que désiré.

ParamètreDéfinition
'saml:SP'Permet de définir que la configuration est de type saml:SP qui déclare donc un Service Provider (SP).
'entityID'C'est l'identifiant de l'entité correspondant à ce Service Provider (SP). Il est préférable de mettre l'URL du site comme entityID. Toutefois ce paramètre est optionnel, s'il n'est pas renseigné, un ID sera généré automatiquement, cet ID aura pour valeur l'URL à laquelle le fichier de métadonnées pourra être téléchargé.
'idp'L'adresse de l'Identity Provider (IdP)
'privatekey'Le nom du fichier contenant la clé privée, sans le chemin puisque la librairie va directement localiser le fichier dans le répertoire cert.
'certificate'Le nom du fichier contenant le certificat, sans le chemin puisque la librairie va directement localiser le fichier dans le répertoire cert.
'sign.authnrequest'Permet de définir si les requêtes d'authentification doivent être signées ou non. Il est recommandé de mettre la valeur à TRUE
'sign.logout'Permet de définir si les requêtes de déconnexion doivent être signées ou non. Il est recommandé de mettre la valeur à TRUE
'redirect.sign'Permet de définir si les redirections doivent être signées ou non. Il est recommandé de mettre la valeur à TRUE
'redirect.validate'Permet de définir si les redirections doivent être validées ou non. Il est recommandé de mettre la valeur à TRUE

Ces paramètres sont les essentiels pour une configuration de base. Selon les besoin de l'Identity Provider (Idp), il est possible que d'autres paramètres soient nécessaires.

Les différents paramètres disponibles pour la définition d'un Service Provider sont disponibles ici et un exemple de fichier authsources.php est disponible ici

Certificats

Les échanges entre les Service Provider (SP) et l'Identity Provider (IdP) étant chiffrés, il est nécessaire d'avoir un certificat.

Si le certificat existe déjà, il suffit de le copier dans ce répertoire.

Sinon, pour créer un certificat :

$ cd cert
$ openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out saml.crt -keyout saml.pem

Cette commande va générer un fichier saml.crt et un fichier sam.pem

Il est nécessaire d'avoir un certificat .crt et son .pem associé.

Interface d'administration de simplesamlphp

Afin d'accéder à l'interface d'administration, il faut configurer simplesamlphp pour y accéder avec un compte d'administration.

Il faut ajouter dans authsources.php :

$config = [
    'admin' => [
      'core:AdminPassword',
    ],
];

et définir le mot de passe admin dans le fichier config.php

$config = [
  'auth.adminpassword' => 'admin',
];

2ème étape : l'échange des fichiers de métadonnées

Pour que l'authentification fonctionne, il est nécessaire que l'Identity Provider (IdP) et le Service Provider (SP) se "connaissent" l'un et l'autre. Le seul moyen d'y parvenir c'est d'échanger les fichiers de métadonnées.

Le Service Provider (SP) doit fournir son fichier de métadonnées à l'Identity Provider (IdP). L'Identity Provider (IdP) doit fournir son fichier de métadonnées au Service Provider (SP).

La page https://my-web-site.example.org/simplesaml/module.php/core/frontpage_federation.php permet de voir tous les Service Provider (SP) définis ainsi que tous les Identity Provider (IdP) déclarés.

Fournir son fichier de métadonnées à l'Identity Provider (IdP)

Une fois la première étape réalisée, la page https://my-web-site.example.org/simplesaml/simplesaml/module.php/saml/sp/metadata.php/{service-provider-name}{service-provider-name} correspond au nom donné au service provider dans le fichier authsources.php doit être accessible. Avec l'exemple ci dessus, ca donne l'url https://my-web-site.example.org/simplesaml/module.php/saml/sp/metadata.php/my-sp1

Cette page permet de voir le fichier de métadonnées correspondant au service provider. Il suffit simplement de télécharger le fichier xml et de le fournir à l'Identity Provider (IdP).

L'identity Provider (IdP) devra fournir son fichier de métadonnées en retour afin de le déclarer dans le Service Provider (SP)

Déclarer le fichier de métadonnées de l'Identity Provider (IdP)

Lorsque l'Identity Provider (IdP) aura fourni son fichier de métadonnées, il faut le déclarer dans le Service Provider (SP).

Il faut donc aller sur la page https://my-web-site.example.org/simplesaml/admin/metadata-converter.php, y coller le contenu du fichier xml de métadonnées pour ainsi le transformer en un tableau PHP.

Le résultat doit être ajouté dans le fichier metadata/saml20-idp-remote.php

3ème étape : test de l'authentification

Une fois les fichiers de métadonnées échangés, il ne reste plus qu'à tester l'authentification.

Il faut se rendre sur la page https://my-web-site.example.org/simplesaml/module.php/core/authenticate.php et choisir le Service Provider à tester. La redirection doit immédiatement se faire vers le formulaire de connexion de l'Identity Provider (IdP).

4ème étape : Configuration du module Drupal

Lorsque le test de l'authentification est concluant, il faut maintenant configurer le module Drupal pour intégrer l'authentification à la gestion des utilisateurs de Drupal.

Après avoir activé le module simplesamlphp_auth, il faut se rendre sur la page https://my-web-site.example.org/admin/config/people/simplesamlphp_auth

  • Il faut activer l'authentification SAML en cochant Activate authentication via SimpleSAMLphp
  • Le champ Authentication source for this SP doit contenir le nom du Service Provider (SP) défini précédemment (exemple my-sp1)
  • Le champ Federated Log In Link Display Name contient le nom que portera le lien sur la page /user/login

Sur la page https://my-web-site.example.org/admin/config/people/simplesamlphp_auth/sync il faut définir quels sont les attributs à utiliser dans la réponse SAML pour alimenter les attributs des utilisateurs Drupal.

Les attributs de la réponse SAML sont visibles après avoir testé le Service Provider (SP) https://my-web-site.example.org/simplesaml/module.php/core/authenticate.php

Problèmes fréquents

Boucle de redirection

Il est possible que ce soit un problème de cookie, dans un premier temps, supprimer tous les cookies et recommencer.

Si le problème persiste, et que le site se trouve derrière un reverse proxy, il faut adapter la configuration.

Ajouter au fichier config.php :

$protocol = 'http://';
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $_SERVER['SERVER_PORT'] = 443;
  $_SERVER['HTTPS'] = 'true';
  $protocol = 'https://';
}

if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
  $config['baseurlpath'] = $protocol . $_SERVER['HTTP_X_FORWARDED_HOST'] . '/simplesaml/';
}
else {
  $config['baseurlpath'] = $protocol . $_SERVER['HTTP_HOST'] . '/simplesaml/';
}

Pour aller plus loin

Extension chrome

Pour debugger les réponses SAML, il existe une extension chrome qui permet d'ajouter un onglet SAML dans les outils de développement pour afficher le contenu des réponses SAML.

Extension téléchargeable ici

Utilisation de Redis pour le stockage des sessions SAML

Simplesamlphp permet de stocker les sessions dans une instance redis.

Pour ce faire, il faut ajouter la librairie predis.

$ composer require "predis/predis" "~1.1"

Et ajouter ces lignes dans le fichier config.php :

$config = [
  'store.type' => 'redis',
  'store.redis.host' => '{redis_host}',
  'store.redis.port' => '{redis_port}',
  'store.redis.prefix' => 'SimpleSAMLphp',
];

Pour conclure

Nous venons de voir comment configurer simplement et rapidement Drupal pour lui ajouter une connexion SSO via le protocole SAML 2.0.

Ce n'est pas la seule connexion SSO qu'il est possible d'implémenter dans Drupal, nous pouvons (tout aussi facilement, voire même plus) ajouter une authentification OpenID Connect, ce qui fera l'objet d'un prochain article.