ldap-notify - LDAP Password/Login Expiration Notification Tool
Usage: ldap-notify [OPTION]... -c config_file.conf
ldap-notify
searches users in an LDAP directory whose login or password expires in a certain number of days. These users are notified with a customizable email. The time intervals for the notifications and the email templates can be freely defined. By using a custom LDAP attribute the last notification is stored in the directory such that users are only notified once per rule. Moreover, this mechanism allows running the tool (e.g. via cron) on multiple machine with a certain time delta in order to implement high availabiliy.
-h
, --help
show this help
-c
, --conf
config-file
mandatory parameter: the config file name
-k
ignore SSL/TLS certificates
--dry
do not send emails or modify anything in ldap
--test
test-address
send all mails to the given address
--restrict
DN;CN;...
restrict notifications to these semicolon separated user DNs or CNs
--time
timestamp
simulate current UTC time (format: 20141031162633Z
)
-v
, --verbose
enable verbose logging
-d
, --debug
enable debug logging
--print-conf
print the used configuration to console and exit
The behaviour of ldap-notify is defined via a config-file. The parameters above will override the options in the configuration file.
The configuration file given by the mandatory -c
or --conf
parameter uses the common INI file format. This means that it consists of sections with key/values pairs in the following format:
[section_name]
attribute=value
second_attribute = multi
line
value
# comment
The multi-line value is useful for long lists like in the restrict_to_users
value.
The default configuration is the following (call ldap-notify
with the --print-conf
parameter to print it):
[common]
server = ldap://localhost
bind_dn =
bind_password =
bind_password_base64 =
base_dn =
subtree_search = false
starttls = false
ignore_cert = false
expiry_attribute = passwordExpirationTime
notify_attribute = pwmNotify
dry = false
restrict_to_users =
user_objectclass = person
object = password
objects =
[smtp]
server =
ssl = false
starttls = false
user =
password =
password_base64 =
[admin]
from_address = root@<HOSTNAME>
to_address = admin@<HOSTNAME>
from_text = $Object Expiry Notification
subject = $Object Expiry Notification Report
text_template = <LDAP_NOTIFY_DIR>/templates/admin.tmpl.txt
[test]
enabled = false
to_address = root@<HOSTNAME>
The configuration options have the following meaning:
Option | Format | Description | Examples |
---|---|---|---|
server |
RFC 4516 | the server LDAP URI | ldap://host:389 or ldaps://host |
bind_dn |
DN or empty | the DN to bind to; can be empty | cn=admin,ou=users,dc=localhost |
bind_password |
string | the password to be used during binding | secret |
bind_password_base64 |
base64 encoded string | an encoded bind password | YWRtaW5fc2VjcmV0 |
base_dn |
DN list | the base DNs to start a search at | ou=users,dc=localhost;ou=admins,dc=localhost or empty |
`subtree_search | boolean | do a SUBTREE or ONELEVEL search | true or false |
starttls |
boolean | use starttls on a ldap:// connection | true or false |
ignore_cert |
boolean | don't check server SSL/TLS certificate | true or false |
expiry_attribute |
LDAP attribute | the attribute holding the expiration timestamp | passwordExpirationTime |
notify_attribute |
LDAP attribute | the attribute used to store sent notifications | pwmNotify |
dry |
boolean | don't send mails or modify LDAP | |
restrict_to_users |
DN or CN list | restrict sent mail and LDAP modifications | cn=admin,ou=users,dc=localhost;root;hschmidt; |
user_objectclass |
LDAP objectClass | an object class name to restrict the user search | pwmUser or person |
object |
string | the object this config talks about | password or login |
objects |
string | the plural string of object | passwords or logins |
The DN list
of base_dn
is separated by semi-colons, spaces or newlines. An empty base_dn
implies substree_search = true
and means to start the search at the dictionary root.
The DN or CN list
of `restrict_to_users is separated by semi-colons, spaces or newlines. A non-trivial example with a multi-line value is the following:
restrict_to_user = cn=alice,ou=users,dc=localhost
cn=bob,ou=users,dc=localhost
root;admin;operations
The object
and objects
values are only used in templates in order to allow unified templates for e.g. password and login configuration.
Option | Format | Description | Examples |
---|---|---|---|
server |
HOSTNAME[:PORT] | the mail server address | smtp.gmail.com |
ssl |
boolean | true if the server speaks SSL | true or false |
starttls |
boolean | use starttls after connecting with encryption | true or false |
user |
string | the SMTP user name to authenticate with | hschmidt |
password |
string | the SMTP password to authenticate with | secret |
password_base64 |
base64 encoded string | the SMTP password encoded with base64 | YWRtaW5fc2VjcmV0 |
Option | Format | Description | Examples |
---|---|---|---|
from_address |
email address | the sender address for the admin report | [email protected] |
to_address |
email address | send the admin report here | [email protected] |
from_text |
sender name | the sender name for the admin report | Password Expiry Notification Service |
subject |
string | the admin report subject | Password Expiry Notification Report |
text_template |
absolute filename | the admin report email body template | /etc/ldap-notify/admin.tmpl.txt |
Option | Format | Description | Examples |
---|---|---|---|
enabled |
boolean | if true, all emails are sent to the test email address | true or false |
to_address |
email address | the test email address | root@localhost |
The object
string in the common
section can be used in the templates such that they work for password and login notification emails.
An arbitrary number of rules can be defined in the configuration file. The rules are named according to their number of days before an expiration date when the rule applies. E.g. a 30 day rule is called "30".
The default values of a 30 day rule:
[30]
from_address = *ADMIN FROM ADRESS*
from_text = *ADMIN FROM TEXT*
subject = $Object will expire soon
text_template = <LDAP_NOTIFY_DIR>/templates/notify.tmpl.txt
html_template =
A quite minimal rules configuration with only one template (the default notify.tmpl.txt
), but customized subject lines looks like this:
[30]
subject = $weeks_left weeks left
[7]
subject = $days_left days left
[1]
subject = Tomorrow
The rule options have the following meaning:
Option | Format | Description | Examples |
---|---|---|---|
from_address |
email address or empty | the notification mail from address | [email protected] |
from_text |
string | the notification mail from text | Password Notification |
subject |
string | the subject of a notification | expires in $days_left days |
text_template |
absolute filename | the notification mail text template | /etc/ldap-notify/notify-30.tmpl.txt |
html_template |
absolute filename | the notification mail html template | /etc/ldap-notify/notify-30.tmpl.html |
The subject of the notification emails will be interpolated with the same variables as in the email template itself (cf. below).
By default, HTML mail templates are disabled. Next to the default text template there is also an example notify.tmpl.html. By assigning a template to the html_template option, HTML mail templates will be enabled.
During test of the script it is highly suggested to use the --test
, the --dry
and --restrict
options or the respective options in the configuration file.
These three options are orthogonal and can be combined depending on the test case at hand:
--test
test-address: all emails that are sent byldap-notify
are sent to the test address, not the actual addresses of the matching users. Moreover, no LDAP modifications are done.--dry
: no emails are sent at all, not even to a test user. Moreover, no LDAP modifications are done.--restrict
DNs;CNs;...: all users are processed as in normal operation, but emails are only sent to the admin (for the admin report) and the given users as DNs or CNs. Moreover, no LDAP modifications are done to users not in this list.
For debugging and testing it is useful to use verbose and debug output:
-v
: show log output on level ERROR, WARN, INFO. Normally, INFO log output is supressed.-d
: show log output on level ERROR, WARN, INFO and DEBUG. Normally, INFO and DEBUG log output is supressed.
The debug parameter -d
can be passed multiple times in order to increase the debug level even further.
Email templates, email subjects and email from strings for rules are interpolated with a number of variables.
In the case of user notification emails the following variables are interpolated:
Variable | Format | Description | Examples |
---|---|---|---|
$expiry_date |
string | the localized (according to the LANG setting) date of the expiration timestamp | 12.10.2014 for LANG=de_DE |
$days_left |
integer | number of days from today to the expiration timestamp, rounded down | 4 |
$weeks_left |
integer | number of weeks from today to the expiration timestamp, rounded down | 2 |
$months_left |
integer | number of months from today to the expiration timestamp, roundded down | 1 |
$rule_days |
integer | the days of the applying rule | 14 |
$cn |
string | the common name of the user being notified | hschmidt |
$dn |
DN | the DN of the user being notified | cn=hschmidt,ou=users,dc=localhost |
$fullname |
string | the full name of the user being notified | Hans Schmidt |
$object |
string | the object in singular, defined by object in the configuration |
password |
$objects |
string | the object in plural, defined by objects in the configuration |
passwords |
$Object |
string | the singular object with capital letter | Password |
$Objects |
string | the plural object with capital letter | Passwords |
$grace |
integer | the number of grace commits | 3 |
The object
and objects
variables are defined by the very same options in the configuration. If objects
is empty, a single s
character is appended to the object
value.
In the case of admin report emails the following variables are interpolated::
Variable | Format | Description | Examples |
---|---|---|---|
$notified_users |
multiline string | users which were notified via email | cn=alice,ou=users,dc=localhost, [email protected], 14 Days Rule, Expiry Date: 2014-10-13 14:20:25 |
$failed_users |
multiline string | users where notification failed | as in $notified_users |
$users_without_email |
multiline string | users to be notified, but without email | cn=alice,ou=users,dc=localhost, 14 Days Rule, Expiry Date: 2014-10-13 14:20:25 |
$no_grace_logins |
multiline string | users without grace logins | cn=alice,ou=users,dc=localhost, [email protected], Expiry Date: 2014-10-13 |
$notified_users_length |
integer | number of rows in $notified_users |
52 |
$failed_users_length |
integer | number of rows in $failed_users |
0 |
$users_without_email_length |
integer | number of rows in $users_without_email |
7 |
$no_grace_logins_length |
integer | number of rows in $no_grace_logins |
5 |
$object |
string | the object in singular | password |
$objects |
string | the object in plural | passwords |
$Object |
string | the singular object with capital letter | Password |
$Objects |
string | the plural object with capital letter | Passwords |
The object
and objects
variables are defined by the very same options in the configuration. If objects
is empty, a single s
character is appended to the object
value.
The ..._length
variables count the number of lines in the respective ..._users
variables. These can be used to shows counters (e.g. of failed notifications) at the very top of the admin report.
The search algorithm in `ldap-notify looks for users of each rule which satisfy the following conditions:
- have an expiration timestamp within the number of days in the rule,
- do not match with other rules,
- are not disabled,
- have not received the same notification before.
In addition in case of any of the following conditions only the admin is notified via the admin report, no user notification is sent out:
- have an email address,
- have grace login available.
The algorithm stores the last sent notification and a timestamp in the notify_attribute
(defined in the common
config section). The value has the following format:
20140116111356Z:30
It tells the algorithm that this user was notified at the given timestamp with a 30 days rule.
Assume that three rules are defined: 30, 7, 1 and passwordExpirationTime
is used as the expiry attribute. Then three independent LDAP searches are performed, each of them with a filter of the following shape:
(& (objectClass=person)
(!(loginDisabled=true))
(& (passwordExpirationTime>=20141112173529Z)
(!(passwordExpirationTime>=20141116173529Z))
(!(loginGraceRemaining=0))
)
)
The timestamps used are:
- 1 days:
passwordExpirationTime >= *NOW*
andpasswordExpirationTime < *24 HOURS FROM NOW*
- 7 days:
passwordExpirationTime >= *24 HOURS FROM NOW*
andpasswordExpirationTime < *7 DAYS FROM NOW*
- 30 days:
passwordExpirationTime >= *7*
andpasswordExpirationTime < *30 DAYS FROM NOW*
.
To detect that the same notification was sent before, but to cope with old notify attribute values at the same time, the notify attribute is read, e.g. 20130116111356Z:30
. This notify attribute timestamp is considered old if
expirationTime - last_notify >= 30 days
- or the current applied rule (e.g. 7) is smaller than the last notified rule:
7 < 30
.
If neither condition matches, the notifiy attribute is current and the user is skipped. If at least one condition matches, the user is notified and a new notify attribute is written.
Users are notified only once for each rule. This allows to launch ldap-notify
on multiple servers, with a time delta to avoid overlap and race conditions. If the first server fails, the second launch on the second server will notice this and send the notifications on behalf of the first instance.
Moreover, ldap-notify
will handle SMTP errors gracefully: if the SMTP connection fails, the notification attribute is not updated.
If the notification attribute cannot be parsed (i.e. its format is invalid), the notification attribute is deleted before processing the user.
ldap-notify
is written in Python. The ldap-notify
has no dependencies other than python-ldap. After cloning the Github repository with the source code, some more dependencies are needed for development which can be installed with pip:
virtualevn ../env
. ../env/bin/activate
pip install -r requirements.txt
After installation the dependencies, the unit tests can be run to verify that everything works as expected:
nosetests --rednose -v ldap_notify/tests
Everything should be green.
To launch the ldap-notify
itself, do the following:
python -mldap_notify.main -c login.conf
Make sure that login.conf
in the current directory is valid.
To update the man page from README.md, install md2man
and run:
grep -v 'Build Status' README.md | md2man-roff > man5/ldap-notify.5
man -M . ldap-notify
Dr. Stefan Schimanski [email protected]