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("[email protected]", 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.
Username Password Domain Machine on domain? Validate as
======== ======== ================= ================== ==============
iboyd pass1 . No Local account
iboyd pass1 (empty) No Local account
iboyd pass1 stackoverflow.com No Domain account
iboyd pass1 . Yes Local account
iboyd pass1 (empty) Yes Domain account
iboyd pass1 stackoverflow.com Yes Domain account
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
PrincipalContext.ValidateCredentials(username, password);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With