# SSL

Authentification | Utilisateurs | Mot-de-passe
--- | --- | ---
✔ |  |

## Présentation

LL::NG utilise le module SSL d'Apache, comme n'importe quel module d'authentification d'Apache avec quelques fonctionnalités supplémentaires :

- Choix de n'importe quel attribut du certificat comme nom d'utilisateur principal
- Autoriser les clients sans certificat dans le chaînage avec d'autres méthodes d'authentification

## Configuration

### With Apache

#### Activer SSL dans Apache

Installer mod_ssl pour Apache.

Pour CentOS/RHEL :

    yum install mod_ssl

In Debian/Ubuntu mod_ssl is already shipped in `apache*-common` package.
Pour CentOS/RHEL, il est recommandé de désactiver l'hôte virtuel SSL par défaut configuré dans /etc/httpd/conf.d/ssl.conf.

#### Configuration globale de ssl dans Apache

Il est possible d'utiliser cette configuration SSL par défaut, par exemple en tête de /etc/lemonldap-ng/portal-apache2.conf :

    SSLProtocol all -SSLv2
    SSLCipherSuite HIGH:MEDIUM
    SSLCertificateFile /etc/httpd/certs/ow2.cert
    SSLCertificateKeyFile /etc/httpd/certs/ow2.key
    SSLCACertificateFile /etc/httpd/certs/ow2-ca.cert

Placer vos propres fichiers au lieu de `ow2.cert`, `ow2.key`, `ow2-ca.cert`:

- SSLCertificateFile : certificat serveur
- SSLCertificateKeyFile : clef privée du serveur
- SSLCACertificateFile : certificat d'autorité pour valider les certificats clients

SI le port est spécifié, déclarer le port SSL :

    NameVirtualHost *:80
    NameVirtualHost *:443

#### Configuration SSL du portail dans Apache

Éditer l'hôte virtuel du portail pour activer la double authentification SSL :

    SSLEngine On
    SSLVerifyClient optional
    SSLVerifyDepth 10
    SSLOptions +StdEnvVars
    SSLUserName SSL_CLIENT_S_DN_CN

Toutes les options SSL sont documentées dans la page mod_ssl d'Apache.

Ci-dessous les principales options utilisées par LL::NG :

- SSLVerifyClient : mettre à `optional` pour autoriser les utilisateurs ne disposant pas d'un certificat valide à accéder à la page du portail LL::NG Pour basculer vers un autre backend d'authentification, utiliser le module Multi, par exemple : `Multi SSL;LDAP`
- SSLOptions : mettre à `+StdEnvVars` pour obtenir les champs du certificat dans les variables d'environnement
- SSLUserName (optionnel) : champ du certificat à utiliser pour identifier pour identifier un utilisateur dans l'hôte virtuel du portail LL::NG

### With Nginx

Enable SSL:

    ssl on;
    ssl_verify_client optional;
    ssl_certificate /etc/letsencrypt/live/my/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my/privkey.pem;
    ssl_verify_depth 3;
    ssl_client_certificate /etc/nginx/ssl/ca.pem;
    ssl_crl /etc/nginx/ssl/crl/my.crl;

You must also export SSL_CLIENT_S_DN_CN in FastCGI params:

    map $ssl_client_s_dn  $ssl_client_s_dn_cn {
               default           "";
               ~/CN=(?<CN>[^/]+) $CN;
          }
    fastcgi_param  SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;

### Configuration de LemonLDAP::NG

Dans le manager, aller dans `Paramètres généraux` > `Modules d'authentification` et choisir SSL pour l'authentification.

Vous pouvez ensuite choisir vos modules d'utilisateurs et de mots-de-passe.

Aller ensuite dans `Paramètres SSL` :

- Niveau d'authentification : niveau d'authentification pour ce module
- Champ extrait du certificat : champ du certificat affecté à la variable interne $user

### Rechargement automatique des certificats SSL

Problème connu : de nombreux navigateurs (Firefox, Chrome) enregistrent le fait qu'un certificat n'est pas disponible un certain temps. C'est particulièrement important pour les cartes à puce : lorsqu'elle n'est pas insérée avant que le navigateur ne démarre, l'utilisateur doit redémarrer ce dernier, ou au moins recharger la page (F5).

Il est possible d'éviter ceci avec un code AJAX et 3 "locations" Apache.

1. Modifier l'hôte virtuel du portail comme suit :

        SSLEngine On
        SSLCACertificateFile /etc/apache2/ssl/ca.crt
        SSLCertificateKeyFile /etc/apache2/ssl/lemonldap.key
        SSLCertificateFile /etc/apache2/ssl/lemonldap.crt

        SSLVerifyDepth 10
        SSLOptions +StdEnvVars
        SSLUserName SSL_CLIENT_S_DN_CN

        # DocumentRoot
        DocumentRoot /var/lib/lemonldap-ng/portal/
        <Directory /var/lib/lemonldap-ng/portal/>
            Order Deny,Allow
            Allow from all
            Options +ExecCGI +FollowSymLinks
            SSLVerifyClient none
        </Directory>

        <Location /index>
            Order Deny,Allow
            Allow from all
            SSLVerifyClient none
        </Location>

        <Location /testssl>
            Order Deny,Allow
            Allow from all
            SSLVerifyClient require
        </Location>

        Alias /sslok /var/lib/lemonldap-ng/portal
        <Location /sslok>
            Order Deny,Allow
            Allow from all
            SSLVerifyClient require
        </Location>

- /index/ est une page non protégée pour afficher un bouton de test SSL
- /testssl/ est une page protégée par SSL qui vérifie le certificat
- /sslok/ est le nouveau portail LemonLDAP::NG. Il faut declarer la nouvelle url dans le manager : Portail → URL: https://auth.example.com/sslok/

2. Il faut ensuite construire la page Ajax, par exemple dans /index/bouton.html. Ça ressemble à :

    <body>
    <script src="./jquery-2.1.4.min.js"             type="text/javascript"> </script>
    <!--<script src="./jquery-ui-1.8-rass.js"   type="text/javascript">  </script>-->

    <a href="http://www.google.fr" class="enteteBouton" id="continuerButton"><img src=authent.png></a>
    <script>
    $('.enteteBouton').click( function (e) {
      var b=navigator.userAgent.toLowerCase();
      if(b.indexOf("msie")!==-1){
        document.execCommand("ClearAuthenticationCache")
      }
      e.preventDefault();
      $.ajax({
            url:"https://auth.example.com/testssl",
            beforeSend:function(){},
            type:"GET",
            dataType:"html",
            success:function(c,a){
              if (c !== "") {
                    alert("Carte OK");
                    window.location.href = "https://auth.example.com/sslok/";
              }
              else {
                  alert('Carte KO');
              }
            },
            error:function (xhr, ajaxOptions, thrownError){
              if(xhr.status==404) {
                    alert("Carte OK");
                    window.location.href = "https://auth.example.com/sslok/";
              }
              else {
                  alert('Carte KO');
              }
            },
            complete:function(c,a){}
      });
    });
    </script>
    </body>

Ce n'est pas compatible avec une chaîne d'authentification (voir Empiler plusieurs backends), en raison du paramètre Apache “SSLVerifyClient”, qui doit être mis à la valeur “require”