Active Directory or “How I Learnt to Live With the Ugly COM Guts”
September 14, 2006
In a project I’m working on, I have to authenticate a user on a custom SharePoint 2003 login form (Yes, that’s possible….more on it will be coming soon). It is a straightforward task, once you overcome the System.DirectoryServices namespace oddities.
In essence, I try to bind a user credentials to a Active Directory LDAP server. If successful, the account is active and with a valid password.
But, what happens when you have a user with “User must change password on the next logon” checkbox turned on? If you try to bind the user, LDAP will throw an error because the credentials you’ve supplied are not valid.
It was an imperative to be able to check for this condition. After a lot of googling, I’ve come out with the solution:
DirectoryEntry user;
...
System.Int64 largeInt = 0;
IADsLargeInteger int64Val = IADsLargeInteger) user.Properties["pwdLastSet"].Value;
largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;
if(largeInt == 0)
Pretty much obfuscated, isn’t it?
It seems that Active Directory stores the “must change password” condition in a property called pwdLastSet, which also stores the date when the password was last set. If this value is zero, the password has not yet been set, ie “must change password” check is marked in the User Properties Tab.
But if you try to check the value directly, you’ll face a lot of exceptions from the underlying COM scaffolding. The pwdLastSet property is a 64-bit integer value which maps into a IADsLargeInteger type (found in “ActiveDs COM Type Library”). This type has two 32-bit halves: HighPart and LowPart. So, if you want to translate this into a large integer (System.Int64 in .NET Framework) you have to perform the multiplication shown in the code above.
A lot of headache could have been avoided if this strange quirk had been well-documented.