2012-06-01 9 views
14

Sto provando a utilizzare lo spazio dei nomi .NET 3.5 System.DirectoryServices.AccountManagement per convalidare le credenziali dell'utente sul server LDAP di Active Directory su una connessione LDAP crittografata SSL. Ecco il codice di esempio:Come convalidare i credenziali di Active Directory su LDAP + SSL?

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:389", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate)) 
{ 
    return pc.ValidateCredentials(_username, _password); 
} 

Questo codice funziona bene su LDAP non protetto (porta 389), ma preferirei non trasmetto una combinazione utente/passaggio in chiaro. Ma quando cambio a LDAP + SSL (porta 636), ottengo la seguente eccezione:

System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests. 
    at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error) 
    at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind() 
    at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions) 
    at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password) 
    at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password) 
    at (my code) 

Port 636 funziona per altre attività, come ad esempio la ricerca delle informazioni non-password per tale voce LDAP/AD ...

UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, _username) 

... così io so che non è messa a punto del mio SSL server LDAP, poiché funziona su SSL per altre ricerche.

Qualcuno ha ottenuto la chiamata ValidateCredentials(...) per funzionare su SSL? Puoi spiegare come? O c'è un altro/miglior modo per validare in modo sicuro le credenziali AD/LDAP?

+0

Ecco un articolo di MSDN per la risoluzione dei problemi di LDAP su SSL: http://support.microsoft.com/kb/938703 – CAbbott

+0

Grazie per il collegamento. Ma di nuovo posso comunicare su LDAPS (porta 636) bene per tutte le altre query LDAP che ho eseguito. Sembra qualcosa di insolito su 'ValidateCredentials()'. Vedrò comunque l'articolo in maggiore dettaglio. –

+0

Le password devono essere trasmesse in chiaro - non con hash - su una connessione protetta a un server che supporta i controlli della qualità della password e della cronologia delle password a meno che il client LDAP non fornisca la verifica della password e della cronologia della password, altrimenti il ​​server non sarà in grado di qualità e storia. –

risposta

14

Sono riuscito a convalidare le credenziali utilizzando lo spazio dei nomi System.DirectoryServices.Protocols, grazie a un collega. Ecco il codice:

// See http://support.microsoft.com/kb/218185 for full list of LDAP error codes 
const int ldapErrorInvalidCredentials = 0x31; 

const string server = "sd.example.com:636"; 
const string domain = "sd.example.com"; 

try 
{ 
    using (var ldapConnection = new LdapConnection(server)) 
    { 
     var networkCredential = new NetworkCredential(_username, _password, domain); 
     ldapConnection.SessionOptions.SecureSocketLayer = true; 
     ldapConnection.AuthType = AuthType.Negotiate; 
     ldapConnection.Bind(networkCredential); 
    } 

    // If the bind succeeds, the credentials are valid 
    return true; 
} 
catch (LdapException ldapException) 
{ 
    // Invalid credentials throw an exception with a specific error code 
    if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials)) 
    { 
     return false; 
    } 

    throw; 
} 

Io non sono entusiasta con l'utilizzo di un blocco try/catch per controllare decisioning logica, ma è ciò che funziona. :/

1

Forse questo è un altro modo. Non c'è nulla di insolito nelle credenziali di convalida. Il ContextOptions deve essere impostato correttamente.

Valore di default:

ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing

Aggiungere Ssl:

ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing | ContextOptions.SecureSocketLayer

ContextOptions.Negotiate o ContextOptions.SimpleBind è richiesto. O qualunque sia il tuo server ha bisogno di eseguire l'autenticazione. ContextOptions supporta solo OR bit-bit.

Si potrebbe anche provare a impostare le proprietà ContextOptions direttamente in questo modo nel metodo ValidateCredentials.

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate | ContextOptions.SecureSocketLayer)) 
{ 
    return pc.ValidateCredentials(_username, _password); 
} 

O

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate)) 
{ 
    return pc.ValidateCredentials(_username, _password, ContextOptions.Negotiate | ContextOptions.SecureSocketLayer); 
} 
+0

Vedo che dici "O qualunque sia il tuo server per eseguire l'autenticazione". Come posso sapere di cosa ha bisogno un server per l'autenticazione? Sto lavorando su un server che è stato precedentemente impostato con alcune opzioni, ma non so cosa sono ora. Posso controllarli in qualche modo? –

0

Per me, il metodo ValidateCredentials funziona bene. Il problema, ho trovato, era sul server che ospita l'AD (sto usando AD LDS). È necessario associare il certificato del server all'istanza AD. Pertanto, se l'istanza è stata chiamata "MyAD" (o ActiveDirectoryWebService), è necessario aprire la console MMC, eseguire lo snap nel modulo "Certificati", selezionare "Account servizio" e quindi selezionare "MyAD" dall'elenco. Da lì è possibile aggiungere il certificato SSL nell'archivio personale "MyAD". Questo finalmente ha dato il via all'elaborazione SSL.

Sospetto, da quello che so del metodo LdapConnection e dal fatto che si è omessa la funzione di callback, che non si sta convalidando il certificato del server. È un lavoro disordinato e ValidateCredentials lo fa gratuitamente. Probabilmente non è un grosso problema, ma un buco di sicurezza nessuno.