LdapConnection 与 PrincipalContext

LdapConnection vs. PrincipalContext(LdapConnection 与 PrincipalContext)
本文介绍了LdapConnection 与 PrincipalContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我有以下两种使用 LDAP 和 LDAPS 对用户进行身份验证的实现,我想知道哪个更好/更正确.作为记录,这两者都适用于 SSL 和非 SSL 连接.

我也很好奇,因为在 Non-SSL PrincipalContext 版本上使用 Wireshark 观看时,我仍然看到端口 636 上的流量.四种组合(Non-SSL LdapConnectionSSL LdapConnectionNon-SSL PrincipalContextSSL PrincipalContext)它是唯一一个在端口 389 和 636 上都有流量的只是其中之一.这可能是什么原因造成的?

LDAP 连接方法:

bool userAuthenticated = false;var domainName = 域名;如果(使用SSL){域名 = 域名 + ":636";}尝试{使用 (var ldap = new LdapConnection(domainName)){var networkCredential = new NetworkCredential(username, password, domainName);ldap.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback((con, cer) => true);ldap.SessionOptions.SecureSocketLayer = useSSL;ldap.SessionOptions.ProtocolVersion = 3;ldap.AuthType = AuthType.Negotiate;ldap.Bind(networkCredential);}//如果绑定成功,我们有一个有效的用户/通行证.userAuthenticated = true;}捕获(LdapException ldapEx){//错误代码 0x31 表示凭据无效,其他任何内容都将被捕获.if (!ldapEx.ErrorCode.Equals(0x31)){扔;}}返回 userAuthenticated;

PrincipalContext 方法:

bool userAuthenticated = false;var domainName = 域名;如果(使用SSL){域名 = 域名 + ":636";ContextOptions 选项 = ContextOptions.SimpleBind |ContextOptions.SecureSocketLayer;使用 (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName, null, options)){userAuthenticated = pc.ValidateCredentials(username, password, options);}}别的{使用 (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName)){userAuthenticated = pc.ValidateCredentials(username, password);}}返回 userAuthenticated;

解决方案

@DTI-Matt,在上面的例子中,你使用了总是返回 trueVerifyServerCertificate 回调.这本质上违背了通过 SSL 连接到 LDAP 的目的,因为没有执行真正的证书检查.

虽然您可以使用 X509Chain 和/或 X509Certificate2 类实现真正的证书检查,但似乎 PrincipalContext 会为您处理检查.

总而言之,LdapConnectionPrincipalContext 都提供非常相似的功能,通过普通或 SSL 连接连接到 LDAP 服务器.您必须提供 LdapConnection 更多的手写代码才能使其正常工作.另一方面,PrincipalContext 为您提供相同的功能,而手动编写的代码更少.

请注意,通过非 SSL PrincipalContext 连接到端口 636(您的默认 LDAP over SSL 端口)可能是由于此类尝试尽可能安全地连接.>

I have the following two implementations of authenticating users with LDAP and LDAPS and I was wondering which was better / more correct. For the record, both of these work on both SSL and non-SSL connections.

I'm also curious because when watching with Wireshark on the Non-SSL PrincipalContext version, I still see traffic on Port 636. Of the four combinations (Non-SSL LdapConnection, SSL LdapConnection, Non-SSL PrincipalContext, SSL PrincipalContext) it is the only one that has traffic on both Port 389 and 636 instead of just one or the other. What could be causing this?

LDAP Connection Method:

bool userAuthenticated = false;
var domainName = DomainName;

if (useSSL)
{
  domainName = domainName + ":636";
}

try
{
  using (var ldap = new LdapConnection(domainName))
  {
    var networkCredential = new NetworkCredential(username, password, domainName);
    ldap.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback((con, cer) => true);
    ldap.SessionOptions.SecureSocketLayer = useSSL;
    ldap.SessionOptions.ProtocolVersion = 3;
    ldap.AuthType = AuthType.Negotiate;
    ldap.Bind(networkCredential);
  }

  // If the bind succeeds, we have a valid user/pass.
  userAuthenticated = true;
}
catch (LdapException ldapEx)
{
  // Error Code 0x31 signifies invalid credentials, anything else will be caught outside.
  if (!ldapEx.ErrorCode.Equals(0x31))
  {
    throw;
  }
}

return userAuthenticated;

PrincipalContext Method:

bool userAuthenticated = false;
var domainName = DomainName;

if (useSSL)
{
  domainName = domainName + ":636";
  ContextOptions options = ContextOptions.SimpleBind | ContextOptions.SecureSocketLayer;

  using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName, null, options))
  {
    userAuthenticated = pc.ValidateCredentials(username, password, options);
  }
}
else
{
  using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName))
  {
    userAuthenticated = pc.ValidateCredentials(username, password);
  }
}

return userAuthenticated;

解决方案

@DTI-Matt, in the examples above, you use VerifyServerCertificate callback that always returns true. This, essentially, defies the purpose of connecting to LDAP over SSL, as no real certificate check is performed.

While you could implement a real certificate check using X509Chain and/or X509Certificate2 classes, it seems PrincipalContext handles the checks for you.

To summarize, both LdapConnection and PrincipalContext provide very similar functionality, in means of connecting to an LDAP server over plain or SSL connection. You have to supply LdapConnection much more hand-written code for it to work properly. On the other hand, PrincipalContext gives you the same functionality with less code to write by hand.

As a note, connections to port 636 (your default LDAP over SSL port), by non-SSL PrincipalContext may be explained by the fact this class tries to connect as secure as possible.

这篇关于LdapConnection 与 PrincipalContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

What#39;s the difference between retrieving WindowsPrincipal from WindowsIdentity and Thread.CurrentPrincipal?(从 WindowsIdentity 和 Thread.CurrentPrincipal 检索 WindowsPrincipal 之间有什么区别?)
How do I find a user#39;s Active Directory display name in a C# web application?(如何在 C# Web 应用程序中查找用户的 Active Directory 显示名称?)
How to use Servicestack Authentication with Active Directory/Windows Authentication?(如何在 Active Directory/Windows 身份验证中使用 Servicestack 身份验证?)
How can I authenticate against Active Directory in Nancy?(如何在 Nancy 中对 Active Directory 进行身份验证?)
How to get a username in Active Directory from a display name in C#?(如何从 C# 中的显示名称获取 Active Directory 中的用户名?)
Oauth 2 token for Active Directory accounts(Active Directory 帐户的 Oauth 2 令牌)