OpenLDAP Server

Installing an OpenLDAP Server for central user management

This post explains how to setup a LDAP DNS server inside a jail and surround it with a phpLDAPadmin web UI inside that same jail. Whenever a new client is served an ip address from the DHCP server, the DHCP server will update the DNS server with the new ip address dynamically.

OpenLDAP

The first thing we need to do is to install the needed openldap-server package. Before we do that we set the time zone though:

tzsetup Europe/Berlin
pkg install openldap-server

After installation of the openldap-server package we already get two messages – one from the openldap-client package and one from the openldap-server package. Let’s look at the openldap-client message:

Message from openldap-client-2.4.45:

************************************************************

The OpenLDAP client package has been successfully installed.

Edit
  /usr/local/etc/openldap/ldap.conf
to change the system-wide client defaults.

Try `man ldap.conf' and visit the OpenLDAP FAQ-O-Matic at
  http://www.OpenLDAP.org/faq/index.cgi?file=3
for more information.

************************************************************

We will actually follow that right away and edit our ldap.conf file as follows:

BASE    dc=home,dc=local 
URI     ldap://ldap1.home.local ldap://ldap1.home.local:666

SIZELIMIT       0
TIMELIMIT       15
DEREF           never

The other message we get is from openldap-server:

Message from openldap-server-2.4.45_4:

************************************************************

The OpenLDAP server package has been successfully installed.

In order to run the LDAP server, you need to edit
  /usr/local/etc/openldap/slapd.conf
to suit your needs and add the following lines to /etc/rc.conf:
  slapd_enable="YES"
  slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/"'
  slapd_sockets="/var/run/openldap/ldapi"

Then start the server with
  /usr/local/etc/rc.d/slapd start
or reboot.

Try `man slapd' and the online manual at
  http://www.OpenLDAP.org/doc/
for more information.

slapd runs under a non-privileged user id (by default `ldap'),
see /usr/local/etc/rc.d/slapd for more information.

************************************************************

We will copy the following entries into our /etc/rc.conf:

slapd_enable="YES"
slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/"'
slapd_sockets="/var/run/openldap/ldapi"

Also, we have to seriously edit our /usr/local/etc/openldap/slapd.conf file and make sure that the following lines are in the config file:

# Include 4 important schema files at least
include         /usr/local/etc/openldap/schema/core.schema
include         /usr/local/etc/openldap/schema/cosine.schema
include         /usr/local/etc/openldap/schema/inetorgperson.schema
include         /usr/local/etc/openldap/schema/nis.schema

# Define the storage location for pid and argument file
pidfile         /var/run/openldap/slapd.pid
argsfile        /var/run/openldap/slapd.args

# set the log level so we stat log connections/operations/results
loglevel        256

# Load dynamic backend modules:
modulepath      /usr/local/libexec/openldap
moduleload      back_mdb

#######################################################################
# MDB database definitions
#######################################################################
database        mdb
maxsize         1073741824

# Define our domain suffix and root dn
suffix          "dc=home,dc=local"
rootdn          "cn=Manager,dc=home,dc=local"

# Use of strong authentication for password
rootpw        {SSHA}SYPSMKmTgbugazvkHadr47fra83ISyON
password-hash {SSHA}

# The database directory MUST exist prior to running slapd AND 
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory       /var/db/openldap-data
# Indices to maintain
index   objectClass     eq

Now you might wonder where the root password comes from? Very easy – you need to create the hash using the slappasswd utility on the command line.

slappasswd -h "{SSHA}"

You will be asked to enter a password and in return you will receive a strong hash for your password (in the example above the password test123 has produced the hash SYPSMKmTgbugazvkHadr47fra83ISyON).

Now we can already start our OpenLDAP server using the following command:

service slapd start

If we look into /var/log/messages we can see the correct start of the server. However, ideally we want a separate log file just for OpenLDAP. We can create that logfile by adding the following two lines into the /etc/syslog.conf file:

!slapd
*.*                                             /var/log/slapd.log

We need to create the empty log file and restart the syslogd daemon next:

touch /var/log/slapd.log
service syslogd restart
service slapd restart

With that done we should see a separate log file with the following content:

Mar 18 11:07:28 ldap slapd[54700]: @(#) $OpenLDAP: slapd 2.4.45 (Mar 15 2018 21:57:40) $        root@111amd64-default-job-17:/wrkdirs/usr/ports/net/openldap24-server/work/openldap-2.4.45/servers/slapd
Mar 18 11:07:28 ldap slapd[54701]: slapd starting

Finally we can create ourselves a small LDIF file and import that into our database.

dn: dc=home,dc=local
objectclass: dcObject
objectclass: organization
o: home
dc: home

dn: cn=Manager,dc=home,dc=local 
objectclass: organizationalRole
cn: Manager

When importing the file you will be asked for a password. The password you have to enter is the same you have put as a hash into the /usr/local/etc/openldap/slapd.conf file (in our example we used test123).

cd /usr/local/etc/openldap
ldapadd -D "cn=Manager,dc=home,dc=local" -W -f import.ldif

Congratulations! Our OpenLDAP server is setup and ready to be used. Special note here: in case you need a SAMBA schema you will note the schema files are not provided by the OpenLDAP installation. Don’t worry, you can find the schema here: https://raw.githubusercontent.com/samba-team/samba/master/examples/LDAP/samba.schema

Nginx

We actually would like to have a web frontend for our OpenLDAP server. One easy way is to install phpLDAPadmin which requires Nginx and PHP. Let’s start by installing Nginx:

pkg install nginx

Right after installation we can enable the service in /etc/rc.conf

sysrc nginx_enable=YES
nginx_enable:  -> YES

After that we can start the service and test it:

service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

If you have a SSL certificate you need to put the following into your server section of your nginx.conf file:

    server {
        listen          443 ssl;
        server_name     ldap1 ldap1.home.local;

        ssl_certificate         ldap1.home.local.bundle.pem;
        ssl_certificate_key     ldap1.home.local.key.pem;

Above will take care of serving content via https. In addition you could redirect all http traffic to https by putting in an additional server section:

    server {
        listen          80 default;
        server_name     ldap1 ldap1.home.local;
        access_log      off;
        error_log       off;
        ## redirect http to https ##
        return          301 https://$server_name$request_uri;
    }

PHP

For phpLDAPadmin we are going to install version 5.6 of PHP. Let’s install the package via package manager:

pkg install php56

First of all we need a php.ini file. We can just copy the production example that comes along with the package:

cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

In the php.ini file we should apply the following fix:

;cgi.fix_pathinfo=1
cgi.fix_pathinfo=0

Next we need to adapt /usr/local/etc/php-fpm.conf to setup fpm for our needs. Find the line where it says at which port to listen and replace that line with an instruction to use a socket file instead.

;listen = 127.0.0.1:9000
listen = /var/run/php-fpm.sock

In the same file find the three lines about listener ownership and uncomment them. Please note that you have to change the listen.mode from 0660 to 0666 as otherwise phpLDAPadmin will complain about missing _SESSION variables (don’t ask me why… didn’t further investigate this).

listen.owner = www
listen.group = www
listen.mode = 0666

Next we have to take care of a couple of things in the Nginx configuration. Edit your nginx.conf file to replace the location section as follows:

#location / {
#    root   /usr/local/www/nginx;
#    index  index.html index.htm;
#}

location / {
    try_files $uri $uri/ =404;
}

root /usr/local/www/nginx;
index index.php index.html index.htm;

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    include fastcgi_params;
}

Now let’s enable the php fpm service.

sysrc php_fpm_enable=YES

php_fpm_enable:  -> YES

And of course, let’s start the php fpm service.

service php-fpm start

Performing sanity check on php-fpm configuration:
[25-Mar-2018 13:09:41] NOTICE: configuration file /usr/local/etc/php-fpm.conf test is successful

Starting php_fpm.

Last but not least we need to restart Nginx.

service nginx restart

Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Stopping nginx.
Waiting for PIDS: 30037.
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

phpLDAPadmin

Let’s install the package via package manager:

pkg install phpldapadmin

The package manager will tell you that it installed phpLDAPadmin into folder /usr/local/www/phpldapadmin. As a first activity, we need to edit the config.php configuration file as we need to setup our LDAP connection details. For that please change the following lines as follows:

// $servers->setValue('server','host','127.0.0.1');
$servers->setValue('server','host','ldap://ldap1.home.local');

// $servers->setValue('server','port',389);
$servers->setValue('server','port',389);

// $servers->setValue('login','auth_type','session');
$servers->setValue('login','auth_type','session');

Eventually we have to edit our nginx.conf again as we need to point the web server root to phpLDAPadmin.

#root /usr/local/www/nginx;
root /usr/local/www/phpldapadmin/htdocs;

For the change to take effect please restart Nginx:

service nginx restart

When creating new posix accounts we should make sure that user ids do not collide with local system users. The way we do it is to make sure new users are being created with ids of 10.000 and above. We will edit the posixAccount.xml template that phpLDAPadmin provides for posix account creation. Specifically we will override the value for the uidNumber attribute:

        UID Number
        terminal.png
        6
        1
        1
<!--    <value>=php.GetNextNumber(/;uidNumber)</value> -->
        =php.GetNextNumber(/;uidNumber;;;;10000)

Neat trick 😉 …now we do the same thing for the gidNumber attribute in the posixGroup.xml template:

        GID Number
        2
        1
        1
        1
<!--    <value>=php.GetNextNumber(/;gidNumber)</value> -->
        =php.GetNextNumber(/;gidNumber;;;;10000)

Taking things for a spin

Last but not least we should check that we can do an ldap search from a remote host somewhere. We use the following command:

ldapsearch -x -b 'dc=home,dc=local' -h ldap.home.local -D 'cn=myuser,ou=users,dc=home,dc=local' -W

If things go to plan you are being prompted for the password of your user (“myuser” in the example above). The query should return something ending with these lines:

# search result
search: 2
result: 0 Success

The importing thing in the result above being the result code 0 Success.

Bonus: Change DN layout for new users

Right now phpLDAPadmin creates new users with a distinguished name that is driven by cn, however we might want users to become created driven by uid. Changing that requires us to go back to the posixAccount.xml template. There we need to do one more so phpLDAPadmin will create new users with a DN driven by uid:

<!-- <rdn>cn</rdn> -->
uid

Why do we do that? Consider this:

dn: cn=sample user,ou=users,dc=home,dc=local
objectClass: top
objectClass: inetOrgPerson
cn: sample user
uid: sampleuser

but on the other hand consider this:

dn: uid=sampleuser,ou=users,dc=home,dc=local
objectClass: top
objectClass: inetOrgPerson
cn: sample user
uid: sampleuser

Even though the attributes are identical, the DN is the primary key and the entries given above, are two complete separate entries with two different DNs. Now if we want to login via uid later on, rather than cn, we need that fix.