System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题 [英] Strange issue with System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity

查看:22
本文介绍了System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这是相关的代码片段:

    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 上的文档也没有.

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

推荐答案

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

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:

此调用存在非托管内存泄漏因为底层实现使用 DirectorySearcher 和SearchResultsCollection 但不调用 disposeSearchResultsCollection 作为文档描述.

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 被重置并释放内存.

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

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

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.

希望能帮到你,

这篇关于System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity 的奇怪问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆