I'm seeing some odd behaviour here using PrincipalContext.ValidateCredentials
. The set-up is two Active Directory domains in parent/child setup (so we have primary domain company.com
and sub-domain development.company.com
).
When I validate credentials against the primary domain, ValidateCredentials
behaves as expected, returning true for good user/pass pairs, and false for anything else.
However if I validate a user in the sub-domain, ValidateCredentials
returns true for both good username/passwords AND invalid users. If I provide a valid user with an invalid password, it correctly returns false.
Now I'm working around it at the moment by doing UserPrincipal.FindByIdentity()
first and if the user exists, then calling ValidateCredentials
-- but I'd like to understand what's going on.
Another workaround I've looked at is by passing the username through as domain\username
as the MSDN entry for ValidateCredentials
states:
In each version of this function, the userName string can be in one of a variety of different formats. For a complete list of the acceptable types of formats, see the ADS_NAME_TYPE_ENUM documentation.
...of which this form of username is listed. But this causes ValidateCredentials
to always return true, no matter what combination of username and password I pass in.
The pertinent code is:
bool authenticated = false;
// Various options tried for ContextOptions, [etc] inc. explicit username/password to bind to AD with -- no luck.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain, null, ContextOptions.Negotiate, null, null))
{
log(pc.ConnectedServer + " => " + pc.UserName + " => " + pc.Name + " => " + pc.Container);
using (var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, username))
{
if (user != null)
{
log(user.DistinguishedName + "; " + user.DisplayName);
authenticated = pc.ValidateCredentials(username, password);
} else {
log("User not found");
// Debug only -- is FindByIdentity() needed. This should always return
// false, but doesn't.
authenticated = pc.ValidateCredentials(username, password);
}
}
}
return authenticated;
Any and all (sensible) suggestions welcome -- I'm scratching my head over this as it just goes against all expectations.
I ought to add: this is running as myself on my machine, both of which are members of the primary domain. However I've also tried running it in a command prompt on my machine as a user of the sub-domain (runas /user:subdomain\user cmd
) with exactly the same results.
Could it be related to this:
Some amount of googling later (not that I've been in and out of google all day trying to find this anyway), I've found the answer.
Put simply, if the Guest account is enabled in the domain, ValidateCredentials will return TRUE for an unknown user. I've just checked the status of the guest user in development.company.com, and sure enough the account is enabled. If I have the guest account disabled, ValidateCredentials correctly returns false.
This is a fairly fundamental gotcha, not sure I'm keen on this behaviour... pity it's not explicitly mentioned on MSDN.