System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题

发布于 2024-08-15 05:18:12 字数 1331 浏览 11 评论 0原文

我们正在编写一个系统,允许用户通过 Intranet 上的 Web 应用程序更改其帐户密码。

起初,一切似乎都进展顺利。在开发过程中,我们的测试帐户的密码可以毫无问题地更改。

然而,当我们让系统上线时,我们开始遇到问题。症状如下:

  1. 起初,一切都很好。用户 可以更改他们的密码。
  2. 在一些 点,出现以下错误 UserPrincipal.FindByIdentity: “System.Runtime.InteropServices.COMException: 认证机制是 未知。 “
  3. 从那时起,就努力 通过网络更改密码 应用程序导致错误: “System.Runtime.InteropServices.COMException: 服务器无法运行。 “
  4. 如果我手动回收应用程序池, 一切似乎都会自行修复,直到 更多错误开始发生......即, 该过程再次开始于 第 1 阶段。

这是相关的代码片段:


    private static PrincipalContext CreateManagementContext() {
        return new PrincipalContext(
            ContextType.Domain, 
            ActiveDirectoryDomain, 
            ActiveDirectoryManagementAccountName,
            ActiveDirectoryManagementAccountPassword);
    }


    private static void ChangeActiveDirectoryPasword(string username, string password) {
        if (username == null) throw new ArgumentNullException("username");
        if (password == null) throw new ArgumentNullException("password");

        using (var context = CreateManagementContext())
        using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username)) {
            user.SetPassword(password);
        }
    }

有任何线索说明为什么会发生这种情况吗? Google 搜索并没有找到任何真正有用的东西,MSDN 上的文档也没有。

We're writing a system that allows a user to change their account password through a web application on our intranet.

At first, everything appeared to be running smoothly. During development passwords for our test accounts could be changed with no problem.

When we made the system live, however, we started running into issues. Here are the symptoms:

  1. At first, everything is fine. Users
    can change their passwords.
  2. At some
    point, the following error occurs in
    UserPrincipal.FindByIdentity:
    "System.Runtime.InteropServices.COMException:
    The authentication mechanism is
    unknown. "
  3. From then on, trying to
    change a password through the web
    application results in the error:
    "System.Runtime.InteropServices.COMException:
    The server is not operational. "
  4. If I manually recycle the app pool,
    everything seems to fix itself until
    more errors begin happening... i.e.,
    the process starts all over again at
    phase 1.

Here's the relevant snippet of code:


    private static PrincipalContext CreateManagementContext() {
        return new PrincipalContext(
            ContextType.Domain, 
            ActiveDirectoryDomain, 
            ActiveDirectoryManagementAccountName,
            ActiveDirectoryManagementAccountPassword);
    }


    private static void ChangeActiveDirectoryPasword(string username, string password) {
        if (username == null) throw new ArgumentNullException("username");
        if (password == null) throw new ArgumentNullException("password");

        using (var context = CreateManagementContext())
        using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username)) {
            user.SetPassword(password);
        }
    }

Any clues as to why this is happening? Google searches aren't turning up anything really helpful, and neither are the docs on MSDN.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱花落人离去 2024-08-22 05:18:12

我注意到的第一件事是您正在使用继承的 UserPrincipal.FindByIdentity来自 AuthenticablePrincipal 继承自 校长。我之所以这么说是因为 Principal 类在 FindByIdentity 中存在已知的内存泄漏。如果您查看此 MSDN 条目,您会注意到底部,来自 Microsoft 的 Gary Caldwell 说了以下内容:

此调用存在非托管内存泄漏
因为底层的实现
使用 DirectorySearcher 和
SearchResultsCollection 但没有
调用 dispose
SearchResultsCollection 作为
文档描述了。

我猜这是你的问题。内存泄漏导致应用程序池被填满并最终导致错误,直到应用程序池被重置并释放内存。

当我们使用任何活动目录功能时,我们使用以下方法来完成用户密码的设置:

Public Shared Function GetUserAccount(ByVal username As String) As DirectoryEntry
    Dim rootPath As String = GetRootPath()
    Using objRootEntry As New DirectoryEntry(rootPath)
        Using objAdSearcher As New DirectorySearcher(objRootEntry)
            objAdSearcher.Filter = "(&(objectClass=user)(samAccountName=" & username & "))"
            Dim objResult As SearchResult = objAdSearcher.FindOne()
            If objResult IsNot Nothing Then Return objResult.GetDirectoryEntry()
        End Using
    End Using
    Return Nothing
End Function

Public Shared Sub SetPassword(ByVal username As String, ByVal newPassword As String)
    Using objUser As DirectoryEntry = GetUserAccount(username)
        If objUser Is Nothing Then Throw New UserNotFoundException(username)
        Try
            objUser.Invoke("SetPassword", newPassword)
            objUser.CommitChanges()
        Catch ex As Exception
            Throw New Exception("Could not change password for " & username & ".", ex)
        End Try
    End Using
End Sub

此外,如果您希望用户直接更改密码并且您不想依赖他们的诚实,您可能需要考虑使用 LDAP 的 ChangePassword 功能,如下所示:

Public Shared Sub ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String)
    Using objUser As DirectoryEntry = GetUserAccount(username)
        If objUser Is Nothing Then Throw New UserNotFoundException(username)
        Try
            objUser.Invoke("ChangePassword", oldPassword, newPassword)
            objUser.CommitChanges()
        Catch ex As TargetInvocationException
            Throw New Exception("Could not change password for " & username & ".", ex)
        End Try
    End Using
End Sub

这会强制用户在更改为新密码之前知道之前的密码。

我希望这有帮助,

谢谢!

First thing I notice is that you are using UserPrincipal.FindByIdentity which is inherited from AuthenticablePrincipal which is inherited from Principal. I say all this because the Principal class has a known memory leak in the FindByIdentity. If you have a look at this MSDN entry, you will notice at the bottom that Gary Caldwell from Microsoft said the following:

This call has an unmanaged memory leak
because the underlying implemenation
uses DirectorySearcher and
SearchResultsCollection but does not
call dispose on the
SearchResultsCollection as the
document describes.

I would guess that this is your issue. The memory leak causes the Application Pool to fill up and finally cause errors, until the Application Pool is reset and the memory is disposed.

When we use any active directory functions, we use the following to accomplish setting of the user's password:

Public Shared Function GetUserAccount(ByVal username As String) As DirectoryEntry
    Dim rootPath As String = GetRootPath()
    Using objRootEntry As New DirectoryEntry(rootPath)
        Using objAdSearcher As New DirectorySearcher(objRootEntry)
            objAdSearcher.Filter = "(&(objectClass=user)(samAccountName=" & username & "))"
            Dim objResult As SearchResult = objAdSearcher.FindOne()
            If objResult IsNot Nothing Then Return objResult.GetDirectoryEntry()
        End Using
    End Using
    Return Nothing
End Function

Public Shared Sub SetPassword(ByVal username As String, ByVal newPassword As String)
    Using objUser As DirectoryEntry = GetUserAccount(username)
        If objUser Is Nothing Then Throw New UserNotFoundException(username)
        Try
            objUser.Invoke("SetPassword", newPassword)
            objUser.CommitChanges()
        Catch ex As Exception
            Throw New Exception("Could not change password for " & username & ".", ex)
        End Try
    End Using
End Sub

Also, if you're wanting the users to change the passwords directly and you don't want to rely on their honesty, you might want to consider using the ChangePassword function of LDAP like this:

Public Shared Sub ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String)
    Using objUser As DirectoryEntry = GetUserAccount(username)
        If objUser Is Nothing Then Throw New UserNotFoundException(username)
        Try
            objUser.Invoke("ChangePassword", oldPassword, newPassword)
            objUser.CommitChanges()
        Catch ex As TargetInvocationException
            Throw New Exception("Could not change password for " & username & ".", ex)
        End Try
    End Using
End Sub

This forces the user to know the prior password before changing to the new one.

I hope this helps,

Thanks!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文