Building a custom authentication service on top of Active Directory (using LDAP), we now need to see if an account's password is expired or not (and preferably also when the password expires/expired). We need to see this when querying for accounts (not at bind()
in the context of a user request).
There are several flags available in Active Directory for this. The first we tried was the User-Account-Control attribute, which has the bit ADS_UF_PASSWORD_EXPIRED
which should be set if the password expires:
The user password has expired. This flag is created by the system using data from the Pwd-Last-Set attribute and the domain policy.
We couldn't get it to work, and found SimpleADSI's explanation:
Caution: This bit does not work as expected!
Normally, this user account control bit is supposed to indicate that the user's password is expired. However, it is not set by the system when the password actually expires, nor can you force the user to change his password at the next logon by setting this bit.
They instead refer to the constructed attribute msDS-User-Account-Control-Computed which also contains a bit for checking password expiry: UF_PASSWORD_EXPIRED
. There is also the msDS-UserPasswordExpiryTimeComputed, another constructed attribute, for getting when in time the password expires. Perfect, with one caveat:
Constructed Attributes cannot be returned as value data in an LDAP search request. unless the search scope is set to "base" which means that the LDAP client accesses only one single object.
This means we had to do one additional query for each account to fetch the constructed attributes. Not ideal, but it works.
Next, more Active Directory domains in the forest also wanted to use the new custom authentication service, so instead of querying our local domain controller we started querying the Active Directory Global Catalog (which means we can query for objects in any domain in the same forest).
And to the problem (finally): the Global Catalog does not synchronize all attributes from the local domain controller. "Luckily" the non-working User-Account-Control attribute is synchronized (oh the irony), but the constructed attributes we are using are not. This means we are back to square one, and cannot get when or even if the password has expired for accounts.
So, the two main questions are:
- Is there any way to enable synchronization of the constructed attributes (or the values they are calculated from) to the Active Directory Global Catalog?
- Is there a better way, perhaps to avoid the single-object-querying we do (did) for fetching the constructed attributes (I guess I am trying to ask if we are doing it all wrong...)?
Thanks in advance!