memory-leaks - System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题

标签 memory-leaks active-directory ldap directoryservices account-management

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

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

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

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

  • 这是相关的代码片段:
        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);
            }
        }
    

    关于为什么会发生这种情况的任何线索?谷歌搜索没有找到任何真正有用的东西,MSDN 上的文档也没有。

    最佳答案

    我注意到的第一件事是您使用的是 UserPrincipal.FindByIdentity ,它是从 AuthenticablePrincipal 继承的,而 Principal 是从 MSDN entry 继承的。我之所以这么说是因为 Principal 类在 FindByIdentity 中有一个已知的内存泄漏。如果你看看这个 Gary Caldwell ,你会在底部注意到微软的 ojit_a 说了以下内容:

    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.



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

    当我们使用任何事件目录功能时,我们使用以下内容来完成用户密码的设置:
    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
    

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

    我希望这有帮助,

    谢谢!

    关于memory-leaks - System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1883165/

    相关文章:

    java - 每当我在 servlet 中更新时,我发现 tomcat 6.0 中存在内存泄漏

    ios - XCode 4.6显示了方法+(void)beginAnimations:(NSString *)animationID context:(void *)context的内存泄漏警告。

    ruby - 跟踪 Ruby 代码中的内存泄漏

    swift - 避免从作为另一个 ViewController 子级的 ViewController 以编程方式完成的 UITableView 的保留周期

    active-directory - LDAP 中的域名和 DC

    ubuntu - 除非使用 CApath 或 CAfile,否则无法验证 CA 证书

    C 语言 OpenLDAP API,用于获取可用于搜索结果条目的属性数

    c# - 事件目录属性 "badPwdCount"

    c# - 扩展用户主体; FindByIdentity() 失败

    unix - Pam 身份验证,先尝试本地用户,然后尝试 LDAP