Authenticating local users off the network
I am trying to authenticate a local user based on the username and password provided. I came across this threa开发者_StackOverflow中文版d: Validate a username and password against Active Directory?
Here is how I validate the user:
PrincipalContext pc = new PrincipalContext(ContextType.Machine);
bool isValid = pc.ValidateCredentials(user, pass);
It works as long as I am on a network, but if I disconnect my computer it gives me:
The network path was not found.
All I am trying to do is validate on the local machine which may or may not be a part of a network.
EDIT: UserPrincipal.FindByIdentity seems to still work with no AD, it's the pc.ValidateCredentials that is giving me trouble.
You should probably look into this link: How to validate domain credentials?
It seems that using the LogonUser Win32 API function is the only option if you have to be able to accomplish your validation even when AD is not online. However, not without serious drawbacks (as indicated in the thread). You need to pimp the account executing your app with a lot of privileges.
As you've noted, the System.DirectoryServices
namespace is not very useful in a disconnected context -- you need to talk to the LSA, not its Active Directory parent.
I don't know of an official .Net API that corresponds to advapi32.LogonUser
, but you can call it to validate against a locally cached logon. If the machine has network access but can't see a domain controller, though, it may take a while to return.
The function has a declaration on pinvoke.net
if you want to call it via P/Invoke. (I haven't reviewed it, though; I've found that the quality of signatures on pinvoke.net
varies wildly.)
A possible ugly workaround -
Using ValidateCredentials() with ContextType.Machine will always check the credentials against the local system first. It only performs network activity if the credentials are NOT found locally. You could catch the PrincipalOperationException if thrown and safely ignore it, knowing that if the method got this far the credentials are not valid.
bool valid = false;
using (PrincipalContext checkpass = new PrincipalContext(ContextType.Machine)) //checks local machine first
{
try // you need to use try catch when you only have local user
{
valid = checkpass.ValidateCredentials(user, password);
}
catch (Exception ex) { valid = true; }
if (valid)
{
// returns ok
}
else
{
// returns false
}
精彩评论