如何通过SSL从LDAP获取DirectoryEntry?

Kem*_*eth 6 c# ssl active-directory

我正在尝试从LDAP获取根DirectoryEntry,以便我可以显示它的一个很好的图形树视图.

这一切在正常连接下都能很好地工作,但我无法使用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;
Run Code Online (Sandbox Code Playgroud)

等等...

但我得到一个"服务器无法运行"的例外.这一切似乎都归结为绑定过程.基于互联网研究,它可能是证书和/或身份验证方法(NTLM等)的问题.

那么如何才能通过SSL获得有效的DirectoryEntry?

我愿意接受替代解决方案,只要我可以检索所需节点的所有LDAP属性.(Root,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();
Run Code Online (Sandbox Code Playgroud)

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

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

我必须在回调中对证书执行哪些检查才能保持SSL连接的神圣性?

小智 7

布莱恩·德斯蒙德就快到了。您需要在 DirectoryEntry AuthenticationType 中设置 2 个标志:

AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.SecureSocketsLayer | 身份验证类型.安全

例子:

new DirectoryEntry("LDAP://" + this.textBoxServer.Text + ":636",
                    this.textBoxUsername.Text,
                    this.textBoxPassword.Text,
                    AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure)
Run Code Online (Sandbox Code Playgroud)

  • +1 也为我证实了 - `AuthenticationTypes` 是一个 `[flag]`。需要设置“SecureSocketsLayer”和“Secure”才能正常工作。 (2认同)

Cla*_*o P 5

我建议你使用PrincipalContextSystem.DirectoryServices.AccountManagement.初始化将如下所示:

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

之后你可以搜索a UserPrincipal和它DistinguishedName:

string dn = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, this.textBoxUsername.Text).DistinguishedName;
Run Code Online (Sandbox Code Playgroud)

如果你想通过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
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

首先,您应该确保您的帐户和密码可用。使用ldp.exe工具检查帐户是否可用。

那么也许您可以尝试如下所示,请使用 LDAP:// 而不是 LDAPS://

LdapConnection conn = new LdapConnection("xx1.bb.aa.com:636");
var op = conn.SessionOptions;
op.ProtocolVersion = 3;
op.SecureSocketLayer = true;
op.VerifyServerCertificate += delegate { return true; };

conn.AuthType = AuthType.Negotiate;
var cred = new NetworkCredential("accountname", "password");

//conn.Credential = cred;
try
{
    conn.Bind(cred);

    if (op.SecureSocketLayer)
    {
        Console.WriteLine("SSL for encryption is enabled - SSL information:");
    }
}
catch (Exception ex)
{

    throw;
}
Run Code Online (Sandbox Code Playgroud)

或者:

DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://xx1.bb.aa.com:636",
    "ldapsusername", "password", AuthenticationTypes.SecureSocketsLayer);

//directoryEntry.Options

DirectorySearcher searcher = new DirectorySearcher(directoryEntry)
{
    PageSize = int.MaxValue,
    Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=hp.wang))"
};

searcher.PropertiesToLoad.Add("sn");

var result = searcher.FindOne();

if (result == null)
{
    return; // Or whatever you need to do in this case
}

string surname;

if (result.Properties.Contains("sn"))
{
    surname = result.Properties["sn"][0].ToString();
}
Run Code Online (Sandbox Code Playgroud)