2013-10-25 3 views
7

У меня есть следующие две реализации аутентификации пользователей с LDAP и LDAPS, и мне было интересно, что было лучше/правильнее. Для записи обе эти функции работают как с SSL, так и с не-SSL-соединениями.LdapConnection vs. PrincipalContext

Я тоже любопытно, потому что при просмотре с Wireshark на версии Non-SSL PrincipalContext, я все еще вижу трафик на порт 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; 
+0

Вы пытались использовать ответ @sindilevich? любое решение об этом? – Kiquenet

ответ

4

@ DTI-Matt, в приведенных выше примерах, можно использовать VerifyServerCertificate функцию обратного вызова, которая всегда возвращает true. Это, по сути, не соответствует цели подключения к LDAP через SSL, поскольку проверка подлинности не выполняется.

Пока вы можете осуществить реальную проверку сертификата с использованием X509Chain и/или X509Certificate2 классов, кажется, PrincipalContext обрабатывает чеки для вас.

Подводя итог, как LdapConnection, так и PrincipalContext обеспечивают очень схожую функциональность в средствах подключения к LDAP-серверу через обычное или SSL-соединение. Вы должны поставить LdapConnection намного больше рукописного кода, чтобы он работал правильно. С другой стороны, PrincipalContext дает вам такую ​​же функциональность, что и меньше кода для записи вручную.

Отметим, что соединения с портом 636 (ваш порт по умолчанию через LDAP по протоколу SSL) по протоколу non-SSL PrincipalContext могут быть объяснены тем фактом, что этот класс пытается подключиться как можно более безопасно.

0

Это то, что мы закончили тем, что работает над 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; 
} 
Смежные вопросы