Prometto, questo sarà il mio ultimo post su questa particolare domanda. :)
Dopo un'altra settimana di ricerca e sviluppo, ho una buona soluzione a questo, e ha funzionato molto bene per me finora.
L'approccio è leggermente diverso dalla mia prima risposta, ma in generale è lo stesso concetto; utilizzando LdapConnection per forzare la convalida del certificato.
//I set my Domain, Filter, and Root-AutoDiscovery variables from the config file
string Domain = config.LdapAuth.LdapDomain;
string Filter = config.LdapAuth.LdapFilter;
bool AutoRootDiscovery = Convert.ToBoolean(config.LdapAuth.LdapAutoRootDiscovery);
//I start off by defining a string array for the attributes I want
//to retrieve for the user, this is also defined in a config file.
string[] AttributeList = config.LdapAuth.LdapPropertyList.Split('|');
//Delcare your Network Credential with Username, Password, and the Domain
var credentials = new NetworkCredential(Username, Password, Domain);
//Here I create my directory identifier and connection, since I'm working
//with a host address, I set the 3rd parameter (IsFQDNS) to false
var ldapidentifier = new LdapDirectoryIdentifier(ServerName, Port, false, false);
var ldapconn = new LdapConnection(ldapidentifier, credentials);
//This is still very important if the server has a self signed cert, a certificate
//that has an invalid cert path, or hasn't been issued by a root certificate authority.
ldapconn.SessionOptions.VerifyServerCertificate += delegate { return true; };
//I use a boolean to toggle weather or not I want to automatically find and query the absolute root.
//If not, I'll just use the Domain value we already have from the config.
if (AutoRootDiscovery)
{
var getRootRequest = new SearchRequest(string.Empty, "objectClass=*", SearchScope.Base, "rootDomainNamingContext");
var rootResponse = (SearchResponse)ldapconn.SendRequest(getRootRequest);
Domain = rootResponse.Entries[0].Attributes["rootDomainNamingContext"][0].ToString();
}
//This is the filter I've been using : (&(objectCategory=person)(objectClass=user)(&(sAMAccountName={{UserName}})))
string ldapFilter = Filter.Replace("{{UserName}}", UserName);
//Now we can start building our search request
var getUserRequest = new SearchRequest(Domain, ldapFilter, SearchScope.Subtree, AttributeList);
//I only want one entry, so I set the size limit to one
getUserRequest.SizeLimit = 1;
//This is absolutely crucial in getting the request speed we need (milliseconds), as
//setting the DomainScope will suppress any refferal creation from happening during the search
SearchOptionsControl SearchControl = new SearchOptionsControl(SearchOption.DomainScope);
getUserRequest.Controls.Add(SearchControl);
//This happens incredibly fast, even with massive Active Directory structures
var userResponse = (SearchResponse)ldapconn.SendRequest(getUserRequest);
//Now, I have an object that operates very similarly to DirectoryEntry, mission accomplished
SearchResultEntry ResultEntry = userResponse.Entries[0];
L'altra cosa che volevo da notare qui è che SearchResultEntry tornerà utente "attributi" invece di "proprietà".
Gli attributi vengono restituiti come matrici di byte, quindi è necessario codificarli per ottenere la rappresentazione di stringa. Fortunatamente System.Text.Encoding contiene una classe ASCIIEncoding nativa in grado di gestirli molto facilmente.
string PropValue = ASCIIEncoding.ASCII.GetString(PropertyValueByteArray);
E questo è tutto! Molto felice di aver finalmente capito.
Cheers!
Hi. Grazie per l'input, molto apprezzato. Sto anche arrivando alla conclusione che l'intero problema potrebbe essere affrontato in modo molto più affidabile utilizzando lo spazio dei nomi dei protocolli di livello inferiore. Quello che ho notato è che quando il certificato autofirmato viene correttamente aggiunto all'archivio certificati macchina locale posso impostare il callback VerifyServerCertificate per validare il certificato con esito positivo, qualcosa come "delegato (connessione LdapConnection, certificato X509Certificate) {return new X509Certificate2 (certificato) .Verify()} ", ma non ottengo ancora alcuna gioia con DirectoryEntry. – Andrew
Ho anche notato che durante gli eventi di sistema durante i tentativi di DirectoryEntry falliti ottengo quanto segue: "Il certificato ricevuto dal server remoto non contiene il nome previsto, quindi non è possibile determinare se ci stiamo connettendo al server corretto. Il nome del server che ci aspettavamo è MYSERVER.MYDOMAIN.CO.UK. La richiesta di connessione SSL non è riuscita. I dati allegati contengono il certificato del server. " Lo sto esaminando ora, ma penso che la risposta sia ancora lo spazio dei nomi dei protocolli per la massima fiducia e una minore dipendenza ambientale. – Andrew
Andrew, grazie per il commento. Sembra che stiamo lavorando per un obiettivo molto simile. L'errore che vedi negli eventi di sistema coincide con molte delle informazioni che ho letto sulla rete riguardo a chi viene rilasciato il certificato. Molti dei server che eseguono SSL con cui sto provando a interagire hanno un certificato che viene rilasciato su un dominio diverso da quello su cui sto legando in LdapConnection ... e questo certamente causa il fallimento di DirectoryEntry. – X3074861X