首页 文章

如何通过LDAP SSL验证Active Directory信誉?

提问于
浏览
14

我正在尝试使用.NET 3.5 System.DirectoryServices.AccountManagement 命名空间来验证针对我们的Active Directory LDAP服务器 over an SSL encrypted LDAP connection 的用户凭据 . 这是示例代码:

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 .

有没有人通过SSL工作 ValidateCredentials(...) ?你能解释一下吗?或者是否有另一种/更好的方法可以安全地验证AD / LDAP凭据?

4 回答

  • 0

    感谢一位同事,我能够使用 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块来控制决策逻辑感到很兴奋,但它的作用是什么 . :/

  • 2

    也许这是另一种方式 . 验证凭据中没有任何异常 . ContextOptions必须正确设置 .

    默认值:

    ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing

    添加Ssl:

    ContextOptions.Negotiate | 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);
    }
    
  • 0

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

    我怀疑,根据我所知道的 LdapConnection 方法以及您省略了回调函数的事实,您没有验证您的服务器证书 . 这是一个麻烦的工作, ValidateCredentials 是免费的 . 可能不是什么大不了的事,但却是一个安全漏洞 .

  • 14

    我知道这是旧的,但对于任何遇到这种情况的人来说:

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

    但是,如果存在(受信任的?) client certificate ,则会隐式绑定LDAP连接,并且不再启用快速绑定 . PrincipalContext不考虑这种情况,并且因意外 DirectoryOperationException 而失败 .

    Workaround: 要尽可能支持SSL,但要有后备,请先使用默认选项调用 ValidateCredentials(...) (即无选项) . 如果使用 DirectoryOperationException 失败,请再次指定 ContextOptions (Negotiate | Sealing | Signing),这是 ValidateCredentials 内部为预期的 LdapException 做的事情 .

相关问题