I'm trying to get the root DirectoryEntry from LDAP so I can show a nice graphical tree view of it.
It all works beautifully under normal connections but I can't get it to work with SSL.
var root = this.checkBoxSSL.Checked
? new DirectoryEntry("LDAP://" + this.textBoxServer.Text,
this.textBoxUsername.Text,
this.textBoxPassword.Text,
AuthenticationTypes.SecureSocketsLayer)
: new DirectoryEntry("LDAP://" + this.textBoxServer.Text,
this.textBoxUsername.Text,
this.textBoxPassword.Text);
var dn = root.Properties["distinguishedName"].Value;
And so on...
But I get a "Server not operational" exception. It all seems to go down to the bind process. Based on internet research it might be a problem with the certificate and/or the Authentication method (NTLM, etc).
So how can I get a working DirectoryEntry over SSL?
I am open to alternative solutions, as long as I can retrieve all the LDAP Properties of the nodes I need. (Root, DC, OU, CN, Groups and Users)
EDIT: As it seems the problem comes down to the SSL certificate. We only have a self-signed cert atm. And this seems to be rejected by .NET by default. We're going to try this with a properly signed cert later on but it's likely I need to be able to handle selfsigned ones too.
This is where my knowledge about certificates has limits. I'm currently exploring a different code solution because it seems to be the only one that allows me to influence the whole certificate handling:
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2();
cert.Import("..\\..\\test certificate.cer");
LdapConnection con = new LdapConnection("ip:636");
con.Credential = new NetworkCredential("un", "pw");
con.AuthType = AuthType.Ntlm;
con.SessionOptions.SecureSocketLayer = true;
con.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback((ldapcon, cer) => {
var cer2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(cer);
StringBuilder strb = new StringBuilder();
strb.AppendFormat("{0} {1} matches: {2}\n", "Subject", cert.Subject, cert.Subject.Equals(cer2.Subject));
strb.AppendFormat("{0} {1} matches: {2}\n", "Cert Hash", cert.GetCertHashString(), Enumerable.SequenceEqual<byte>(cer.GetCertHash(), cert.GetCertHash()));
strb.AppendFormat("{0} matches: {2}\n", "Public Key", cert.GetPublicKeyString(), Enumerable.SequenceEqual<byte>(cer.GetPublicKey(), cert.GetPublicKey()));
strb.AppendFormat("{0}: {1}, {2}", "Verification", cert.Verify(), cer2.Verify());
var res = MessageBox.Show(strb.ToString(),
"Allow certificate?", MessageBoxButtons.YesNo);
return res == System.Windows.Forms.DialogResult.Yes;
});
con.Bind();
Essentially, if that VerifyServerCertificateCallback returns true then the connection succeeds, if it returns falls the connection fails with the same exception as with any other solution I've tried.
Curiously, neither installing the AD certificate or the root certificate of the AD controller didn't help the other solutions but it does change the result of the Verify() method.
What kind of checks do I have to perform on the certificate in the callback to maintain the sanctity of the SSL connection?
LDAPConnectionyou have here in your last example? - Markus