# Multiple backends stack

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

## Presentation

This backend allows one to chain authentication method, for example to failback to LDAP authentication if Remote authentication failed…

## Configuration

You have to use `Multiple` as authentication modul (this will also force `Multiple` for the users module). Then go in `Multiple parameters` to define the modules to chain for authentication and users. Modules are separated by semi-colons/

For example:

    CAS;LDAP

If CAS failed, LDAP will be used.

You can also add a condition. Example:

    Remote $ENV{REMOTE_ADDR}=~/^192/;LDAP $ENV{REMOTE_ADDR}!~/^192/'

Multiple will try to use the same module for authentication and users. Example, if you have `DBI;LDAP` and DBI failed for authentication, it will try first to call LDAP as user database.

### Advanced configuration

The `Multiple` system can :

- stack several times the same module with a different name
- overload any LL::NG parameter when a specific backend is used

Overloading is not available trough the Manager

To stack several times the same module, use “#name” with different names. Example:

    LDAP#Openldap; LDAP#ActiveDirectory

Then you can have different parameters for each stored in a Perl hash entry named multi:

    multi => {
        'LDAP#Openldap' => {
          'ldapServer' => 'ldap1.example.com',
          'LDAPFilter' => '(uid=$user)',
        },
        'LDAP#ActiveDirectory' => {
          'ldapServer' => 'ldaps://ad.example.com',
          'LDAPFilter' => '(&(sAMAccountName=$user)(objectClass=person))',
        }
    },

This key must be stored directly in lemonldap-ng.ini:

    [portal]
    multi = {'LDAP#Openldap'=>{'ldapServer'=>'ldap1.example.com','LDAPFilter'=>'(uid=$user)'},'LDAP#ActiveDirectory'=>{'ldapServer'=>'ldaps://ad.example.com','LDAPFilter'=>'(&(sAMAccountName=$user)(objectClass=person))'}}

## Known problems

### AuthApache authentication

When using this module, LL::NG portal will be called only if Apache does not return “401 Authentication required”, but this is not the Apache behaviour: if the auth module fails, Apache returns 401.

To bypass this, follow the documentation of AuthApache module

### SSL authentication

To chain SSL, you have to set “SSLRequire optional” in Apache configuration, else users will be authenticated by SSL only.

### Complex use case

Here is a complex use case involving :

- multiple authentication with
  1. SSL
  2. Kerberos
  3. LDAP
- LemonLDAP::NG as a SAML IdP

The URLs will be:

- https://auth.example.com/kerberos: call to SSL, then Kerberos authentication
- https://auth.example.com/: call to LDAP authentication
- https://auth.example.com/kerberos/saml: official path to SAML request for LemonLDAP::NG IdP. IdP Metadatas contain URL of this form.
- https://auth.example.com/saml: redirected SAML path

In this case, redirection script described in the kerberos configuration page is insufficient. You have to transfer every parameter in SAML request, so rather use this redirection script instead:

    #!/usr/bin/perl
    use CGI ':cgi-lib';
    use strict;
    use MIME::Base64;
    use CGI::Carp 'fatalsToBrowser';

    my $uri = $ENV{"REDIRECT_URL"};
    $uri .= "?".$ENV{"REDIRECT_QUERY_STRING"};
    $uri =~ s/\/kerberos//;
    print CGI::header(-Refresh => '0; URL=https://auth.example.com'.$uri);
    exit(0);

You also have to make LemonLDAP::NG tolerant to the Path in order to have SAML request correctly detected. To do this, go in the manager, and configure the SAML Path (General Parameters > Issuer modules > SAML > Path) with a regular expression:

    ^/(kerberos/saml/|saml/)

Don't forget to configure your authentication modules accordingly. Especially the chained authentications: General Parameters > Authentication parameters > Multi parameters > Authentication stack string

    SSL;Apache;LDAP

Finally, don't forget to configure the portal virtual host with all the authentication parameters needed. Take a special care to the added RewriteRule in the SAML issuer section:

    <VirtualHost "*:443">
        ServerName auth.example.com

        SSLEngine on

        SSLCertificateFile      /etc/httpd/ssl/auth.example.com.crt
        SSLCertificateKeyFile   /etc/httpd/ssl/auth.example.com.key
        SSLCertificateChainFile /etc/httpd/ssl/chain.pem

        SSLVerifyClient optional
        SSLCACertificateFile    /etc/httpd/ssl/ca.crt
        SSLVerifyDepth 10
        SSLOptions +StdEnvVars

        LogLevel warn
        ErrorLog /var/log/httpd/error_log

        # DocumentRoot
        DocumentRoot /var/lib/lemonldap-ng/portal/
        <Directory /var/lib/lemonldap-ng/portal/>
            Require all granted
            Options +ExecCGI +FollowSymLinks
        </Directory>

        Alias /kerberos /var/lib/lemonldap-ng/portal/
        <Location /kerberos>
          Options +execCGI
          ErrorDocument 401 /redirectKRB.pl

          AuthType Kerberos
          KrbMethodNegotiate On
          KrbMethodK5Passwd Off
          AuthName "REALM.COM"
          KrbAuthRealms REALM.COM
          Krb5KeyTab /etc/httpd/keytabs/auth.keytab
          KrbVerifyKDC Off
          KrbServiceName Any
          Require valid-user
        </Location>

    [...]

        # SAML2 Issuer
        <IfModule mod_rewrite.c>
            RewriteEngine On
            RewriteRule ^/saml/metadata /metadata.pl
            RewriteRule ^/saml/.* /index.pl
            RewriteRule ^/kerberos/saml/.* /index.pl
        </IfModule>

    [...]
    </VirtualHost>