Engineering and technology notes

OpenLDAP Password Policy overlay (ppolicy)

OpenLDAP has a dynamically loadable module which can enforce password policies. It allows to define policies for the userPassword attribute. Policies can define the maximum login attempts with the wrong password, maximum age of a password and many more.

Here is a short introduction into this module. If you want to read about it in detail, see the link collection at the end of this page.

Note: The connection parameters and DN parameters deeply depend on your setup, the examples here need to be adjusted to your setup.

Configuration of the ppolicy overlay

The basic configuration depends on your OpenLDAP version. Newer versions store their configuration in a so-called Online Configuration Database (OLC), older ones use a configuration file called slapd.conf

OpenLDAP with OLC

  • Load the ppolicy schema into OLC: ldapmodify -D "cn=root,cn=config" -W -a -f /etc/openldap/schema/ppolicy.ldif
  • Load the module: ldapmodify -D "cn=root,cn=config" -W -a -f ppolicymodule.ldif
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModuleLoad: ppolicy.la
  • Configure ppolicy overlay: ldapmodify -D "cn=root,cn=config" -W -a -f ppolicyoverlay.ldif
dn: olcOverlay=ppolicy,olcDatabase={1}bdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=passwordDefault,ou=Policies,dc=mydomain,dc=tld
olcPPolicyHashCleartext: FALSE
olcPPolicyUseLockout: FALSE
olcPPolicyForwardUpdates: FALSE

OpenLDAP with slapd.conf

If you have an older version of OpenLDAP, the configuration goes into slapd.conf:

#-- Load schema
include         /etc/openldap/schema/ppolicy.schema

#-- Load module
moduleload ppolicy.la

The next snippet should come somewhere after the database definition:

#-- Load overlay
overlay ppolicy
ppolicy_default "cn=passwordDefault,ou=Policies,dc=mydomain,dc=tld"

This means the default policy is located under cn=passwordDefault,ou=Policies,dc=mydomain,dc=tld

Definition of a password policy

In the overlay configuration we specified the default policy, so we add it now using the following LDIF:

dn: ou=Policies,dc=mydomain,dc=tld
ou: Policies
objectClass: organizationalUnit

dn: cn=passwordDefault,ou=Policies,dc=mydomain,dc=tld
objectClass: pwdPolicy
objectClass: person
objectClass: top
cn: passwordDefault
sn: passwordDefault
pwdAttribute: userPassword
pwdCheckQuality: 0
pwdMinAge: 0
pwdMaxAge: 0
pwdMinLength: 8
pwdInHistory: 5
pwdMaxFailure: 3
pwdFailureCountInterval: 0
pwdLockout: TRUE
pwdLockoutDuration: 0
pwdAllowUserChange: TRUE
pwdExpireWarning: 0
pwdGraceAuthNLimit: 0
pwdMustChange: FALSE
pwdSafeModify: FALSE

All these parameters are described in detail at Chapter 6 OpenLDAP password policy overlay / pwdPolicy ObjectClass and Attributes.

This policy applies to all userPassword attributes. If an object needs a different policy, just define the differing policy under another name and reference the policy with the pwdPolicySubentry attribute. Example:

dn: cn=My User,ou=People,dc=mydomain,dc=tld
changetype: modify
add: pwdPolicySubentry
pwdPolicySubentry: cn=passwordSpecial,ou=Policies,dc=mydomain,dc=tld

Usage and behaviour

Query all locked accounts

If an object has the pwdAccountLockedTime attribute: it is locked since then. Simply issue the following query:
ldapsearch <MYCONNECTIONPARAMS> -b "ou=People,dc=mydomain,dc=tld" "pwdAccountLockedTime=*" pwdAccountLockedTime

Unlock an account

There are two variants. For the first one you simply delete the pwdAccountLockedTime attribute which unlocks the account immediately:

dn: cn=My User,ou=People,dc=mydomain,dc=tld
changetype: modify
delete: pwdAccountLockedTime

The second variant adds the attribute pwdReset which basically means: The user can only login again after changing it’s password:

dn: cn=My User,ou=People,dc=mydomain,dc=tld
changetype: modify
add: pwdReset
pwdReset: TRUE

If the user tries other operations than changing its password, the OpenLDAP server responds with bind: Operations are restricted to bind/unbind/abandon/StartTLS/modify password Changing an LDAP password can be done f.e. with the ldappasswd tool:

ldappasswd <MYCONNECTIONPARAMS> -D "cn=My User,ou=People,dc=mydomain,dc=tld" -W -S "cn=My User,ou=People,dc=mydomain,dc=tld"

Behaviour of some policy settings

A short overview of how some of the policies behave (not all covered here):

pwdMinAge

Result: Constraint violation (19)
Additional info: Password is too young to change

pwdMaxAge

ldap_bind: Invalid credentials (49)
in the logfile: ppolicy_bind: Entry cn=My User,ou=People,dc=mydomain,dc=tld has an expired password: 0 grace logins

pwdGraceAuthNLimit

in the log: ppolicy_bind: Entry cn=My User,ou=People,dc=mydomain,dc=tld has an expired password: 1 grace logins

pwdInHistory

Result: Constraint violation (19)
Additional info: Password is in history of old passwords

pwdAllowUserChange

Result: Insufficient access (50)
Additional info: User alteration of password is not allowed

Storage location of the policy data

Policy data (f.e. number of failed login attempts) is stored as Operational Attributes on each object. In a normal ldapsearch query operational attributes are not returned. To make them visible, add a “+” to the end of the query. Example: ldapsearch <MYCONNECTIONPARAMS> -b "ou=People,dc=mydomain,dc=tld" "+"

Considerations when using LDAP replication

If you replicate from an LDAP master to LDAP slave(s) and your users are authenticating against slaves, take into consideration that the policy data needs to be synced somehow back to the master (f.e. number of failed login attempts).

The ppolicy module already knows about it. You basically need to set the
configuration value olcPPolicyForwardUpdates (OLC style) / ppolicy_forward_updates (slapd.conf). Furthermore chaining must be configured, including syncrepl. This is very well documented at Linuxtopia.

Source: OpenLDAP Password Policy overlay (ppolicy)

Add new schema to OpenLDAP

Hello ! In this post, I will explain how to add a new schema into OpenLDAP 2.4 and higher. Why ? Because since release 2.4, the structure of the server has a little changed. I’m not an LDAP expert but I’m writing this article because I insulted my OpenLDAP and my Linux several times during one week while I try to add my own schema into OpenLDAP 2.4. I have read a lot of posts but honestly, I never find a good “how-to” which respond to the question in this post’s title.

The configuration in OpenLDAP 2.4 and next versions is now in LDIF format and it follows a pretty logical schema like this :

 config_dit

We can look that schemas must be placed as child of cn=schema,cn=config. Before the release 2.4, all .schema (stored under /etc/ldap/schema/) were included into slapd.conf. Since 2.4, we must “forget” the .schema file. The best way to explain how to add new schema with 2.4 (and higher) release is to start with a real and practical example. I suppose you already have a OpenLDAP server  running. For your information, my OpenLDAP runs on a Ubuntu Server 12.04 LTS with a 3.5.0-48 64 bits kernel.

root@ldapserver:~# lsb_release -a && uname -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.4 LTS
Release:        12.04
Codename:       precise
Linux ldapserver 3.5.0-48-generic #72~precise1-Ubuntu SMP Tue Mar 11 20:09:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
 THE PREPARATION

For this example, we can imagine that we want to add a new schema with a custom objectClass for our business application. This new objectClass has the name of nsaEngineer and the schema nsaProject. As a reminder, a schema is a container (package) for one or many objectClass. An objectClass contains references to other objectClass and attributes. Now, the objectClass nsaEngineer has 3 customs mandatory attributes and a optional (description) which is referenced in another base schema.

  • mainDoorKey (mandatory)
  • safeKey (mandatory)
  • nsaID (mandatory)
  • description (optional)

Now, let’s go to create this schema (and objectClass and attributes). Note : for more information about LDAP structures, please consult the following link : LDAP structure

CREATION OF CLASSIC .SCHEMA

The .schema format is simple to understand and to write for the beginners. Let’s start by creating a working directory for example /tmp/ldapworkingdir.

root@ldapserver:~# mkdir /tmp/ldapworkingdir

 Now, create the file nsaProject.schema which contains the definition of the new and custom attributes and the new objectClass nsaEngineer and save it in /etc/ldap/schema/. I will not explain in detail the content of nsaProject.schema because it is out of the scope for this post.

Convert and add the schema to OpenLDAP

Now it’s time to try to convert our .schema into an LDIF file and add it to OpenLDAP. To begin, create a dummy file into /tmp/ldapworkingdir called ldap.conf for example and write into it the include directive to the nsaProject.schema.

root@ldapserver:~# cd /tmp/ldapworkingdir/
root@ldapserver:/tmp/ldapworkingdir# touch ldap.conf
root@ldapserver:/tmp/ldapworkingdir# echo "include /etc/ldap/schema/nsaProject.schema" > ldap.conf

 Now try to convert the .schema file with this command

root@ldapserver:/tmp/ldapworkingdir# slaptest -f ldap.conf -F .
config file testing succeeded

 This will create in place a directory called cn=config and a file cn=config.ldif. Now go to new created sub-directory ./cn=config/cn/schema/ and edit the file cn={0}nsaProject

root@ldapserver:/tmp/ldapworkingdir# cd cn\=config/cn\=schema/

 The file must contains the following:

# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
# CRC32 50a9d844
dn: cn={0}nsaproject
objectClass: olcSchemaConfig
cn: {0}nsaproject
olcAttributeTypes: {0}( 2.25.896523589646542389.1 NAME 'mainDoorKey' SUP descr
 iption EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VA
 LUE )
olcAttributeTypes: {1}( 2.25.896523589646542389.2 NAME 'safeKey' SUP descripti
 on EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VALUE
 )
olcAttributeTypes: {2}( 2.25.896523589646542389.3 NAME 'nsaID' SUP description
  EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VALUE )
olcObjectClasses: {0}( 2.25.896523589646542389.10 NAME 'nsaEngineer' STRUCTURA
 L MUST ( mainDoorKey $ safeKey $ nsaID ) MAY description )
structuralObjectClass: olcSchemaConfig
entryUUID: 51ee4aea-79c9-1033-958d-ef361bf34673
creatorsName: cn=config
createTimestamp: 20140527090205Z
entryCSN: 20140527090205.718989Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20140527090205Z

 You must keep only the following things and delete the rest.

  • dn: cn={0}nsaproject
  • objectClass: olcSchemaConfig
  • cn: {0}nsaproject
  • olcAttributeTypes:
  • olcObjectClasses:

You must modify dn: and cn:  (just remove {0} for cn but write the correct dn for the schema ! (dn:cn=nsaproject,cn=schema,cn=config) ). After these modifications, the file is like this:

dn: cn=nsaproject,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: nsaproject

olcAttributeTypes: {0}( 2.25.896523589646542389.1 NAME 'mainDoorKey' SUP descr
 iption EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VA
 LUE )

olcAttributeTypes: {1}( 2.25.896523589646542389.2 NAME 'safeKey' SUP descripti
 on EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VALUE
 )

olcAttributeTypes: {2}( 2.25.896523589646542389.3 NAME 'nsaID' SUP description
  EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 SINGLE-VALUE )

olcObjectClasses: {0}( 2.25.896523589646542389.10 NAME 'nsaEngineer' STRUCTURA
 L MUST ( mainDoorKey $ safeKey $ nsaID ) MAY description )

 That’s it ! Now we are ready to add this schema to the OpenLDAP server using this command

root@ldapserver:/tmp/ldapworkingdir/cn=config/cn=schema#  ldapadd -Q -Y EXTERNAL -H ldapi:/// -W -f /tmp/ldapworkingdir/cn\=config/cn\=schema/cn\=\{0\}nsaproject.ldif
Enter LDAP Password:
adding new entry "cn=nsaproject,cn=schema,cn=config"

 Now you can verify if the new schema is correctly added using a ldapsearch command like this :

root@ldapserver: ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config nsa*
dn: cn=config
dn: cn=module{0},cn=config
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: cn={4}nsaproject,cn=schema,cn=config     #yeah :-)
dn: olcBackend={0}hdb,cn=config
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}hdb,cn=conf

Vladimir Horowitz

Vladimir Samoylovich Horowitz (/ˈhɒrəvɪts/; Russian: Владимир Самойлович Горовиц; Yiddish: וולאדימיר סאַמוילאָוויטש האָראָוויץ‎; October 1 [O.S. September 18] 1903 – November 5, 1989) was a Russian-born American classical pianist and composer, who lived most of his life in the United States. He was acclaimed for his virtuoso technique, his tone color, and the excitement that was engendered by his playing. He is widely regarded as one of the greatest pianists of all time.

https://en.m.wikipedia.org/wiki/Vladimir_Horowitz

How To Install and Configure OpenLDAP and phpLDAPadmin on an Ubuntu 14.04 Server | DigitalOcean

Install phpLDAPadmin to Manage LDAP with a Web Interface

Although it is very possible to administer LDAP through the command line, most users will find it easier to use a web interface. We’re going to install phpLDAPadmin, which provides this functionality, to help remove some of the friction of learning the LDAP tools.

The Ubuntu repositories contain the phpLDAPadmin package. You can install it by typing:

sudo apt-get install phpldapadmin

This should install the administration interface, enable the necessary Apache virtual hosts files, and reload Apache.

The web server is now configured to serve your application, but we will make some additional changes. We need to configure phpLDAPadmin to use the domain schema we configured for LDAP, and we are also going to make some adjustments to secure our configuration a little bit.

Configure phpLDAPadmin

Now that the package is installed, we need to configure a few things so that it can connect with the LDAP directory structure that was created during the OpenLDAP configuration stage.

Begin by opening the main configuration file with root privileges in your text editor:

sudo nano /etc/phpldapadmin/config.php

In this file, we need to add the configuration details that we set up for our LDAP server. Start by looking for the host parameter and setting it to your server’s domain name or public IP address. This parameter should reflect the way you plan on accessing the web interface:

$servers->setValue('server','host','server_domain_name_or_IP');

Next up, you’ll need to configure the domain name you selected for your LDAP server. Remember, in our example we selected test.com. We need to translate this into LDAP syntax by replacing each domain component (everything not a dot) into the value of a dc specification.

All this means is that instead of writing test.com, we will write something like dc=test,dc=com. We should find the parameter that sets the server base parameter and use the format we just discussed to reference the domain we decided on:

$servers->setValue('server','base',array('dc=test,dc=com'));

We need to adjust this same thing in our login bind_id parameter. The cn parameter is already set as “admin”. This is correct. We just need to adjust the dc portions again, just as we did above:

$servers->setValue('login','bind_id','cn=admin,dc=test,dc=com');

The last thing that we need to adjust is a setting that control the visibility of warning messages. By default phpLDAPadmin will throw quite a few annoying warning messages in its web interface about the template files that have no impact on the functionality.

We can hide these by searching for the hide_template_warning parameter, uncommenting the line that contains it, and setting it to “true”:

$config->custom->appearance['hide_template_warning'] = true;

This is the last thing that we need to adjust. You can save and close the file when you are finished.

Create a Password Authentication File

We also want to password protect our phpLDAPadmin location. Even though phpLDAPadmin has password authentication, this will provide an extra level of protection.

The utility that we need is contained in an Apache utility package. Get it by typing:

sudo apt-get install apache2-utils

Now that you have the utility available, you can create a password file that will contain a username that you choose and the associated hashed password.

We will keep this in the /etc/apache2 directory. Create the file and specify the username you want to use by typing:

sudo htpasswd -c /etc/apache2/htpasswd demo_user

Now, we are ready to modify Apache to take advantage of our security upgrades.

Secure Apache

The first thing we should do is enable the SSL module in Apache. We can do this by typing:

sudo a2enmod ssl

This will enable the module, allowing us to use it. We still need to configure Apache to take advantage of this though.

Currently, Apache is reading a file called 000-default.conf for regular, unencrypted HTTP connections. We need to tell it to redirect requests for our phpLDAPadmin interface to our HTTPS interface so that the connection is encrypted.

When we redirect traffic to use our SSL certificates, we’ll also implement the password file to authenticate users. While we’re modifying things, we’ll also change the location of the phpLDAPadmin interface itself to minimize targeted attacks.

Modify the phpLDAPadmin Apache Configuration

The first thing we will do is modify the alias that is set up to serve our phpLDAPadmin files.

Open the file with root privileges in your text editor:

sudo nano /etc/phpldapadmin/apache.conf

This is the place where we need to decide on the URL location where we want to access our interface. The default is /phpldapadmin, but we want to change this to cut down on random login attempts by bots and malicious parties.

For this guide, we’re going to use the location /superldap, but you should choose your own value.

We need to modify the line that specifies the Alias. This should be in an IfModule mod_alias.c block. When you are finished, it should look like this:

<IfModule mod_alias.c>
    Alias /superldap /usr/share/phpldapadmin/htdocs
</IfModule>

When you are finished, safe and close the file.

Configure the HTTP Virtual Host

Next, we need to modify our current Virtual Hosts file. Open it with root privileges in your editor:

sudo nano /etc/apache2/sites-enabled/000-default.conf

Inside, you’ll see a rather bare configuration file that looks like this:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

We want to add information about our domain name or IP address to define our server name and we want to set up our redirect to point all HTTP requests to the HTTPS interface. This will match the alias we configured in the last section.

The changes we discussed will end up looking like this. Modify the items in red with your own values:

<VirtualHost *:80>
    ServerAdmin webmaster@server_domain_or_IP
    DocumentRoot /var/www/html
    ServerName server_domain_or_IP
    Redirect permanent /superldap https://server_domain_or_IP/superldap
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Save and close the file when you are finished.

Source: How To Install and Configure OpenLDAP and phpLDAPadmin on an Ubuntu 14.04 Server | DigitalOcean

What are CSS Modules and why do we need them?

What does this look like and why do it? We’ll get to that in a sec. First, remember how HTML and CSS normally work. A class is applied in HTML:

<h1 class="title">An example heading</h1>

And that class is styled in CSS:

.title {
  background-color: red;
}

As long as that CSS is applied to the HTML document, the background of that <h1> would be red. We don’t need to process the CSS or the HTML. The browser understands both those file formats.

Source: What are CSS Modules and why do we need them? | CSS-Tricks