Implement OpenLDAP Password Policies

|
Last Updated:
|
|

In this guide, we are going to learn how to implement OpenLDAP password policies. In OpenLDAP, password policies are implemented through the use of Password Policy (ppolicy) Overlay.

Implementing OpenLDAP Password Policies

PPolicy Control Mechanisms

ppolicy overlay provides a variety of password control mechanisms including;

  • Password aging — both minimum and maximum ages
  • Password quality
  • Automatic account locking
  • Password reuse and duplication control
  • Account time-outs
  • Mandatory password resets
  • Acceptable password content
  • Grace logins to allow the use of expired passwords for a specific time period after the expiry date.

Read more about ppolicy overlay on man slapo-ppolicy.

Load Password Policy Module

In order to implement the password policies, you need to ensure that the, ppolicy.la module is loaded onto LDAP database. To list loaded modules, run the command;

slapcat -n 0 | grep -i module

In our current LDAP setup, no password policy module, ppolicy.la, is loaded. See the output of the command above;


dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/libexec/openldap
olcModuleLoad: {0}back_mdb.la
olcModuleLoad: {1}memberof.la
olcModuleLoad: {2}refint.la
structuralObjectClass: olcModuleList
olcAttributeTypes: {15}( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' DESC 
 'Loadable module that instantiates "check_password() function' EQUALITY cas
 op AUXILIARY MAY pwdCheckModule )

Therefore, to load the module, you can simply create an LDIF file as shown below to define how to add the password policy module to slapd.

Note that in our setup, the modules are located under the path, /usr/libexec/openldap as defined by the olcModulePath attribute.

vim load-ppolicy-mod.ldif

dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: ppolicy.la

Load the module in to LDAP database.

ldapadd -Y EXTERNAL -H ldapi:/// -f load-ppolicy-mod.ldif

After loading the module, if you list the slapd modules again, you should get an output similar to the below (It might be different for your case);

slapcat -n 0 | grep -i module

dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/libexec/openldap
olcModuleLoad: {0}back_mdb.la
olcModuleLoad: {1}memberof.la
olcModuleLoad: {2}refint.la
olcModuleLoad: {3}ppolicy.la
structuralObjectClass: olcModuleList

Create Password Policies OU Container

Create an LDAP OU container that will be used to store the default password policies.

vi pwpolicy-ou.ldif

dn: ou=pwpolicy,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: organizationalUnit
objectClass: top
ou: pwpolicy
ldapadd -Y EXTERNAL -H ldapi:/// -f pwpolicy-ou.ldif

Create OpenLDAP Password Policy Overlay DN

Once you have loaded the ppolicy module into slapd database, proceed to add the LDAP password policy Overlay DN.

Add the password policy overlay into your respective LDAP database backend, which in this setup is mdb.

ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b  cn=config olcDatabase | grep mdb

See the highlighted line in the output below;

dn: olcDatabase={1}mdb,cn=config
olcDatabase: {1}mdb
dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config

Create an LDIF file with the content below for adding the ppolicy Overlay DN along with the configuration options into slapd. Replace the domain components accordingly.

vi pwpolicyoverlay.ldif
dn: olcOverlay=ppolicy,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=default,ou=pwpolicy,dc=ldapmaster,dc=kifarunix-demo,dc=com
olcPPolicyHashCleartext: TRUE

Read more about the configuration options applied to the ppolicy overlay above on man slapo-ppolicy.

Update the database.

ldapadd -Y EXTERNAL -H ldapi:/// -f pwpolicyoverlay.ldif

Create OpenLDAP Password Policies

You are now ready to create your LDAP password policies under your default password policies ou created above, cn=default,ou=pwpolicy,dc=ldapmaster,dc=kifarunix-demo,dc=com.

The ppolicy overlay depends on the pwdPolicy object class and thus when defining the policies, you can use any of the attributes described under the ObjectClass attributes section of man slapo-ppolicy.


cat > ldap-pwpolicies.ldif << 'EOL'
dn: cn=default,ou=pwpolicy,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: person
objectClass: pwdPolicyChecker
objectClass: pwdPolicy
cn: pwpolicy
sn: pwpolicy
pwdAttribute: userPassword
pwdMinAge: 0
pwdMaxAge: 5184000
pwdInHistory: 5
pwdCheckQuality: 2
pwdMinLength: 12
pwdExpireWarning: 432000
pwdGraceAuthNLimit: 5
pwdLockout: TRUE
pwdLockoutDuration: 0
pwdMaxFailure: 3
pwdFailureCountInterval: 0
pwdReset: TRUE
pwdMustChange: TRUE
pwdAllowUserChange: TRUE
pwdSafeModify: FALSE
EOL

For a good explanation of the password attributes used above, consult, man slapo-ppolicy. For a description of object classes used consult, Object Classes and Attributes.

Update the Password policies on the slapd.

ldapadd -Y EXTERNAL -H ldapi:/// -f ldap-pwpolicies.ldif

Testing Password Policies

To test the effectiveness of the implemented OpenLDAP password policies, we will try to change the password of one of the existing OpenLDAP users in our environment.

Some of the checks we implemented above include;

  • pwdInHistory: stores 5 previously used passwords in the database to avoid re-use.
  • pwdCheckQuality: Set to value to 2. The server will check the syntax of the password and if the server is unable to check the syntax it will return an error refusing the password.
  • pwdMinLength: Sets the minimum number of characters that will be accepted in a password to 12.

Reset User's Password as OpenLDAP RootDN Administrator

Note that the rootDN, which is typically the LDAP administrator, is granted full access and permissions to the entire LDAP directory, including the ability to bypass password policies. This is to ensure that the LDAP administrator can always access and manage the directory, even if there are password policy restrictions in place for regular users. This means that the rootDN administrator can set any password for any user, regardless of the password policy rules defined for regular users. They are not subject to password complexity requirements, expiration rules, or other password policy restrictions that apply to regular users.

Try setting a simple password;

ldappasswd -H ldapi:/// -Y EXTERNAL -S "uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com"

Since you are resetting/setting password as LDAP admin, any password can work;


New password: password
Re-enter new password: password
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0

From the logs, the result is success.


Jul 30 07:43:32 debian slapd[70873]: conn=1045 fd=17 ACCEPT from PATH=/usr/var/run/ldapi (PATH=/usr/var/run/ldapi)
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=0 BIND dn="" method=163
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=0 BIND authcid="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" authzid="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=0 BIND dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" mech=EXTERNAL bind_ssf=0 ssf=71
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=0 RESULT tag=97 err=0 qtime=0.000016 etime=0.000246 text=
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=1 EXT oid=1.3.6.1.4.1.4203.1.11.1
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=1 PASSMOD id="uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com" new
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=1 RESULT oid= err=0 qtime=0.000015 etime=0.005999 text=
Jul 30 07:43:32 debian slapd[70873]: conn=1045 op=2 UNBIND
Jul 30 07:43:32 debian slapd[70873]: conn=1045 fd=17 closed

Reset User's Password as Non Admin User

Next, try to test the OpenLDAP password polices complexity enforcement by setting/resetting the password as non admin OpenLDAP user. Simply just login to a system even try to reset your own user password.

In my Debian 12 server, i have configure SSSD OpenLDAP authenticaiton;

Configure SSSD for OpenLDAP Client Authentication on Debian 12/11/10/9

Thus, let me try to login to my Debian 12 server as an OpenLDAP user;

ssh [email protected]

Using simple password (The password fails the dictionary check - it is based on a dictionary word);


The authenticity of host '192.168.56.103 (192.168.56.103)' can't be established.
ED25519 key fingerprint is SHA256:fwedLDZSVOjpS4vf9coDc9Fw39cbpMiy4ZdCYf5xguY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.56.103' (ED25519) to the list of known hosts.
[email protected]'s password: 
Password expired. Change your password now.
Password expired. Change your password now.
Creating directory '/home/johndoe'.
Linux bookworm12 6.1.0-10-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.37-1 (2023-07-03) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Jul 30 07:57:51 2023 from 192.168.56.103
WARNING: Your password has expired.
You must change your password now and login again!
Current Password: 
New password: 
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
New password: 
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
New password: 
Retype new password: 
Password change failed. Server message: Password fails quality checking policy
passwd: Authentication token is no longer valid; new one required
passwd: password unchanged
Connection to 192.168.56.103 closed.

Re-using the existing password (The password is the same as the old one);


[email protected]'s password: 
Password expired. Change your password now.
Password expired. Change your password now.
Linux bookworm12 6.1.0-10-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.37-1 (2023-07-03) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Jul 30 08:02:37 2023 from 192.168.56.103
WARNING: Your password has expired.
You must change your password now and login again!
Current Password: 
New password: 
BAD PASSWORD: The password is the same as the old one
New password: 
BAD PASSWORD: The password is the same as the old one
New password: 
BAD PASSWORD: The password is the same as the old one
passwd: Have exhausted maximum number of retries for service
passwd: password unchanged
Connection to 192.168.56.103 closed.

One thing that I noticed while testing on whether the user will be prompted to reset their password on first time login is that, despite having set the, pwdMustChange: TRUE attribute, unless you add the attribute, pwdReset: TRUE on the user entry, this will not work.

So if you want the user to be prompted to reset their passwords on first time login, simply edit the user entry and add the pwdReset: TRUE.

For example, if I want the user, june, in my LDAP db to be prompted to reset the password, I would simply edit and update its entry as follows;

vim mod-john.ldif
dn: uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com
changetype: modify
add: pwdReset
pwdReset: TRUE
ldapmodify -Y EXTERNAL -H ldapi:/// -f mod-june.ldif

If you are logging to a system you had already logged in using your OpenLDAP account, and using SSSD for authentication, clear the cache;

sss_cache -E
systemctl stop sssd;rm -rf /var/lib/sss/db/*;systemctl restart sssd

The login;

ssh -l johndoe localhost

Let's set the password that matches the complexity, (sTr0nGW@123.).


The authenticity of host 'localhost (::1)' can't be established.
ED25519 key fingerprint is SHA256:fwedLDZSVOjpS4vf9coDc9Fw39cbpMiy4ZdCYf5xguY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
johndoe@localhost's password: 
Password expired. Change your password now.
Password expired. Change your password now.
Linux bookworm12 6.1.0-10-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.37-1 (2023-07-03) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Jul 30 08:16:04 2023 from ::1
WARNING: Your password has expired.
You must change your password now and login again!
Current Password: 
New password: sTr0nGW@123.
Retype new password: sTr0nGW@123.
passwd: password updated successfully
Connection to localhost closed.

Read more about OpenLDAP password policies on Administrator's Guide: Overlays.

Enforcing Password Complexity Policy

Well, as you can see, as the policies provided, are working as expected.

As a further example, you can try to perform multiple failed logins (As per this, the account will lock after third failed attempt);

pwdLockout: TRUE
pwdLockoutDuration: 0
pwdMaxFailure: 3
ssh johndoe@locahost

After a number of failed attempts (3>), then your account locks. You can check the password failure time and lock time.

ldapsearch -Y EXTERNAL -H ldapi:/// \
-b "uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com" "(pwdAccountLockedTime=*)" \
pwdFailureTime pwdFailureCount pwdAccountLockedTime -QQ -LL

version: 1

dn: uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com
pwdFailureTime: 20230730193044.652730Z
pwdFailureTime: 20230730193049.144979Z
pwdFailureTime: 20230730193100.668744Z
pwdAccountLockedTime: 20230730193100Z

To list all accounts whose accounts have been locked;

ldapsearch -Y EXTERNAL -H ldapi:/// \
-b "dc=ldapmaster,dc=kifarunix-demo,dc=com" "(pwdAccountLockedTime=*)" dn -QQ -LLL

Sample output;

dn: uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com

If you want to unlock a locked account, then you need to delete the pwdAccountLockedTime attribute from the user's entry.

For example, to unlock johndoe's account, create an LDIF file on the OpenLDAP server;

vim unlock_user.ldif

Replace the DN of the user accordingly.


dn: uid=johndoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com
changetype: modify
delete: pwdAccountLockedTime

The update the database to remove the entry;

ldapmodify -Y external -H ldapi:/// -f unlock_user.ldif

You should now be able to login to the account with correct credentials;

Configure SSSD for OpenLDAP Authentication on CentOS 8

How to Create OpenLDAP Member Groups

Configure SSSD for OpenLDAP Client Authentication on Debian 10/9

How to Configure SUDO via OpenLDAP Server

SUPPORT US VIA A VIRTUAL CUP OF COFFEE

We're passionate about sharing our knowledge and experiences with you through our blog. If you appreciate our efforts, consider buying us a virtual coffee. Your support keeps us motivated and enables us to continually improve, ensuring that we can provide you with the best content possible. Thank you for being a coffee-fueled champion of our work!

Photo of author
koromicha
I am the Co-founder of Kifarunix.com, Linux and the whole FOSS enthusiast, Linux System Admin and a Blue Teamer who loves to share technological tips and hacks with others as a way of sharing knowledge as: "In vain have you acquired knowledge if you have not imparted it to others".

Leave a Comment