LdapConnection and PrincipalContext

I have the following two options for authenticating users with LDAP and LDAPS, and I was wondering what was better / more correct. For recording, both of these functions work with both SSL and non-SSL connections.

I'm also curious that when I watch with Wireshark in the Non-SSL PrincipalContext version, I still see traffic on port 636. Of the four combinations ( Non-SSL LdapConnection , SSL LdapConnection , Non-SSL PrincipalContext , SSL PrincipalContext ) this is the only one which has traffic to both ports 389 and 636 instead of one or the other. What could be the reason for this?

LDAP connection method:

 bool userAuthenticated = false; var domainName = DomainName; if (useSSL) { domainName = domainName + ":636"; } try { using (var ldap = new LdapConnection(domainName)) { var networkCredential = new NetworkCredential(username, password, domainName); ldap.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback((con, cer) => true); ldap.SessionOptions.SecureSocketLayer = useSSL; ldap.SessionOptions.ProtocolVersion = 3; ldap.AuthType = AuthType.Negotiate; ldap.Bind(networkCredential); } // If the bind succeeds, we have a valid user/pass. userAuthenticated = true; } catch (LdapException ldapEx) { // Error Code 0x31 signifies invalid credentials, anything else will be caught outside. if (!ldapEx.ErrorCode.Equals(0x31)) { throw; } } return userAuthenticated; 

PrincipalContext Principle:

 bool userAuthenticated = false; var domainName = DomainName; if (useSSL) { domainName = domainName + ":636"; ContextOptions options = ContextOptions.SimpleBind | ContextOptions.SecureSocketLayer; using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName, null, options)) { userAuthenticated = pc.ValidateCredentials(username, password, options); } } else { using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName)) { userAuthenticated = pc.ValidateCredentials(username, password); } } return userAuthenticated; 
+7
c # ssl active-directory ldap
source share
2 answers

@ DTI-Matt, in the examples above, you use the VerifyServerCertificate , which always returns true . This, in fact, does not meet the purpose of connecting to LDAP over SSL, since authentication is not performed.

While you can implement real certificate validation using the X509Chain and / or X509Certificate2 , it seems that PrincipalContext processing your validations.

To summarize, both LdapConnection and PrincipalContext provide very similar functionality in connecting to an LDAP server through a regular or SSL connection. You must supply LdapConnection much more handwritten code for it to work correctly. On the other hand, PrincipalContext gives you the same functions as less code for manual recording.

As a side note, connections to port 636 (your LDAP by default SSL port), not to SSL PrincipalContext can be explained by the fact that this class tries to connect as securely as possible.

+4
source share

This is what we ended up working on SSL / Non-SSL.

 public bool UserValid(string username, string password, bool useSSL) { bool userAuthenticated = false; var domainName = DomainName; if (useSSL) { domainName = domainName + ":636"; } try { using (var ldap = new LdapConnection(domainName)) { var networkCredential = new NetworkCredential(username, password, DomainName); // Uses DomainName without the ":636" at all times, SSL or not. ldap.SessionOptions.VerifyServerCertificate += VerifyServerCertificate; ldap.SessionOptions.SecureSocketLayer = useSSL; ldap.AuthType = AuthType.Negotiate; ldap.Bind(networkCredential); } // If the bind succeeds, we have a valid user/pass. userAuthenticated = true; } catch (LdapException ldapEx) { // Error Code 0x31 signifies invalid credentials, so return userAuthenticated as false. if (!ldapEx.ErrorCode.Equals(0x31)) { throw; } } return userAuthenticated; } private bool VerifyServerCertificate(LdapConnection connection, X509Certificate certificate) { X509Certificate2 cert = new X509Certificate2(certificate); if (!cert.Verify()) { // Could not validate potentially self-signed SSL certificate. Prompting user to install certificate themselves. X509Certificate2UI.DisplayCertificate(cert); // Try verifying again as the user may have allowed the certificate, and return the result. if (!cert.Verify()) { throw new SecurityException("Could not verify server certificate. Make sure this certificate comes from a trusted Certificate Authority."); } } return true; } 
0
source share

All Articles