Authentication | Users | Password |
---|---|---|
✔ |
LL::NG uses Apache SSL module, like any other Apache authentication module, with extra features:
By default, SSL is required before the portal is displayed (handled by webserver). If you want to display a button to connect to LLNG (compatible with Combination), you can activate "SSL by Ajax request" in the manager. See SSL by Ajax below.
You have to install mod_ssl for Apache.
For CentOS/RHEL:
yum install mod_ssl
apache*-common
package.
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
ow2.cert
, ow2.key
, ow2-ca.cert
:If you specify port in virtual host, then declare SSL port:
NameVirtualHost *:80 NameVirtualHost *:443
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:
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
+StdEnvVars
to get certificate fields in environment variablesEnable 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 directive must be in http context map $ssl_client_s_dn $ssl_client_s_dn_cn { default ""; ~/CN=(?<CN>[^/]+) $CN; # prior Nginx 1.11.6 #~,CN=(?<CN>[^,]+) $CN; # Nginx >= 1.11.6 } fastcgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;
server { listen 443; server_name authssl.example.com; root /usr/share/lemonldap-ng/portal/htdocs/; # Use "lm_app" format to get username in nginx.log (see nginx-lmlog.conf) access_log /var/log/nginx/access.log lm_app; ssl_verify_client on; ssl_verify_depth 3; # Full chain CRL is required # All CRLs must be concatenated in a single .pem format file ssl_crl /etc/nginx/ssl/crl/crls.pem; if ($uri !~ ^/((static|javascript|favicon).*|.*\.psgi)) { rewrite ^/(.*)$ /index.psgi/$1 break; } location ~ ^(?<sc>/.*\.psgi)(?:$|/) { # uWSGI Configuration include /etc/nginx/uwsgi_params; uwsgi_pass 127.0.0.1:5000; uwsgi_param LLTYPE psgi; uwsgi_param SCRIPT_FILENAME $document_root$sc; uwsgi_param SCRIPT_NAME $sc; uwsgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn; } #index index.psgi; location / { try_files $uri $uri/ =404; add_header Strict-Transport-Security "max-age=15768000"; } }
In Manager, go in General Parameters
> Authentication modules
and choose SSL for authentication.
Then, go in SSL parameters
:
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>
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>
If you enable this feature, you must configure 2 portal virtual hosts:
SSLVerifyClient none
SSLVerifyClient require
and a Header set Allow-Control-Allow-Origin https://portal-main-url
then declare the second URL in SSL options in the Manager. That's all ! Then you can chain it in a combination.
To avoid a persistent loop between Portal and a redirection URL (pdata is not removed because domains mismatch), you have to set pdata cookie domain by editing lemonldap-ng.ini
in section [portal]:
[portal] pdataDomain = example.com
To avoid a bad/expired token during session upgrading (Reauthentication) if URLs are served by different load balancers, you can force Upgrade tokens to be stored into Global Storage by editing lemonldap-ng.ini
in section [portal]:
[portal] forceGlobalStorageUpgradeOTT = 1
Go to : General Parameters > Advanced Parameters > Security > Content security policy
and set :
Default value => 'self' "Ajax request URL"
Form destinations => 'self' "Ajax request URL"
Ajax destinations => 'self' "Ajax request URL"
Script source => 'self' "Ajax request URL"