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

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

问题描述

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

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. 如果我手动回收应用程序池,     一切似乎来修复自己,直到     更多的错误开始发生......即,     这个过程开始从头再来的     阶段1。
  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.

下面是code中的相关代码段:

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);
		}
	}

任何线索,为什么发生这种情况?谷歌搜索不转了什么真正有用的,而且也不是在文档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 这是从<一个继承href="http://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.authenticableprincipal.aspx">AuthenticablePrincipal它是从<一个继承href="http://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.principal.aspx">Principal.我说的这一切,因为主要类有在 FindByIdentity 一个已知的内存泄漏。如果你看一下这个 MSDN进入,你会发现在那的加里·考德威尔从微软表示如下:

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但不   调用Dispose的   SearchResultsCollection作为   文档介绍了。

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

另外,如果你想在用户直接更改密码,你不希望靠自己的诚实,你可能要考虑使用的ChangePassword LDAP的功能是这样的:

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天全站免登陆