I would like to find out if there is any .Net way to validate an Active Directory user credential even if the user's password is expired or the user has "user must change password at next logon" set. I have tried PrincipalContext.ValidateCredential and this returns false for my user. I also tried Ldap Bind and that does not work either. My purpose is to authenticate the user and then prompt him with a change password dialog if his password is expired or he has to change passwored at next login.
-
1If you are needing to check against an expired password then it sounds like you are doing somethign wrong. The whole point of an expired password is that it can't be used any more and shouldn't be used for authentication, I'm sure. Perhaps you don't want to be expiring passwords so enthusiastically or something like that? – Chris Jan 23 '12 at 17:19
-
1I'm working on an UI that should authenticate the user and then prompt him to change the password if the password has expired or has to be changed at next logon. If I only validate the user existence in the first step, then the user experience is confusing. The user will seem to be logged in on the first screen and then when he tries to change his password (by inputting his old password and a new password) he will discover that his old password is incorrect. Windows does the same when your password is expired, you don’t get to the change password screen unless you provide a correct password. – Monica Jan 23 '12 at 18:38
-
What I have tried and did not work: LDap bind, UserPrincipal.ValidateCredentials, LogonUser(this works only on the local machine). – Monica Jan 26 '12 at 17:38
-
Try this... [http://stackoverflow.com/questions/5664482/ldap-validation-fails-when-user-must-change-password-on-next-log-on-any-solut][1] [1]: http://stackoverflow.com/questions/5664482/ldap-validation-fails-when-user-must-change-password-on-next-log-on-any-solut – Aleks Sep 04 '13 at 13:04
4 Answers
We have several AD controllers in our setup and the PrincipalContext.ValidateCredentials method would always return false on the AD controllers on Windows 2003 servers on users with the "user must change password at next logon" checkbox checked.
But on the ones on Windows 2008 R2 servers, it would return true if the creds were valid even if the checkbox was checked.
So I just made sure my code was hitting one of the windows 2008 R2 servers and that did the trick.
I did work on a solution for the 2003 servers (before I realized things would just work on the other ones). Here is the code:
var adContext = new PrincipalContext(ContextType.Domain, adLocation, adContainer, adAdminUsername, adAdminPassword);
var initialValidation = adContext.ValidateCredentials(username, password);
Console.WriteLine("Initial validation returned: " + initialValidation);
if (!initialValidation)
{
// maybe validation failed because "user must change password at next logon".
// let's see if that is the case.
var user = UserPrincipal.FindByIdentity(adContext, username);
if (user.LastPasswordSet == null)
{
// the user must change his password at next logon. So this might be
// why validation returned false
// uncheck the "change password" checkbox and attempt validation again
var deUser = user.GetUnderlyingObject() as DirectoryEntry;
var property = deUser.Properties["pwdLastSet"];
property.Value = -1;
deUser.CommitChanges();
// property was unset, retry validation
adContext.ValidateCredentials(username, password);
Console.WriteLine("Secondary validation returned: " + adContext.ValidateCredentials(username, password));
// re check the checkbox
property.Value = 0;
deUser.CommitChanges();
}
}

- 1,274
- 13
- 12
-
It's not actually that simple. Even AD 2008 behaves differently if they are running in different domain functional levels, e.g. 2000, 2003 or 2008 R2. Better check for both methods regardless of which AD version you are running against. – Ezra Nugroho May 01 '15 at 20:58
Inspired by Pedro's answer, here's another simpler way to temporarily "unexpire" the user's password, so that ValidateCredentials
can be used:
var user = UserPrincipal.FindByIdentity(PrincipalContext, username);
user.PasswordNeverExpires = true;
user.Save();
Now this works:
var canLogin = PrincipalContext.ValidateCredentials(username, password);
After verification, the flag can be reset:
user.PasswordNeverExpires = false;
user.Save();

- 23,054
- 9
- 78
- 76
I have found absolutely NO WAY to validate a user if the "User must change password at next log on" flag is set.
This is the solution I came up with. Sorry it is in VB, it is inherited code :)
' Authenticate Using the Administrator Account Dim domainAndUserName As String = tmpDomain + "\" + tmpUser Dim entry As DirectoryEntry = New DirectoryEntry(sLDAP_PATH, m_AD_BIND_USERNAME, m_AD_BIND_PASSWORD) Dim ds As DirectorySearcher = New DirectorySearcher(entry) ds.Filter = "(&(objectClass=user)(anr=" + tmpUser + "))" ' Lookup the User Dim user As SearchResult = ds.FindOne() ' Check the User Status ' If the "User must change password at next logon" flag is set ' then we need to clear it before we can test the users credentials If Convert.ToInt64(user.Properties("pwdLastSet").Item(0)) = 0 Then Dim deUser As DirectoryEntry = user.GetDirectoryEntry() deUser.Properties("pwdLastSet")(0) = -1 deUser.CommitChanges() Dim isValidCreds As Boolean = True ' Create Directory Entry for User entry = New DirectoryEntry(sLDAP_PATH, domainAndUserName, Password) ' Attempt to create NativeObject based on credentials ' If it fails the credentials are invalid Try Dim obj As Object = entry.NativeObject() Catch ex As Exception isValidCreds = False End Try ' Reset the flag deUser.Properties("pwdLastSet")(0) = 0 deUser.CommitChanges() ' If the credentials are valid, return '1907' ' if the credentials aren't valid, return '1326' If isValidCreds Then Throw New Exception("1907") ' Password Expired Else Throw New Exception("1326") ' Invalid Login End If ElseIf Convert.ToInt64(user.Properties("userAccountControl").Item(0)) = 514 Then Throw New Exception("1331") ' Account Disabled ElseIf user.Properties("lockoutTime").Count > 0 AndAlso Convert.ToInt64(user.Properties("lockouttime").Item(0)) > 0 Then Throw New Exception("1909") ' Account Locked Out End If
Only thing to be aware of is there is a potential for an issue due to slow replication, i.e., you may set the flag but since the update hasn't replicated to all of your DCs when you attempt to create the 'NativeObject' it may still fail.

- 148
- 7
This article might help. You can use DirectorySearcher
to find out if a user exists and what the password status is.

- 2,952
- 13
- 15
-
I need to validate that the user's password is correct (even if it is expired or the user has to change it at next logon). Just cheching that the user exists and getting the password status is not enough :( – Monica Jan 23 '12 at 17:11
-
Hey Monica, did you ever figure this out? I'm also running into a situation where I don't just want to call the UserPrincipal.SetPassword(newPassword) method. I need something like a UserPrincipal.SetPassword(oldPassword, newPassword) overload that checks old creds before setting the new ones. – Pedro May 30 '12 at 20:15