我有以下两种使用LDAP和LDAPS验证用户的实现,我想知道哪个更好/更正确。对于记录,这两个都适用于SSL和非SSL连接。
我也很好奇,因为在Non-SSL PrincipalContext
版本上观看Wireshark时,我仍然看到636端口的流量。在四种组合中Non-SSL LdapConnection
,SSL LdapConnection
,{{1 }},Non-SSL PrincipalContext
)它是唯一一个在端口389和636上都有流量而不是只有一个流量的流量。可能导致这种情况的原因是什么?
LDAP连接方法:
SSL PrincipalContext
PrincipalContext方法:
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;
答案 0 :(得分:5)
@ DTI-Matt,在上面的示例中,您使用始终返回VerifyServerCertificate
的{{1}}回调。这基本上违反了通过SSL连接到LDAP的目的,因为没有执行真正的证书检查。
虽然您可以使用true
和/或X509Chain
类实施真正的证书检查,但似乎X509Certificate2
会为您处理检查。
总而言之,PrincipalContext
和LdapConnection
都提供了非常类似的功能,通过普通或SSL连接连接到LDAP服务器。您必须提供PrincipalContext
更多手写代码才能正常工作。另一方面,LdapConnection
为您提供相同的功能,只需较少的代码即可手动编写。
作为注释,非SSL PrincipalContext
与端口636(您的默认LDAP over SSL端口)的连接可以通过此类尝试尽可能安全地连接来解释。
答案 1 :(得分:0)
这就是我们最终解决的问题,即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;
}