=== Configure OpenLDAP Password Expiry Email Notification === This tutorial will provide some basics steps to take to configure OpenLDAP to send out notifications via email to users mailbox informing them about the password expiration also system admins. The Script can be found at [https://github.com/ltb-project/ldap-scripts here] {{{ grep -Ev "^\s[#\;]|^\s$|^#" checkLdapPwdExpiration.sh }}} {{{ MY_LDAP_HOSTURI="ldapi:///" MY_LDAP_DEFAULTPWDPOLICYDN="cn=default,ou=pwpolicy,dc=ldapmaster,dc=kifarunix-demo,dc=com" MY_LDAP_SEARCHBASE="ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com" MY_LDAP_SEARCHFILTER="(&(uid=*)(objectClass=inetOrgPerson))" MY_LDAP_SEARCHSCOPE="one" MY_LDAP_SEARCHBIN="/usr/bin/ldapsearch" MY_LDAP_NAME_ATTR=cn MY_LDAP_LOGIN_ATTR=uid MY_LDAP_MAIL_ATTR=mail export LC_ALL=en_US.UTF-8 MY_MAIL_BODY="Hi %name,\n\n \ Your password will expire in %expireDays days on %expireTimeTZ.\n\n \ Visit Kifarunix-demo Self Service Password site, https://ldap-ssp.kifarunix-demo.com to reset your password.\n\n \ As a reminder, ensure that your password conforms to the company outlined password policies.\n\n \ Kifarunix-demo IT team,\n Regards." EX_MAIL_BODY="Hi %name,\n\n \ Your password expired on %expireTimeTZ.\n\n \ Kindly contact Kifarunix-demo IT team to help reset the password.\n\n \ Kifarunix-demo IT team,\n Regards." MY_MAIL_SUBJECT="LDAP Account Password Expiry Status" MY_MAIL_BIN="mail" MY_LOG_HEADER="`date +\"%b %e,%Y %T\"`" MY_GAWK_BIN="/usr/bin/gawk" getTimeInSeconds() { date=0 os=`uname -s` if [ "$1" ]; then date=`${MY_GAWK_BIN} 'BEGIN { \ if (ARGC == 2) { \ print mktime(ARGV[1]) \ } \ exit 0 }' "$1"` else if [ "${os}" = "SunOS" ]; then date=`/usr/bin/truss /usr/bin/date 2>&1 | nawk -F= \ '/^time\(\)/ {gsub(/ /,"",$2);print $2}'` else now=`date +"%Y %m %d %H %M %S" -u` date=`getTimeInSeconds "$now"` fi fi echo ${date} } tmp_dir="/tmp/$$.checkldap.tmp" result_file="${tmp_dir}/res.tmp.1" buffer_file="${tmp_dir}/buf.tmp.1" tmp_dir_stats="/tmp/ldap-password-stats" ldap_param="-Y EXTERNAL -H ${MY_LDAP_HOSTURI} -LLL -Q" nb_users=0 nb_expired_users=0 nb_warning_users=0 if [ -d ${tmp_dir} ]; then echo "Error : temporary directory exists (${tmp_dir})" exit 1 fi mkdir ${tmp_dir} if [ ${MY_LDAP_ROOTDN} ]; then ldap_param="${ldap_param} -D ${MY_LDAP_ROOTDN} -w ${MY_LDAP_ROOTPW}" fi ${MY_LDAP_SEARCHBIN} ${ldap_param} -s ${MY_LDAP_SEARCHSCOPE} \ -b "${MY_LDAP_SEARCHBASE}" "${MY_LDAP_SEARCHFILTER}" \ "dn" > ${result_file} while read dnStr do if [ ! "${dnStr}" ]; then continue fi dn=`echo ${dnStr} | cut -d : -f 2` nb_users=`expr ${nb_users} + 1` ${MY_LDAP_SEARCHBIN} ${ldap_param} -s base -b "${dn}" \ ${MY_LDAP_NAME_ATTR} ${MY_LDAP_LOGIN_ATTR} ${MY_LDAP_MAIL_ATTR} pwdChangedTime pwdPolicySubentry \ > ${buffer_file} login=`grep -w "${MY_LDAP_LOGIN_ATTR}:" ${buffer_file} | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` name=`grep -w "${MY_LDAP_NAME_ATTR}:" ${buffer_file} | cut -d : -f 2\ | sed "s/^ *//;s/ *$//"` mail=`grep -w "${MY_LDAP_MAIL_ATTR}:" ${buffer_file} | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` pwdChangedTime=`grep -w "pwdChangedTime:" ${buffer_file} \ | cut -d : -f 2 | cut -c 1-15 | sed "s/^ *//;s/ *$//"` pwdPolicySubentry=`grep -w "pwdPolicySubentry:" ${buffer_file} \ | cut -d : -f 2 | sed "s/^ *//;s/ *$//"` if [ ! "${pwdChangedTime}" ]; then echo "No password change date for ${login} (${mail})" >> ${tmp_dir_stats} continue fi if [ ! "${pwdPolicySubentry}" -a ! "${MY_LDAP_DEFAULTPWDPOLICYDN}" ]; then echo "No password policy for ${login} (${mail})" >> ${tmp_dir_stats} continue fi ldap_search="${MY_LDAP_SEARCHBIN} ${ldap_param} -s base" if [ "${pwdPolicySubentry}" ]; then ldap_search="${ldap_search} -b ${pwdPolicySubentry}" else ldap_search="${ldap_search} -b ${MY_LDAP_DEFAULTPWDPOLICYDN}" fi ldap_search="$ldap_search pwdMaxAge pwdExpireWarning pwdMinLength pwdInHistory" pwdMaxAge=`${ldap_search} | grep -w "pwdMaxAge:" | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` pwdExpireWarning=`${ldap_search} | grep -w "pwdExpireWarning:" | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` pwdMinLength=`${ldap_search} | grep -w "pwdMinLength:" | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` pwdInHistory=`${ldap_search} | grep -w "pwdInHistory:" | cut -d : -f 2 \ | sed "s/^ *//;s/ *$//"` if [ ! "${pwdMaxAge}" ]; then echo "No password expiration configured for ${login} (${mail})" >> ${tmp_dir_stats} continue fi MY_MAIL_DELAY=${MY_MAIL_DELAY:=$pwdExpireWarning} if [ "${pwdChangedTime}" ]; then s=`echo ${pwdChangedTime} | cut -c 13-14` m=`echo ${pwdChangedTime} | cut -c 11-12` h=`echo ${pwdChangedTime} | cut -c 9-10` d=`echo ${pwdChangedTime} | cut -c 7-8` M=`echo ${pwdChangedTime} | cut -c 5-6` y=`echo ${pwdChangedTime} | cut -c 1-4` currentTime=`getTimeInSeconds` pwdChangedTime=`getTimeInSeconds "$y $M $d $h $m $s"` diffTime=`expr ${currentTime} - ${pwdChangedTime}` fi expireTime=`expr ${pwdChangedTime} + ${pwdMaxAge}` if [ ${currentTime} -gt ${expireTime} ]; then nb_expired_users=`expr ${nb_expired_users} + 1` expireTime=`date -d @$expireTime "+%A %d, %B %Y at %T"` logmsg="${EX_MAIL_BODY}" logmsg=`echo -e ${logmsg} | sed "s/%name/${name}/; \ s/%login/${login}/; s/%expireTimeTZ/${expireTime}/; s/%pwdMinLength/${pwdMinLength}/; s/%pwdInHistory/${pwdInHistory}/; \ s/%expireDays/${expireDays}/"` echo "${logmsg}" | ${MY_MAIL_BIN} -s "${MY_MAIL_SUBJECT}" ${mail} >&2 echo "Password expired for ${login} on ${expireTime}. Mail sent to ${mail}" >> ${tmp_dir_stats} continue fi expireTimeTZ=`date -d @$expireTime "+%A %d, %B %Y at %T"` expireTimeMail=`date -d @$expireTime "+%s"` now=`date +%s` expireDays=`echo $(( (${expireTimeMail} - ${now} )/(60*60*24) ))` if [ "${mail}" -a "${name}" \ -a "${login}" -a "${diffTime}" -a "${pwdMaxAge}" ] then diffTime=`expr ${diffTime} + ${MY_MAIL_DELAY}` if [ ${diffTime} -gt ${pwdMaxAge} ]; then logmsg="${MY_MAIL_BODY}" logmsg=`echo -e ${logmsg} | sed "s/%name/${name}/; \ s/%login/${login}/; s/%expireTimeTZ/${expireTimeTZ}/; s/%pwdMinLength/${pwdMinLength}/; s/%pwdInHistory/${pwdInHistory}/; \ s/%expireDays/${expireDays}/"` echo "${logmsg}" | ${MY_MAIL_BIN} -s "${MY_MAIL_SUBJECT}" ${mail} >&2 echo "Password warning for ${login} (expiry date, ${expireTimeTZ}). Mail sent to ${mail}" >> ${tmp_dir_stats} nb_warning_users=`expr ${nb_warning_users} + 1` fi fi done < ${result_file} sed -i "1iHello Admin,\nFind the LDAP users account password expiry status as at ${MY_LOG_HEADER}.\n" ${tmp_dir_stats} echo "Total User Accounts checked: ${nb_users}" >> ${tmp_dir_stats} echo "Accounts with Expired Passwords: ${nb_expired_users}" >> ${tmp_dir_stats} echo "Accounts with Passwords in Warning state: ${nb_warning_users}" >> ${tmp_dir_stats} sed -i -e '/^Total.*/i\\ ' -e '/^Total.*/i ===== Statistics =====' ${tmp_dir_stats} mail -s "LDAP Password Expiration Status" kifaunix@gmail.com < ${tmp_dir_stats} rm -rf ${tmp_dir} rm -rf ${tmp_dir_stats} exit 0 }}} '''The Script Requirements''' As outlined on the LTB page, the script requires; - gawk (GNU awk) (which gawk) - ldapsearch (which ldapsearch) - mailx (provides mail command, which mailx) - date (which date) which utility enables you to check if the command is installed and the full path to its location. '''The Script Variables''' Also, update the following variables on the script accordingly. - MY_LDAP_HOSTURI: LDAP URI - MY_LDAP_ROOTDN (optional): DN to use to bind. No DN means anonymous - MY_LDAP_ROOTPW: Password - MY_LDAP_DEFAULTPWDPOLICYDN: Default password policy DN. Do not set if no default policy is used. In this case, the script will only affect users with password policy in their entry (pwdPolicySubentry) - MY_LDAP_SEARCHBASE: Users search base - MY_LDAP_SEARCHFILTER: Users search filter - MY_LDAP_SEARCHBIN: Path to ldapsearch binary - MY_MAIL_DELAY: Time before expiration where a mail is sent. No mail sent after expiration. If no value, the script will take the pwdExpireWarning of the password policy - MY_LDAP_NAME_ATTR: attribute containing user’s name - MY_LDAP_LOGIN_ATTR: attribute containing user’s login - MY_LDAP_MAIL_ATTR:attribute containing user’s name - MY_MAIL_BODY: message body - MY_MAIL_SUBJECT: message subject - MY_MAIL_BIN: mail binary - MY_LOG_HEADER: log header - MY_GAWK_BIN: path to gawk binary '''Sample LDAP User entry''' Below is our sample OpenLDAP user entry. Note the following attributes; - MY_LDAP_NAME_ATTR=cn - MY_LDAP_LOGIN_ATTR=uid - MY_LDAP_MAIL_ATTR=mail {{{ ldapsearch -Y EXTERNAL -H ldapi:/// -s one -b "ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com" -LLL -Q uid=janedoe }}} {{{ dn: uid=janedoe,ou=people,dc=ldapmaster,dc=kifarunix-demo,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: extensibleObject uid: janedoe cn: Jane sn: Doe loginShell: /bin/bash uidNumber: 10010 gidNumber: 10010 homeDirectory: /home/janedoe shadowMax: 60 shadowMin: 1 shadowWarning: 7 shadowInactive: 7 shadowLastChange: 0 userPassword:: e1NTSEF9dmczUGpBa0EybUtOanJ4QWc1dWN5d20wNnlmOGg4cE8= mail: janedoe@kifarunix-demo.com }}} '''Testing the LDAP Password Expiration Notification Script''' To check the script can get us what is expected of it, simply execute it on the LDAP server as follows; {{{ bash checkLdapPwdExpiration.sh }}} Our script writes output to, /tmp/ldap-password-stats, file. {{{ cat /tmp/ldap-password-stats }}} {{{ Hello Admin, Find the LDAP users account password expiry status as Jun 13,2020 21:19:18. Password warning for janedoe (expiry date, Thursday 18, June 2020 at 11:12:37). Mail sent to janedoe@kifarunix-demo.com Password expired for koromicha on Friday 08, May 2020 at 21:34:02. Mail sent to koromicha@kifarunix-demo.com No password change date for johndoe (johndoe@kifarunix-demo.com) ===== Statistics ===== Total User Accounts checked: 4 Accounts with Expired Passwords: 1 Accounts with Passwords in Warning state: 1 }}} From the output above, we can see that; - A total of fours users, in the directory, were checked. - Password for user koromicha, has expired on Friday 08, May 2020 at 21:34:02. Notification email sent to user. - Password for the user, janedoe, will expire on Thursday 18, June 2020 at 11:12:37. Notification email sent to user. - No password change date for johndoe (johndoe@kifarunix-demo.com) Since we do not have any mail utility installed, you may get such an output; {{{ mail: command not found }}} '''Configure your LDAP Server to Send Mails''' In order for your OpenLDAP server to be able to send mails out, you need to have an MTA installed and configured. If you noticed above, the script tried use sendmail. In this demo, we will be using postfix instead. {{{ sudo apt install postfix }}} {{{ vim /etc/postfix/main.cf }}} Make the following adjustments; {{{ myhostname = ldap.kifarunix-demo.com inet_protocols = ipv4 (or all) relayhost = [smtp.gmail.com]:587 smtp_use_tls = yes smtp_sasl_auth_enable smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_security_options = noanonymous }}} Save and exit the configuration. Enter the authentication credentials on the file, /etc/postfix/sasl_passwd in the format; {{{ [smtp.gmail.com]:587 userid@gmail:password }}} Hash the credentials file. {{{ postmap /etc/postfix/sasl_passwd }}} Set the proper permissions on the credentials file, {{{ chown root:postfix /etc/postfix/sasl_passwd* chmod 640 /etc/postfix/sasl_passwd* }}} Start the Postfix configuration. {{{ systemctl enable --now postfix }}} '''Test Email Delivery''' {{{ echo "Test Postfix gmail relay" | mail -s "Test postfix gmail relay" admin@kifarunix-demo.com }}} Check the logs. {{{ tail /var/log/maillog }}} If you see this line, all is well; {{{ ...to=admin@kifarunix-demo.com, relay=smtp.gmail.com[74.125.133.108]:587, ...status=sent (250 2.0.0 OK .. }}} Once the email relay configuration is done, rerun the script. {{{ bash checkLdapPwdExpiration.sh }}} Check the administrator inbox, which in this demo is set to, admin@kifarunix-demo.com, and the inbox for the user whose password is in warning state, janedoe@kifarunix-demo.com. On Admin Mailbox, this is the email from LDAP; {{{ Subject: LDAP Password Expiration Status Hello Admin, Find the LDAP users account password expiry status as Jun 13,2020 21:31:11. Password warning for janedoe (expiry date, Thursday 18, June 2020 at 11:12:37). Mail sent to janedoe@kifarunix-demo.com Password expired for koromicha on Friday 08, May 2020 at 21:34:02. Mail sent to koromicha@kifarunix-demo.com No password change date for johndoe (johndoe@kifarunix-demo.com) ===== Statistics ===== Total User Accounts checked: 4 Accounts with Expired Passwords: 1 Accounts with Passwords in Warning state: 1 }}} On the User’s inbox (Janedoe and Koromicha in this case); {{{ Subject: LDAP Account Password Expiry Status Hi jane, Your password will expire in 4 days on Thursday 18, June 2020 at 11:12:37. Visit Kifarunix-demo Self Service Password site, https://ldap-ssp.kifarunix-demo.com to reset your password. As a reminder, ensure that your password conforms to the company outlined password policies. Kifarunix-demo IT team, Regards. }}} {{{ Subject: LDAP Account Password Expiry Status Hi koromicha, Your password expired on Friday 08, May 2020 at 21:34:02. Kindly contact Kifarunix-demo IT team to help reset the password. Kifarunix-demo IT team, Regards. }}} And there you go. You are now receiving the status of the LDAP accounts password expiry as the administrator. At the same time, users whose passwords are yet to expire are notified via their respective emails as defined on their LDAP entries. We hope that was informative. '''Create Daily Cron Job for the Script''' To ensure that the script is executed regularly, all you need to do is to create a cron job to execute the script at a specific regular time and have the LDAP accounts passwords status sent to users. Before you can install a cron job, ensure that the script is executable. {{{ chmod +x /home/kifarunix/checkLdapPwdExpiration.sh }}} To install a cron job, run the command below; {{{ crontab -e }}} Enter the line below, to have the script executed every day from Monday-Friday at 0800 hrs. {{{ 0 8 * * 1-5 /home/kifarunix/checkLdapPwdExpiration.sh }}} That marks the end of our guide on how to send OpenLDAP password expiry notifications via email. Additional: https://ubuntu.com/server/docs/install-and-configure-postfix