How to check AD user credentials when the user password is expired or "user must change password at next logon"

10,713

Solution 1

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();
  }
}

Solution 2

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();
Share:
10,713
Monica
Author by

Monica

Updated on July 30, 2022

Comments

  • Monica
    Monica almost 2 years

    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.