猿问

通过 C# ASP.NET 更改 Active Directory LDAP 密码:无法读取配置

我们正在尝试通过 C# ASP.NET 4.5 应用程序更改 Active Directory 中的用户密码(我们将使用“Jane”作为示例用户),但我们收到以下错误。


Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied. (Exception from HRESULT: 0x80070547)


可以毫无问题地建立与远程(第 3 方)AD 服务器的连接,并且我们的服务用户已通过身份验证。也可以毫无问题地检索 Jane 的目录条目。


我们尝试更改/设置密码,同时作为 Jane 和我们的服务用户进行身份验证,两者都产生相同的错误(上图)。


下面是一个正在使用的代码示例。


using (var context = new PrincipalContext(ContextType.Domain, ServiceDomain, ServiceDefaultLocation, ContextOptions.Negotiate, ServiceUser, ServicePassword))

using (var identity = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Jane"))

{

    // identity.SetPassword("SomeNewPassword"); // also tried

    identity.ChangePassword("TheOldPassword", "SomeNewPassword"); // this is the error line

    identity.Save();

}

系统事件日志显示更改/设置密码审核失败,原因列为“登录期间发生错误”。身份验证包列出“MICROSOFT_AUTHENTICATION_PACKAGE_V1_0”。在此之前,我们有针对我们的服务用户的审核成功事件。


值得注意的是,它大约是。在我们收到错误前 20 秒,表明它可能是连接/超时问题,但是传出连接不受限制,并且我们的 IP 已在远程端列入白名单(再次,我们可以连接并检索用户条目)。不过,作为用户进行身份验证也可能需要很长时间(这仍然可以成功)。


我们的服务用户有权更改/设置其他用户的密码,但不能直接更改用户属性,因此我们被告知。


如果有任何其他信息可能有助于诊断问题,请告诉我。


慕仙森
浏览 485回答 3
3回答

宝慕林4294392

所以UserPrincipal.ChangePassword()会打电话:de.Invoke("ChangePassword", new object[] { oldPassword, newPassword });它在DirectoryEntry幕后使用。DirectoryEntry.Invoke()用于调用“本机 Active Directory 域服务对象上的方法”,这意味着这将最终使用本机 WindowsIADsUser::ChangePassword方法。备注说它使用 3 种方法之一:IADsUser::ChangePassword 的功能类似于IADsUser::SetPassword,因为它将使用三种方法之一来尝试更改密码。最初,如果与服务器建立了安全的 SSL 连接,则 LDAP 提供程序将尝试 LDAP 更改密码操作。如果此尝试失败,则 LDAP 提供程序接下来将尝试使用 Kerberos(请参阅 IADsUser::SetPassword 了解在使用跨林身份验证的 Windows 上可能导致的一些问题),如果这也失败,它最终将调用 Active Directory 特定网络管理 API,NetUserChangePassword。The RemarksIADsUser::SetPassword说的多一点:首先,LDAP 提供程序尝试通过 128 位 SSL 连接使用 LDAP。要使 LDAP SSL 成功运行,LDAP 服务器必须安装适当的服务器身份验证证书,并且运行 ADSI 代码的客户端必须信任颁发这些证书的机构。服务器和客户端都必须支持 128 位加密。其次,如果 SSL 连接不成功,LDAP 提供者会尝试使用 Kerberos。第三,如果 Kerberos 不成功,LDAP 提供程序会尝试调用NetUserSetInfo API。在以前的版本中,ADSI在线程运行的安全上下文中调用NetUserSetInfo ,而不是在调用IADsOpenDSObject::OpenDSObject或ADsOpenObject时指定的安全上下文。在以后的版本中,这已更改,以便 ADSI LDAP 提供程序在调用 NetUserSetInfo 时模拟 OpenDSObject 调用中指定的用户。因此,如果这对您根本不起作用,则意味着所有三种方法都失败了。我真的不知道 Kerberos 或 NetUserSetInfo 是如何工作的,但我确实知道基于 SSL 的 LDAP 是如何工作的,你可以试试看它是否适合你。连接到 LDAPS 端口应该很容易(假设这是域的DNS名称)::636ServerDomainusing (var context = new PrincipalContext(ContextType.Domain, $"{ServiceDomain}:636", ServiceDefaultLocation, ContextOptions.Negotiate, ServiceUser, ServicePassword))using (var identity = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Jane")){    // identity.SetPassword("SomeNewPassword"); // also tried    identity.ChangePassword("TheOldPassword", "SomeNewPassword"); // this is the error line    identity.Save();}但是,如果服务器使用您运行它的计算机不信任的证书,您可能会遇到麻烦(您必须在运行它的计算机上安装根证书)。LDAPS 也有可能没有在 DC 上运行。但值得一试。

慕少森

您是否尝试过 DirectoryEntry?用它来调试与连接相关的问题更容易。var entry = new DirectoryEntry{        Path = "LDAP://yourDCname";        Username = yourUsername;        Password = yourPassword;    };    using(var searcher = new DirectorySearcher(entry))    {        searcher.Filter = "(sAMAccountName=Jane)";        var result = searcher.FindOne();        var user = result.GetDirectoryEntry();        try        {            user.Invoke("ChangePassword", new object[] { oldPassword, newPassword});            user.CommitChanges();        }        catch        {            throw;        }    }我也曾经忘记了后台运行在谷歌浏览器中的 ZenMate VPN 插件。所以我无法连接到域控制器。

鸿蒙传说

我在密码重置服务器网页上遇到了类似的问题,用户可以重置自己的密码。我发现即使服务帐户被授予仅重置密码的权限,域的设置也不允许这样做。您是否尝试过授予服务帐户域管理员权限只是为了测试它不是权限问题?
随时随地看视频慕课网APP
我要回答