Monday, October 23, 2017

PrincipalContext LDAPS Self-Signed Certificate

Leave a Comment

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.

1 Answers

Answers 1

Check this answer by Gabriel Luci

Are you sure it supports SSL and that the firewall is open to allow that connection?

LDAP uses port 389. LDAPS uses port 636.

If you have the telnet client installed, you can use it to check the connectivity:

telnet yourdomain.com 636 If you get a blank screen, it worked. If it can't connect, it will tell you.

If that is open and it still does not work, it could be using a self-signed SSL certificate. Check the Windows event log for certificate-related errors.

I've also used Chrome to check the certificate. You have to run chrome like this:

chrome.exe --explicitly-allowed-ports=636 Then browse to https://yourdomain.com:636 and see if it gives you any certificate errors. Then you can actually see the certificate. If that's the problem, you may be able to import the certificate and explicitly trust it.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment