LdapConnection与PrincipalContext

我有以下两种使用LDAP和LDAPSvalidation用户的实现,我想知道哪个更好/更正确。 对于记录,这两个都适用于SSL和非SSL连接。

我也很好奇,因为在Non-SSL PrincipalContext版本上使用Wireshark观看时,我仍然看到端口636上的流量。在四种组合中( Non-SSL LdapConnectionSSL LdapConnectionNon-SSL PrincipalContextSSL PrincipalContext ),它是只有一个在389和636端口都有流量,而不只是一个或另一个。 可能是什么导致了这个?

LDAP连接方法:

 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方法:

 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; 

@ DTI-Matt,在上面的示例中,您使用始终返回true VerifyServerCertificate回调。 这基本上违反了通过SSL连接到LDAP的目的,因为没有执行真正的证书检查。

虽然您可以使用X509Chain和/或X509Certificate2类实现真正的证书检查,但似乎PrincipalContext为您处理检查。

总而言之, LdapConnectionPrincipalContext提供了非常类似的function,通过普通或SSL连接连接到LDAP服务器。 您必须为LdapConnection更多手写代码才能正常工作。 另一方面, PrincipalContext为您提供相同的function,只需较少的代码即可手动编写。

请注意,非SSL PrincipalContext与端口636(您的默认LDAP over SSL端口)的连接可能是由于此类尝试尽可能安全地连接的事实。

这就是我们最终解决的问题,即SSL /非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; }