I'm trying to use the .NET 3.5 System.DirectoryServices.AccountManagement
namespace to validate user credentials against our Active Directory LDAP server over an SSL encrypted LDAP connection. Here's the sample code:
using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:389", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
return pc.ValidateCredentials(_username, _password);
}
This code works fine over unsecured LDAP (port 389), however I'd rather not transmit a user/pass combination in clear text. But when I change to LDAP + SSL (port 636), I get the following exception:
System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)
at (my code)
Port 636 works for other activities, such as looking up non-password information for that LDAP/AD entry…
UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, _username)
…so I know it's not my LDAP server's SSL setup, since it works over SSL for other lookups.
Has anyone gotten the ValidateCredentials(...)
call to work over SSL? Can you explain how? Or is there another/better way to securely validate AD/LDAP credentials?
Best Answer
I was able to validate credentials using the
System.DirectoryServices.Protocols
namespace, thanks to a co-worker. Here's the code:I'm not thrilled with using a try/catch block to control decisioning logic, but it's what works. :/