# SSL

Authentication | Users | Password
--- | --- | ---
✔ |  |

## Presentation

LL::NG uses Apache SSL module, like any other Apache authentication module, with extra features:

- Choice of any certificate attribute as user main login
- Allow no certificate to chain with other authentication methods

## Configuration

### With Apache

#### Enable SSL in Apache

You have to install mod_ssl for Apache.

For CentOS/RHEL:

    yum install mod_ssl

In Debian/Ubuntu mod_ssl is already shipped in `apache*-common` package.
For CentOS/RHEL, We advice to disable the default SSL virtual host configured in /etc/httpd/conf.d/ssl.conf.

#### Apache SSL global configuration

You can then use this default SSL configuration, for example in the head of /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

Put your own files instead of `ow2.cert`, `ow2.key`, `ow2-ca.cert`:

- SSLCertificateFile: Server certificate
- SSLCertificateKeyFile: Server private key
- SSLCACertificateFile: CA certificate to validate client certificates

If you specify port in virtual host, then declare SSL port:

    NameVirtualHost *:80
    NameVirtualHost *:443

#### Apache portal SSL configuration

Edit the portal virtual host to enable SSL double authentication:

    SSLEngine On
    SSLVerifyClient optional
    SSLVerifyDepth 10
    SSLOptions +StdEnvVars
    SSLUserName SSL_CLIENT_S_DN_CN

All SSL options are documented in Apache mod_ssl page.

Here are the main options used by LL::NG:

- SSLVerifyClient: set to `optional` to allow user with a bad certificate to access to LL::NG portal page. To switch to another authentication backend, use the Multi module, for example: `Multi SSL;LDAP`
- SSLOptions: set to `+StdEnvVars` to get certificate fields in environment variables
- SSLUserName (optional): certificate field that will be used to identify user in LL::NG portal virtual host

### 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 of LemonLDAP::NG

In Manager, go in `General Parameters` > `Authentication modules` and choose SSL for authentication.

You can then choose any other module for users and password.

Then, go in `SSL parameters`:

- Authentication level: authentication level for this module
- Extracted certificate field: field of the certificate affected to $user internal variable

### Auto reloading SSL Certificates

A known problematic is that many browser (Firefox, Chrome) remembers the fact that the certificate is not available at a certain time. It is particularly important for smart cards: when the card is not inserted before the browser starts, the user must restart his browser, or at least refresh (F5) the page.

It is possible with AJAX code and 3 Apache locations to bypass this limitation.

1. Modify the portal virtual host to match this example:

        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/ is an unprotected page to display a SSL test button
- /testssl/ is a SSL protected page to check the certificate
- /sslok/ is the new LemonLDAP::NG portal. You need to declare the new url in the manager: Portal → URL: https://auth.example.com/sslok/

2. Then you need to construct the Ajax page, for example in /index/bouton.html. It looks like this:

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

It is incompatible with authentication chaining (see Stack Multiple backends), because of Apache parameter “SSLVerifyClient”, which must have the value “require”