i want to validate a set of credentials against the domain controller. e.g.:
Username: joel
Password: splotchy
Domain: STACKOVERFLOW
In .NET 3.5 and newer you can use PrincipalContext.ValidateCredentials(username, password)
.
Otherwise you're in trouble.
Following the code in the Microsoft Knowledge Base article How to validate user credentials on Microsoft operating systems, i get to the point where you call AcceptSecurityContext
:
ss = AcceptSecurityContext(
@pAS._hcred, //[in]CredHandle structure
phContext, //[in,out]CtxtHandle structure
@InBuffDesc, //[in]SecBufferDesc structure
0, //[in]context requirement flags
SECURITY_NATIVE_DREP, //[in]target data representation
@pAS._hctxt, //[in,out]CtxtHandle strcture
@OutBuffDesc, //[in,out]SecBufferDesc structure
ContextAttributes, //[out]Context attribute flags
@Lifetime); //[out]Timestamp struture
except that the function fails with:
SEC_E_NO_AUTHENTICATING_AUTHORITY
(0x80090311)The function failed. No authority could be contacted for authentication. This could be due to the following conditions:
- The domain name of the authenticating party is incorrect.
- The domain is unavailable.
- The trust relationship has failed.
This would be a useful error, except that i can validate the same credentials from .NET 3.5 using:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
valid = context.ValidateCredentials(username, password);
}
What could be happening that allows .NET to validate a set of credentials, while native code cannot?
Update: LogonUser
also fails:
LogonUser("joel@stackoverflow.com", null, "splotchy",
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_WINNT50, out token);
with
1311 - There are currently no logon servers available to service the logon request
Update Two: i've tried both the preferred Negotiate
provider, as well as the Windows NT4 legacy "NTLM" provider
String package = "Negotiate"; //"NTLM"
QuerySecurityPackageInfo(package, [out] packageInfo);
...
AcquireCredentialsHandle(
null, //[in] principle
package, //[in] package
SECPKG_CRED_OUTBOUND, //[in] credential use
null, //[in] LogonID
pAuthIdentity, //[in] authData
null, //[in] GetKeyFn, not used and should be null
null, //[in] GetKeyArgument, not used and should be null
credHandle, //[out] CredHandle structure
expires); //[out] expiration TimeStamp structure
I presume that this is to solve the same problem as another question that you posted.
I kind of understand what you are trying to do now. Let me recap what you wrote on another post.
You want to
You can achieve the first two cases by doing proper SSPI handshaking with the domain controller. The KB article that you are referring to in another question is doing loop back SSPI handshaking. It's not going to work in case number one because the client machine does not trust the domain that you are authenticating to. That should be why you are seeing
SEC_E_NO_AUTHENTICATING_AUTHORITY
.To cut it short, if you want to do exactly the same thing as
you need to handle the local user differently from the domain user. For domain user, you need to call ldap_bind_s to bind to the domain controller using the given credentials. For local user, you need to use ADsOpenObject to bind to the WinnT://YourComputerName using the given credentials. This is what
PrincipalContext.ValidateCredentials
doing from what I read in the Reflector.I don't see there is any equivalent one single native API doing the same thing for you.