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

时间:2018-12-18 14:03:35

标签: c# active-directory ldap passwords

我们正在尝试通过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已在远程端列入白名单(同样,我们可以连接并检索用户条目)。 不过,通过身份验证也可能需要花费很长时间(仍然可以成功工作)。

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

如果还有其他信息可以帮助诊断问题,请告诉我。

3 个答案:

答案 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::OpenDSObjectADsOpenObject的调用中指定的安全上下文。在以后的版本中,此更改已更改,以便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上运行。

但是值得一试。