c# - 如何通过 SSL 从 LDAP 获取 DirectoryEntry?

标签 c# ssl active-directory

我正在尝试从 LDAP 获取根 DirectoryEntry,以便我可以显示它的漂亮图形 TreeView 。

它在正常连接下运行良好,但我无法让它与 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;

等等……

但我收到“服务器无法运行”异常。这一切似乎都归结为绑定(bind)过程。根据 Internet 研究,证书和/或身份验证方法(NTLM 等)可能有问题。

那么我怎样才能通过 SSL 获得有效的 DirectoryEntry?

我愿意接受替代解决方案,只要我可以检索我需要的节点的所有 LDAP 属性。 (根、DC、OU、CN、组和用户)

编辑: 看来问题出在 SSL 证书上。我们只有一个自签名证书 atm。而这似乎默认被 .NET 拒绝。稍后我们将使用正确签名的证书进行尝试,但我可能也需要能够处理自签名的证书。

这是我对证书的了解有限的地方。我目前正在探索一种不同的代码解决方案,因为它似乎是唯一允许我影响整个证书处理的解决方案:

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();

本质上,如果 VerifyServerCertificateCallback 返回 true 则连接成功,如果它返回失败则连接失败并出现与我尝试过的任何其他解决方案相同的异常。

奇怪的是,安装 AD 证书或 AD Controller 的根证书都没有帮助其他解决方案,但它确实改变了 Verify() 方法的结果。

我必须在回调中对证书执行何种检查以维护 SSL 连接的安全性?

最佳答案

我建议您使用 System.DirectoryServices.AccountManagement 中的 PrincipalContext。初始化看起来像这样:

PrincipalContext context = new PrincipalContext(
            ContextType.Domain, NAME_OF_THE_DOMAIN + ":636", 
            null, 
            ContextOptions.SecureSocketLayer | ContextOptions.Negotiate, 
            this.textBoxUsername.Text, 
            this.textBoxPassword.Text);

之后,您可以搜索 UserPrincipal 及其 DistinguishedName:

string dn = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, this.textBoxUsername.Text).DistinguishedName;

如果你想遍历 AD 树,只需在 PrincipalSearcher 的帮助下做这样的事情:

using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
    foreach (var result in searcher.FindAll())
    {
        DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;

        //DO watherever you want
    }
}

关于c# - 如何通过 SSL 从 LDAP 获取 DirectoryEntry?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28608542/

相关文章:

active-directory - 如何构建此 LDAP 连接字符串?

django - 为什么我的Django服务器只能本地访问?

php - Apple Production Push 服务不工作!

c# - 引用类型相等

c# - WPF 从 C# 代码设置文本框边框颜色

ssl - 有没有办法防止Unity中的javax.net.ssl.SSLHandshakeException因为服务器不支持SSLv3来防止poodle攻击?

java - 使用 Spring Security 获取通过 Active Directory 登录的用户的电子邮件地址

azure - 如何在azure中的单个应用程序上对多个事件目录用户进行身份验证

c# - 如何在 C++/CLI 中包装 C++ 接口(interface)(抽象类)?

C#:十进制 -> 可以精确存储的最大整数