【问题标题】:LdapConnection vs. PrincipalContextLdapConnection 与 PrincipalContext
【发布时间】:2013-11-04 22:27:39
【问题描述】:

我有以下两种使用 LDAP 和 LDAPS 对用户进行身份验证的实现,我想知道哪个更好/更正确。作为记录,这些都适用于 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;

【问题讨论】:

  • 您尝试过使用@sindilevich 答案吗?有什么解决办法吗?

标签: c# .net ssl active-directory ldap


【解决方案1】:

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

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

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

请注意,通过非 SSL PrincipalContext 连接到端口 636(您的默认 LDAP over SSL 端口)可能是因为此类尝试尽可能安全地连接。

【讨论】:

    【解决方案2】:

    这就是我们最终在 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-13
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多