65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 LdapConnection 和自定义证书验证进行 eDirectory 身份验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (18投票s)

2007年6月7日

3分钟阅读

viewsIcon

107445

downloadIcon

1710

本文解释了如何使用 LdapConnection 类通过 LDAPS 验证用户身份,并执行自定义证书验证

Screenshot - ldapconnection.png

引言

本文解释了如何使用 System.DirectoryServices.Protocols.LdapConnection 类通过 LDAPS 验证用户身份,并执行自定义证书验证。

背景

最近,我在使用 System.DirectoryServices.DirectoryEntry 连接到 Novell eDirectory 服务器时遇到了问题,因为该证书是自签名证书。在 ASP.NET 应用程序中运行时,不会检查机器级别的证书存储。因此,即使自签名证书位于受信任的存储中,DirectoryEntry 仍然拒绝建立连接。

LdapConnection 类是这种情况下的更好选择,因为它允许用户手动验证证书。 请注意,当在 Windows Forms 应用程序中运行时,DirectoryEntry 方法可以很好地与受信任的自签名证书一起使用。 可以在这里找到使用 DirectoryEntry 连接到 eDirectory 的一个很好的例子。

使用代码

该示例为了简单起见使用了 Login 控件。 我建议在“现实世界”中创建一个自定义的 MembershipProvider。 以下示例代码用于通过安全的 LDAP 连接到 Novell eDirectory 服务器。 但是,只要使用正确的服务器/端口/根 DN,该代码应该可以与其他目录提供程序一起正常工作。

另请记住,如果您不使用 LDAPS,请省略 con.SessionOptions.SecureSocketLayer = true 行。 但是,如果您不使用 LDAPS,那么您不妨使用 DirectoryEntry

连接和身份验证

首先,我们设置我们的 LdapConnection 类。 我们指定将通过 SSL 连接的服务器的地址和端口,设置证书回调(稍后会详细介绍),并提供用于身份验证的默认凭据。

此示例使用 eDirectory 的“无上下文登录”功能,因此允许使用空白凭据。 根据您的 LDAP 服务器,您可能需要指定凭据来搜索目录。 另请注意,如果未指定端口,则将使用默认值 389。

LdapConnection con = new LdapConnection(new LdapDirectoryIdentifier(
    "EDIRECTORYSERVER:636"));
con.SessionOptions.SecureSocketLayer = true;
con.SessionOptions.VerifyServerCertificate = 
    new VerifyServerCertificateCallback(ServerCallback);
con.Credential = new NetworkCredential(String.Empty, String.Empty);
con.AuthType = AuthType.Basic;

现在我们绑定初始连接。 如果 con.Bind() 执行时不抛出异常,则指定的服务器和凭据有效。

using (con)
{
    con.Bind();

下一步是搜索用户的完全限定的专有名称。 这是一个必要的步骤,因为当用户提供他们的用户名时,他们没有提供他们在目录中的名称的完整上下文; 即,提供 jlennon 而不是 cn=jlennon,ou=Beatles,ou=Artists,o=AppleRecordsLDAPDirectory

首先,我们准备 SearchRequest 对象。 我们指定根 DN、搜索过滤器和搜索范围。 然后我们发送请求。

    SearchRequest request = new SearchRequest(
        "o=LDAPRoot",
        "(&(objectClass=Person)(uid=" + Login1.UserName + "))", 
        SearchScope.Subtree);

    SearchResponse response = (SearchResponse)con.SendRequest(request);

如果我们走到这一步而没有抛出异常,我们知道指定的根 DN 和搜索过滤器是有效的。 如果两者都无效,将抛出 DirectoryOperationException

现在我们可以从搜索结果中提取 DN。 如果您想提供“没有此用户名”消息,您可以检查 response.Entries.Count > 0。 如果提供的用户名不存在,将在下一行抛出 ArgumentOutOfRangeException

    SearchResultEntry entry = response.Entries[0];
    string dn = entry.DistinguishedName;

现在我们有了用户的完整 DN,我们可以检查给定的密码是否有效。 我们在 LdapConnection 对象上设置一个新的 NetworkConnection 并重新绑定。 如果提供的密码无效,con.Bind() 将抛出 LdapException

    con.Credential = new NetworkCredential(dn, Login1.Password);
    con.Bind();
}

如果我们走到这一步,我们就成功通过身份验证了! 我们现在可以使用 SearchRequest 搜索组成员身份等。但是,这超出了本示例的范围。

VerifyServerCertificateCallback

这应该不需要解释。 我们只需从磁盘加载证书文件,并将其与服务器提供的证书进行比较。 生产代码应处理与读取证书相关的异常:找不到文件、访问被拒绝等。如果您真的信任服务器,您可以省略所有这些,只需 return true。 ;)

public static bool ServerCallback(
    LdapConnection connection, X509Certificate certificate)
{
    try
    {
        X509Certificate expectedCert =
            X509Certificate.CreateFromCertFile(
            "C:\\certificates\\certificate.cer");

        if (expectedCert.Equals(certificate))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    catch (Exception ex)
    {
        return false;
    }
}

历史

  • 2007 年 6 月 6 日 - 初始版本
© . All rights reserved.