Search code examples
pythonactive-directoryldap

LDAP3 search when Active Directory accounts expire


I want to specify an LDAP3 search against an Active Directory server which returns when the PW of an account expires.

server = Server(server_name, port=636, use_ssl=True, get_info=ALL)
conn = Connection(server, user='{}\\{}'.format(domain_name, user_name), password=password, authentication=NTLM, auto_bind=True)

 conn.search(
            search_base=f'OU={root_ou},OU={sub_ou},OU={org_ou},DC={domain_name},DC={domain_suffix}',
            # search_filter='(objectClass=person)',

            # https://learn.microsoft.com/en-us/windows/win32/adschema/a-accountexpires
            search_filter='(userAccountControl:1.2.840.113556.1.4.159)',
            # search_scope='SUBTREE',
            attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES]
)

Can I specify the search filter in a way so that it returns:

The date when the account expires. This value represents the number of 100-nanosecond intervals since January 1, 1601 (UTC). A value of 0 or 0x7FFFFFFFFFFFFFFF (9223372036854775807) indicates that the account never expires.

I would like to see the actual value as a date.


Solution

  • I can't give you the complete solution in Python, since I'm not a Python developer, but I can point you in the right direction.

    The accountExpires attribute tells you when the account expires, not the password.

    If you want the password expiry, it's a bit harder. You first have to find out the maximum allowed password age on your domain. To do that, look at the maxPwdAge attribute at the root of the domain. You can bind to the root of the domain just like you can any user, e.g. LDAP://DC={domain_name},DC={domain_suffix}

    Once you have that, you can look at the pwdLastSet attribute on the user account, then do that math to figure out if it has been longer than the maximum allowed age. If the value is 0, then the user must change their password at next logon.

    You must also check if the user has a password that never expires. That flag is part of the userAccountControl attribute, which is a bit flag. You're looking for the ADS_UF_DONT_EXPIRE_PASSWD flag, which has a hex value of 0x10000. You can use Python's bitwise AND operator &:

    if userAccountControl & 0x10000:
         # Password does not expire
    

    If that flag is set, then the value of pwdLastSet is irrelevant.