我正在尝试使用.NET 3.5 System.DirectoryServices.AccountManagement
命名空间来验证针对我们的Active Directory LDAP服务器通过SSL加密的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。
是否有人通过SSL进行ValidateCredentials(...)
调用?你能解释一下吗?或者是否有其他/更好的方法可以安全地验证AD / LDAP凭据?
答案 0 :(得分:14)
由于有同事,我能够使用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块来控制决策逻辑并不感到兴奋,但它是有效的。 :/
答案 1 :(得分:3)
也许这是另一种方式。验证凭据中没有任何异常。 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);
}
答案 2 :(得分:0)
对我来说,ValidateCredentials方法工作得很好。我发现问题出在托管AD的服务器上(我正在使用AD LDS)。您需要将服务器证书与AD实例相关联。因此,如果您的实例名为“MyAD”(或ActiveDirectoryWebService),则需要打开MMC,在“证书”模块中单击,选择“服务帐户”,然后从列表中选择“MyAD”。从那里,您可以将SSL证书添加到“MyAD”个人存储中。这最终使SSL处理工作陷入困境。
我怀疑,根据我所知道的 LdapConnection 方法以及您省略了回调函数的事实,您没有验证您的服务器证书。这是一个混乱的工作, ValidateCredentials 是免费的。可能不是什么大不了的事,但却是一个安全漏洞。
答案 3 :(得分:0)
我知道这已经过时了,但对于再次遇到此问题的人来说:
默认情况下, id
会尝试打开SSL连接(PrincipalContext.ValidateCredentials(...)
),然后设置选项ldap_init(NULL, 636)
。
但是,如果存在(受信任的?)客户端证书,则会隐式绑定LDAP连接,并且不再启用快速绑定。 PrincipalContext没有考虑这种情况,并且因意外LDAP_OPT_FAST_CONCURRENT_BIND
而失败。
解决方法:要尽可能支持SSL,但要进行后备,请先使用默认选项调用DirectoryOperationException
(即无选项)。如果此操作因ValidateCredentials(...)
而失败,请再次指定DirectoryOperationException
(协商|密封|签名),这是ContextOptions
内部为预期的ValidateCredentials
执行的操作。< / p>