LdapConnection vs. PrincipalContext

I have the following two implementations of authenticating users with LDAP and LDAPS and I was wondering which was better / more correct. For the record, both of these work on both SSL and non-SSL connections.

I'm also curious because when watching with Wireshark on 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 ) it is the only one that has traffic on both Port 389 and 636 instead of just one or the other. What could be causing 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 Method:

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, in the examples above, you use VerifyServerCertificate callback that always returns true . This, essentially, defies the purpose of connecting to LDAP over SSL, as no real certificate check is performed.

While you could implement a real certificate check using X509Chain and/or X509Certificate2 classes, it seems PrincipalContext handles the checks for you.

To summarize, both LdapConnection and PrincipalContext provide very similar functionality, in means of connecting to an LDAP server over plain or SSL connection. You have to supply LdapConnection much more hand-written code for it to work properly. On the other hand, PrincipalContext gives you the same functionality with less code to write by hand.

As a note, connections to port 636 (your default LDAP over SSL port), by non-SSL PrincipalContext may be explained by the fact this class tries to connect as secure as possible.


这就是我们通过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;
}
链接地址: http://www.djcxy.com/p/75142.html

上一篇: GITHub API问题与文件上传

下一篇: LdapConnection与PrincipalContext