# 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1652714495099/6NnL_flSV.png align="center")

*Source :* [*https://en.wikipedia.org/wiki/SAML\_2.0*](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](https://simplesamlphp.org/)" qui permet de définir un Service Provider
    
* le module Drupal "[simplesamlphp\_auth](https://www.drupal.org/project/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](https://simplesamlphp.org/res/ssplogo-fish-only.jpg align="center")

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

```shell
$ 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.

```plaintext
- 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 :

```plaintext
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 :

```plaintext
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
<?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ètre | Dé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' &lt;/dev/urandom |
| `'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](https://github.com/simplesamlphp/simplesamlphp/blob/master/config-templates/config.php). 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 :

```php
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
<?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ètre | Dé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](https://simplesamlphp.org/docs/latest/simplesamlphp-reference-sp-remote.html) et un exemple de fichier authsources.php [est disponible ici](https://github.com/simplesamlphp/simplesamlphp/blob/master/config-templates/authsources.php)

#### 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 :

```plaintext
$ 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` :

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

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

```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}` où `{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` :

```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](https://chrome.google.com/webstore/detail/saml-chrome-panel/paijfdbeoenhembfhkhllainmocckace)

#### 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`.

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

Et ajouter ces lignes dans le fichier `config.php` :

```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.
