Documentation

Server 2.x

LDAP#

This document describes how to configure LDAP. We assume you used the deploy_${DIST}.sh script to deploy the software.

The LDAP integration can be used both for user authentication and for authorization, i.e. who will be considered an administrator and which profiles will be available for a particular user.

For more information about authorization, after getting authentication to work, you can look here for determining admin portal access, and here for determining who can access which profiles.

NOTE: we have an instruction video on how to configure Active Directory via LDAP here

Introduction#

It is a good idea to try with ldapsearch if you are not absolutely sure what to configure. Once ldapsearch works, it becomes easier to configure the LDAP module.

First, install ldapsearch and the PHP module for LDAP:

$ sudo yum install openldap-clients php-ldap  # CentOS/Fedora
$ sudo apt install ldap-utils php-ldap        # Debian

Restart PHP to activate the LDAP module:

$ sudo systemctl restart php-fpm                            # CentOS/Fedora
$ sudo systemctl restart php$(/usr/sbin/phpquery -V)-fpm    # Debian

You need a couple of details first, you can obtain those from your LDAP administrator, you need at least:

FreeIPA#

For simple FreeIPA setups these are sufficient. Here the uid we want to use for users to authenticate is part of the DN:

$ ldapsearch \
    -W \
    -H ldap://ipa.tuxed.example \
    -D "uid=fkooman,cn=users,cn=accounts,dc=tuxed,dc=example" \
    -b "uid=fkooman,cn=users,cn=accounts,dc=tuxed,dc=example"

After providing the user’s password, you should see all the LDAP attributes associated with that user account, e.g. memberOf, mail, uid.

Active Directory#

If you are using Active Directory, it is slightly different, replace DOMAIN with the name of your domain and fkooman with a valid user in your AD:

$ ldapsearch \
        -W \
        -H ldap://ad.example.org \
        -D "DOMAIN\fkooman" \
        -b "dc=example,dc=org" \
        "(sAMAccountName=fkooman)"

You can use the old “NetBIOS domain name” as in the example above, or some other options, e.g. userPrincipalName:

$ ldapsearch \
        -W \
        -H ldap://ad.example.org \
        -D "fkooman@example.org" \
        -b "dc=example,dc=org" \
        "(userPrincipalName=fkooman@example.org)"

Search First#

If you want to use an attribute that is NOT part of the DN, you first need to perform a search for the user’s DN, based on the attribute + value you want. For example we want the users to login with the uidNumber attribute and my uidNumber happens to be 572600001:

For this we do an anonymous bind to figure out my DN in the LDAP:

$ ldapsearch \
    -LLL \
    -x \
    -H ldap://server.ipa.test \
    -b "cn=users,cn=accounts,dc=ipa,dc=test" \
    "(uidNumber=572600001)" \
    dn

This returns my DN, in this case dn: uid=fkooman,cn=users,cn=accounts,dc=ipa,dc=test which we can now use to bind now to the server to verify the password:

$ ldapsearch \
    -LLL \
    -W \
    -H ldap://server.ipa.test \
    -D "uid=fkooman,cn=users,cn=accounts,dc=ipa,dc=test" \
    -b "uid=fkooman,cn=users,cn=accounts,dc=ipa,dc=test"

If this works, we can use this information as explained below in the configuration examples.

Configuration#

You can configure the portal to use LDAP. This is configured in the file /etc/vpn-user-portal/config.php.

You have to set authMethod first:

'authMethod' => 'FormLdapAuthentication',

Next is configuring the LDAP server in the FormLdapAuthentication section.

NOTE: {{UID}} is a special template variable that is replaced by what the user specifies in the “User Name” box at login in the portal. If you specify DOMAIN\{{UID}} as bindDnTemplate in the configuration, the actual “bind DN” will become DOMAIN\fkooman assuming the user entered fkooman as “User Name” in the portal.

The userIdAttribute is used to normalize the user identity. For LDAP both fkooman and FKOOMAN are the same. By querying the userIdAttribute we take the exact same format as used in the LDAP server.

'FormLdapAuthentication' => [
    // *** FreeIPA ***
    // -H ldap://ipa.tuxed.example
    'ldapUri' => 'ldap://ipa.tuxed.example',
    // -D "uid=fkooman,cn=users,cn=accounts,dc=tuxed,dc=example"
    'bindDnTemplate' => 'uid={{UID}},cn=users,cn=accounts,dc=tuxed,dc=example',
    // (if -b is the same -D we do NOT specify baseDn...)
    // to normalize the entered user ID, specify the attribute you want to
    // use to identify the user in the VPN server
    'userIdAttribute' => 'uid',

    // *** AD (NetBIOS domain name) ***
    // -H ldap://ad.example.org \
    'ldapUri' => 'ldap://ad.example.org',
    // -D "DOMAIN\fkooman" \
    'bindDnTemplate' => 'DOMAIN\{{UID}}',
    // -b "dc=example,dc=org" \
    'baseDn' => 'dc=example,dc=org',
    // "(sAMAccountName=fkooman)"
    'userFilterTemplate' => '(sAMAccountName={{UID}})',
    // to normalize the entered user ID, specify the attribute you want to
    // use to identify the user in the VPN server
    'userIdAttribute' => 'sAMAccountName',

    // *** AD (userPrincipalName) ***
    // -H ldap://ad.example.org \
    'ldapUri' => 'ldap://ad.example.org',
    // -D "fkooman@example.org" \
    'bindDnTemplate' => '{{UID}}',

    // when the user does NOT specify the realm, e.g. only "fkooman", this
    // option will add "@example.org" to the "User Name" as specified on 
    // the login page. If and only if there is no "@" in the provided 
    // "User Name".!
    'addRealm' => 'example.org',
    // -b "dc=example,dc=org" \
    'baseDn' => 'dc=example,dc=org',
    // "(userPrincipalName=fkooman@example.org)"
    'userFilterTemplate' => '(userPrincipalName={{UID}})',
    // to normalize the entered user ID, specify the attribute you want to
    // use to identify the user in the VPN server
    'userIdAttribute' => 'userPrincipalName',

    // *** Search First ***
    // -H ldap://server.ipa.test \
    'ldapUri' => 'ldap://server.ipa.test',
    // -b "cn=users,cn=accounts,dc=ipa,dc=test" \
    'baseDn' => 'cn=users,cn=accounts,dc=ipa,dc=test',
    // "(uidNumber=572600001)" \
    'userFilterTemplate' => '(uidNumber={{UID}})',
    // to normalize the entered user ID, specify the attribute you want to
    // use to identify the user in the VPN server
    'userIdAttribute' => 'uidNumber',
    // in vpn-user-portal >= 2.3.8 you can also perform a bind before 
    // searching as not all LDAP servers allow anonymous bind to search the
    // directory. If at all possible, allow anonymous bind on your LDAP 
    // server from the VPN server. NEVER USE THE LDAP ADMIN ACCOUNT HERE!
    //'searchBindDn' => 'cn=Anonymous Search User,dc=example,dc=org',
    //'searchBindPass' => 's3r3t',
],

This should be all to configure your LDAP!

LDAPS#

In order to use LDAPS, you can use the LDAPS scheme in the baseUri configuration option, e.g.:

'ldapUri' => 'ldaps://ldap.example.org',

If you use LDAPS and your LDAP server has a self signed certificate you may need to make the CA certificate available on the VPN machine.

On the IPA server the CA certificate is stored in /etc/ipa/ca.crt. Copy this to the machine running the VPN software. If you don’t have direct access to the IPA server you can also use OpenSSL to obtain the CA certificate:

$ openssl s_client -showcerts -connect ipa.example.org:ldaps

You can copy/paste the CA certificate from the certificates shown.

NOTE: make sure you validate this CA out of band! You MUST be sure this is the actual CA!

CentOS / Fedora#

If you use a self signed certificate for your LDAP server perform these steps. If your certificate is signed by a trusted CA you do not need to do this, it will work out of the box.

Put the self signed certificate file in /etc/pki/ca-trust/source/anchors. After this:

$ sudo update-ca-trust

This will add the CA certificate to the system wide database in such a way that it will remain there, even when the ca-certificates package updates.

You MUST restart php-fpm to pick up the changes:

$ sudo systemctl restart php-fpm

Debian#

If you use a self signed certificate for your LDAP server perform these steps. If your certificate is signed by a trusted CA you do not need to do this, it will work out of the box.

Put the self signed certificate file in /usr/local/share/ca-certificates/ipa.example.org.crt. After this:

$ sudo update-ca-certificates

This will add the CA certificate to the system wide database in such a way that it will remain there, even when the ca-certificate package updates.

You MUST restart php-fpm to pick up the changes:

$ sudo systemctl restart php$(/usr/sbin/phpquery -V)-fpm