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






4.74/5 (18投票s)
2007年6月7日
3分钟阅读

107445

1710
本文解释了如何使用 LdapConnection 类通过 LDAPS 验证用户身份,并执行自定义证书验证
引言
本文解释了如何使用 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 日 - 初始版本