我们正在尝试通过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已在远程端列入白名单(同样,我们可以连接并检索用户条目)。 不过,通过身份验证也可能需要花费很长时间(仍然可以成功工作)。
我们的服务用户有权更改/设置其他用户的密码,尽管不能直接更改用户属性,所以我们被告知。
如果还有其他信息可以帮助诊断问题,请告诉我。
答案 0 :(得分:0)
您是否尝试过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;
}
}
我也曾经忘记了在后台运行于Google Chrome浏览器中的ZenMate VPN插件。所以我无法连接到域控制器。
答案 1 :(得分:0)
我在密码重设服务器网页上遇到了类似的问题,用户可以重设自己的密码。我发现,即使授予服务帐户仅重置密码的权限,该域的设置也不允许这样做。您是否尝试过授予服务帐户域管理员权限,以证明这不是权限问题?
答案 2 :(得分:0)
所以UserPrincipal.ChangePassword()
将call:
de.Invoke("ChangePassword", new object[] { oldPassword, newPassword });
在幕后使用的DirectoryEntry
上的。 DirectoryEntry.Invoke()
用于调用“本机Active Directory域服务对象上的方法”,这意味着最终将使用本机Windows IADsUser::ChangePassword
方法。 Remarks表示使用3种方法之一:
IADsUser :: ChangePassword的功能类似于IADsUser::SetPassword,因为它将使用三种方法之一来尝试更改密码。最初,如果建立了到服务器的安全SSL连接,则LDAP提供程序将尝试LDAP更改密码操作。如果此尝试失败,则LDAP提供程序接下来将尝试使用Kerberos(有关在跨林身份验证的Windows上可能导致的某些问题,请参阅IADsUser :: SetPassword),如果这也失败,则它将最终调用Active Directory特定的网络。管理API NetUserChangePassword。
Remarks of IADsUser::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的工作原理,但我确实知道LDAP over SSL的工作原理,这是您的事,然后尝试看看它是否对您有用。
应该很简单,只需将:636
放在ServerDomain
的末尾以连接到LDAPS端口(假设这是域的DNS名称):< / p>
using (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上运行。
但是值得一试。