LdapConnection与PrincipalContext
我有以下两种使用LDAP和LDAPSvalidation用户的实现,我想知道哪个更好/更正确。 对于记录,这两个都适用于SSL和非SSL连接。
我也很好奇,因为在Non-SSL PrincipalContext
版本上使用Wireshark观看时,我仍然看到端口636上的流量。在四种组合中( Non-SSL LdapConnection
, SSL LdapConnection
, Non-SSL PrincipalContext
, SSL 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
为您处理检查。
总而言之, LdapConnection
和PrincipalContext
提供了非常类似的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; }