Windows 服务 LdapException:LDAP 服务器不可用

问题描述 投票:0回答:2

我有一个 Windows 服务,它通过 WCF 向 Windows 窗体应用程序提供数据。该服务还负责用户身份验证,通过公司 Active Directory 服务器使用 LDAP 验证用户密码。

问题是它工作了几周(甚至几个月),然后发生了一些事情并且 LDAP 用户身份验证失败并出现以下异常,直到我重新启动服务:

System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. 
---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.     
at System.DirectoryServices.Protocols.LdapConnection.Connect()     
at System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID)     
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)     
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request)     
at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)    
 --- End of inner exception stack trace ---     
 at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)     
 at System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()     
 at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)     
 at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String userName, String password)     
 at SMSTModel.Authentication.ActiveDirectory.IsUserAllowed(String username, String password)

服务重启解决了问题。

public static bool IsUserAllowed(string username, string password)
{
    String localDomain = Domain.GetComputerDomain().Name;
    string userDomain = null;
    string user = username;
    if (user.Contains(@"\"))
    {
        userDomain = user.Substring(0, user.IndexOf("\\"));
        user = user.Substring(user.IndexOf("\\") + 1);
    }

    userDomain = userDomain != null ? userDomain : localDomain;
    using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, userDomain, user, password))
    {
        bool credOk = pc.ValidateCredentials(user, password);
        if (!credOk)
            return false;
        using (UserPrincipal userP = UserPrincipal.FindByIdentity(pc, user))
        {
            if (userP != null)
            {
                using (PrincipalContext pc1 = new PrincipalContext(ContextType.Domain, localDomain))
                {
                    using (GroupPrincipal groupPrincipal = new GroupPrincipal(pc1))
                    {
                        groupPrincipal.Name = "APP_*";
                        using (PrincipalSearcher principalSearcher = new PrincipalSearcher(groupPrincipal))
                            foreach (Principal found in principalSearcher.FindAll())
                            {
                                if (found.Name == "APP_Group" && found is GroupPrincipal && userP.IsMemberOf((GroupPrincipal)found))
                                {
                                    return true;
                                }
                            }
                    }
                }
            }
        }
    }

    return false;
}

知道为什么会发生这种情况以及如何解决它吗?

c# .net active-directory ldap principalcontext
2个回答
3
投票

看起来异常发生在这里:

using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, userDomain, user, password))

那么你知道所使用的

userDomain
是什么吗?您的环境中似乎可能有多个域,那么您的所有域都会出现这种情况,还是只有一个域会出现这种情况?

在我们的环境中,我见过我们的 AD 管理员停用域控制器的情况,但由于某种原因该服务器仍然显示在 DNS 中。换句话说,如果我在命令行中进行 DNS 查找:

nslookup example.com

其中一个 IP 用于已退役的 DC。

您的情况有这种可能性。如果它选择了错误的 IP 地址,则重新启动应用程序将使其执行另一次 DNS 查找,这可能会在列表顶部返回不同的 IP 地址,并且一切都会再次正常。

要弄清楚这一点,您确实必须观察它停止工作时发生的情况。如果您尚未安装 Wireshark,请在您的服务器上安装。当它停止工作时,使用 Wireshark 通过端口 389(默认 LDAP 端口)查找流量,并查看它尝试连接到哪个 IP。


0
投票

这里也一样。这与尝试 LDAP 时的上下文绑定有关。

我们有解决方案吗?

© www.soinside.com 2019 - 2024. All rights reserved.