We have an application that authenticates against a remote AD using LDAP, by IP address, over a VPN tunnel, using the following code:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldap.Host, ldap.Path.Replace("/", ""), ContextOptions.Negotiate, UserName, Password))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(pc, domainAndUsername))
{
if (user != null)
{
SAMAccountName = user.SamAccountName;
retVal = true;
}
}
}
This works great for normal, non-SSL LDAP. However, we've encountered a situation where we need to be connecting to LDAPS, via SSL, and it doesn't work. I've tried a ton of variations on the PrincipalContext constructor, but everything we do results in a failed connection, with this error:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. ---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
at System.DirectoryServices.Protocols.LdapConnection.Connect()
at System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID)
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
--- End of inner exception stack trace ---
at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
at System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()
at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)
We know it's not the LDAP server itself, as trying by the method discussed here connects without errors. I'm not really comfortable with using try...catch for logic flow, and I've read of some other issues with this method (like not properly respecting certificates and such), so I'm trying to make this work with PrincipalContext.
Could anybody offer me some guidance here? I'm going crazy on this one.
EDIT: Upon some further research, it looks like this may be a problem with self-signed certificates.
EDIT 2: After breaking it down into X509 chain calls, I'm getting this specific error:
PartialChain A certificate chain could not be built to a trusted root authority.
Looking at that, you'd think it's just a matter of adding the CA as a trusted root, but that didn't seem to fix the problem.