2013-10-25 8 views
7

Ho le seguenti due implementazioni di autenticazione degli utenti con LDAP e LDAPS e mi chiedevo quale fosse il migliore/più corretto. Per la cronaca, entrambi funzionano su entrambe le connessioni SSL e non SSL.LdapConnection vs. PrincipalContext

Sono anche curioso perché quando si guarda con Wireshark sulla versione Non-SSL PrincipalContext, continuo a vedere il traffico sulla porta 636. Dei quattro combinazioni (Non-SSL LdapConnection, SSL LdapConnection, Non-SSL PrincipalContext, SSL PrincipalContext) è l'unico che ha il traffico su entrambi Porta 389 e 636 invece di uno solo o l'altro. Che cosa potrebbe causare questo?

LDAP metodo di connessione:

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 Metodo:

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

hai provato a utilizzare @sindilevich risposta? qualche soluzione al riguardo? – Kiquenet

risposta

4

@ DTI-Matt, negli esempi di cui sopra, si utilizza VerifyServerCertificate callback che restituisce sempre true. Questo, in sostanza, sfugge allo scopo di connettersi a LDAP su SSL, poiché non viene eseguito alcun controllo reale dei certificati.

Mentre si potrebbe implementare un vero e proprio controllo certificato utilizzando X509Chain e/o X509Certificate2 classi, sembra PrincipalContext gestisce i controlli per voi.

Per riassumere, sia LdapConnection e PrincipalContext forniscono funzionalità molto simili, in mezzo alla connessione a un server LDAP tramite connessione semplice o SSL. È necessario fornire LdapConnection codice molto più scritto a mano per farlo funzionare correttamente. D'altra parte, PrincipalContext offre la stessa funzionalità con meno codice da scrivere a mano.

Come nota, le connessioni alla porta 636 (la porta LDAP predefinita su SSL), da non SSL PrincipalContext possono essere spiegate dal fatto che questa classe cerca di connettersi nel modo più sicuro possibile.

0

Questo è quello che abbiamo concluso che funziona su 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; 
}