I've had to respond to this topic a number of times now, so I figured I would just write it up here for future reference.
If you are using Active Directory, and you administratively change a principle's password, sometimes you find that the old password still works (at least for a little while). Most often, you'll see this if you are using PrincipleContext or a Membership Provider that uses A.D. under the covers, because when you call their methods to change password, they do an administrative password change using LDAP.
This is actual an old feature of NTLM authentication. The concept being (if I remember correctly) that after an administrative password change, you could still have cached credentials, shares, etc. using the old password. Therefore, NTLM still accepted the old password for some specified amount of time after the password change. The same "feature" is no longer available under Kerberos from what I understand.
So first, you might be asking, "What's all this about NTLM and Kerberos? I'm using Active Directory and/or LDAP". True, but AD is just a giant database of network resource info (including users and groups) and LDAP is simply one protocol to query/change that data. The information by itself doesn't actually "do" anything. To perform authentication, Windows uses information from AD, but uses one of two protocols: NTLM or Kerberos. NTLM is a hashed credential challenge-response based protocol, and Kerberos is a (non-Microsoft) based protocol using 3rd party symmetric credential encryption and verfication via tickets. If you didn't get all that, don't worry. The point is that they work differently. NTLM is the old Windows NT networking library (including authentication), and Kerberos is the shiney new authentication library. But Windows still maintains both because not all environments or even all versions of Windows are capable of using strictly Kerberos. In fact, by default, Windows uses a pseudo-protocol called Negotiate, which tries to use Kerberos, and if that fails, falls back on NTLM.
So one way to prevent the old password being valid after a password change is stop using NTLM for authentication. And that's easier said than done. If you are using PrincipleContext, nothing you do will prevent the code from using Negotiate (which ends up using NTLM when Kerberos comes back with an error). Even changing the ContextOptions won't do it.
The PrincipleContext class authenticates by establishing a secure LDAP connection and then calling Bind() on that connection. It provides the given credentials (user name and password) to the Bind operation. But no matter what you change on the PrincipleContext, it will almost always use Negotiate (barring some scenarios, like looking for local users, which simply queries the local SAM database). Therefore, you have to stop using PrincipleContext.ValidateCredentials. Instead, you can do what it does under the covers, and Bind to an LDAP connection manually. It's quick and only takes a few lines of code. Basically, you create a new LdapConnection and set the NetworkCredentials (just an object that holds user name and password). Next, (and this is the important part), set the AuthType to Kerberos. Finally, call the Bind() method. If the credentials are invalid, you'll get an exception to that effect. This is exactly what PrincipleContext.ValidateCredentials does (if you are trying to validate based on Active Directory), but this way, you get to control the protocol being used. Also, don't forget that LdapConnection is a Disposable object, so make sure to call Dispose() when you're done, or instantiate it inside a Using block.
posted @ Thursday, April 16, 2009 4:42 PM