15

我正在尝试使用 .NET 3.5命名空间通过 SSL 加密的 LDAP 连接System.DirectoryServices.AccountManagement针对我们的 Active Directory LDAP 服务器验证用户凭据。这是示例代码:

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:389", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
    return pc.ValidateCredentials(_username, _password);
}

此代码在不安全的 LDAP(端口 389)上运行良好,但我宁愿不以明文形式传输用户/密码组合。但是当我更改为 LDAP + SSL(端口 636)时,出现以下异常:

System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
  at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
  at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
  at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
  at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
  at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)
  at (my code)

端口 636 用于其他活动,例如查找该 LDAP/AD 条目的非密码信息......

UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, _username)

...所以我知道这不是我的 LDAP 服务器的 SSL 设置,因为它可以通过 SSL 进行其他查找。

有没有人接到ValidateCredentials(...)要求通过 SSL 工作的电话?你能解释一下怎么做吗?还是有另一种/更好的方法来安全地验证 AD/LDAP 凭据?

4

4 回答 4

15

System.DirectoryServices.Protocols感谢一位同事,我能够使用命名空间验证凭据。这是代码:

// See http://support.microsoft.com/kb/218185 for full list of LDAP error codes
const int ldapErrorInvalidCredentials = 0x31;

const string server = "sd.example.com:636";
const string domain = "sd.example.com";

try
{
    using (var ldapConnection = new LdapConnection(server))
    {
        var networkCredential = new NetworkCredential(_username, _password, domain);
        ldapConnection.SessionOptions.SecureSocketLayer = true;
        ldapConnection.AuthType = AuthType.Negotiate;
        ldapConnection.Bind(networkCredential);
    }

    // If the bind succeeds, the credentials are valid
    return true;
}
catch (LdapException ldapException)
{
    // Invalid credentials throw an exception with a specific error code
    if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials))
    {
        return false;
    }

    throw;
}

我不喜欢使用 try/catch 块来控制决策逻辑,但它确实有效。:/

于 2012-06-01T15:32:06.283 回答
3

也许这是另一种方式。验证凭据没有什么异常。ContextOptions 必须正确设置。

默认值:

ContextOptions.协商 | ContextOptions.Signing | ContextOptions.Sealing

添加 SSL:

ContextOptions.协商 | ContextOptions.Signing | ContextOptions.Sealing | ContextOptions.SecureSocketLayer

ContextOptions.Negotiate 或 ContextOptions.SimpleBind 是必需的。或者您的服务器需要执行身份验证的任何内容。ContextOptions 仅支持 OR 位对位。

您也可以尝试在 ValidateCredentials 方法中直接设置 ContextOptions。

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate | ContextOptions.SecureSocketLayer))
{
    return pc.ValidateCredentials(_username, _password);
}

或者

using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
    return pc.ValidateCredentials(_username, _password, ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);
}
于 2014-03-12T17:44:15.667 回答
0

对我来说,ValidateCredentials 方法工作得很好。我发现问题出在托管 AD 的服务器上(我正在使用 AD LDS)。您需要将服务器证书与 AD 实例相关联。因此,如果您的实例名为“MyAD”​​(或 ActiveDirectoryWebService),您需要打开 MMC,进入“证书”模块,选择“服务帐户”,然后从列表中选择“MyAD”​​。从那里您可以将 SSL 证书添加到“MyAD”​​个人存储中。这最终启动了 SSL 处理。

我怀疑,根据我对LdapConnection方法的了解以及您省略了回调函数的事实,您没有验证您的服务器证书。这是一项繁琐的工作,而ValidateCredentials是免费的。可能没什么大不了的,但仍然存在安全漏洞。

于 2017-02-02T21:12:03.963 回答
0

我知道这已经过时了,但是对于再次遇到此问题的任何人:

PrincipalContext.ValidateCredentials(...),默认情况下,尝试打开 SSL 连接 ( ldap_init(NULL, 636)),然后设置选项LDAP_OPT_FAST_CONCURRENT_BIND

但是,如果存在(受信任的?)客户端证书,则 LDAP 连接是隐式绑定的,并且无法再启用快速绑定。PrincipalContext 不考虑这种情况,并因意外而失败DirectoryOperationException

解决方法:要尽可能支持 SSL,但有一个备用方案,请ValidateCredentials(...)首先使用默认选项(即没有选项)调用。如果DirectoryOperationException使用. ContextOptions_ ValidateCredentials_LdapException

于 2018-03-15T22:24:54.263 回答