5. LDAP

5.1. ldap3

5.1.1. LDAP Expiring Passwords

Listing 463. LDAP Expiring Passwords
# !/usr/bin/env python3

from datetime import datetime, timedelta
from pprint import pprint
from ldap3 import Server, Connection, SEARCH_SCOPE_WHOLE_SUBTREE


LDAP_HOST = "127.0.0.1"
LDAP_PORT = 389
LDAP_USER = "myusername"
LDAP_PASS = "mypassword"


def search(filter, basedn='OU=Users,DC=local', attributes=('mail', 'pwdLastSet')):
    with Connection(Server(LDAP_HOST, port=LDAP_PORT), user=LDAP_USER, password=LDAP_PASS) as ldap:
        ldap.search(basedn, filter, SEARCH_SCOPE_WHOLE_SUBTREE, attributes=attributes)
        return [record['attributes'] for record in ldap.response]


def datetime_to_mstimestamp(dt):
    """
    Active Directory has different approach to create timestamp than Unix.
    Here's a function to convert the Unix timestamp to the AD one.

    >>> dt = datetime(2000, 1, 1, 0, 0)
    >>> datetime_to_mstimestamp(dt)
    125911548000000000
    """
    timestamp = int(dt.timestamp())
    magic_number = 116_444_736_000_000_000
    shift = 10_000_000
    return (timestamp*shift) + magic_number


def mstimestamp_to_datetime(mstimestamp):
    """
    Active Directory has different approach to create timestamp than Unix.
    Here's a function to convert AD timestamp to the Unix one.

    >>> ms_timestamp = 130567328471235643
    >>> mstimestamp_to_datetime(ms_timestamp)
    datetime.datetime(2014, 10, 2, 16, 14, 7, 123563)
    """
    magic_number = 11_644_473_600
    shift = 10_000_000
    timestamp = (mstimestamp/shift) - magic_number
    return datetime.fromtimestamp(timestamp)


def month_ago(date):
    """
    >>> dt = datetime(2000, 1, 31, 0, 0)
    >>> month_ago(dt)
    datetime.datetime(2000, 1, 1, 0, 0)
    """
    return date - timedelta(days=30)


if __name__ == "__main__":
    now = datetime.now()
    since = month_ago(now)
    older_than_month_ago = f"""
        (&
           (objectCategory=Person)
           (userAccountControl=512)
           (pwdLastSet<={datetime_to_mstimestamp(since)})
           (mail=*)
        )
    """

    for user in search(older_than_month_ago):
        pwd_last_set = int(user['pwdLastSet'][0])
        user['pwdLastSet'] = mstimestamp_to_datetime(pwd_last_set)
        pprint(user)