Étrange problème avec le Système.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity

nous écrivons un système qui permet à un utilisateur de changer le mot de passe de son compte au moyen d'une application web sur notre intranet.

au début, tout semblait fonctionner en douceur. Pendant le développement, les mots de passe de nos comptes de test peuvent être modifiés sans problème.

quand nous avons fait vivre le système, Cependant, nous avons commencé à rencontrer des problèmes. Voici les symptômes:

  1. au début, tout va bien. Utilisateur peuvent changer leurs mots de passe.
  2. à certains point, l'erreur suivante se produit dans UserPrincipal.FindByIdentity: "Système.Runtime.InteropServices.COMException: Le mécanisme d'authentification est inconnu. "
  3. à partir de là, en essayant de modifier un mot de passe via le web résultats de l'application dans l'erreur: "Système.Runtime.InteropServices.COMException: Le serveur n'est pas opérationnel. "
  4. si je recycle manuellement l'application pool, tout semble se fixer jusqu'à ce que d'autres erreurs commencent à se produire... c'est à dire, le processus recommence à la phase 1.

Voici l'extrait de code correspondant:


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

des indices sur ce qui se passe? Les recherches sur Google ne sont pas très utiles, pas plus que les documents sur MSDN.

13
demandé sur Scott 2009-12-10 21:50:37

1 réponses

la première chose que je remarque est que vous utilisez UserPrincipal.FindByIdentity qui est hérité de principal authentifiable qui est hérité de Principal . Je dis tout cela parce que la classe Principal a une fuite de mémoire connue dans le FindByIdentity . Si vous avez un coup d'oeil à cette entrée MSDN , vous remarquerez en bas que Gary Caldwell de Microsoft dit ce qui suit:

cet appel a une fuite de mémoire non gérée parce que la mise en œuvre sous-jacente utilise le chercheur directeur et SearchResultsCollection mais n'a pas appel disposer sur le SearchResultsCollection que l' le document décrit.

je suppose que c'est votre problème. La fuite de mémoire fait que le Pool D'applications se remplit et finalement cause des erreurs, jusqu'à ce que le Pool D'applications soit réinitialisé et que la la mémoire est éliminé.

lorsque nous utilisons n'importe quelle fonction active directory, nous utilisons ce qui suit pour effectuer le réglage du mot de passe de l'utilisateur:

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

aussi, si vous voulez que les utilisateurs changent les mots de passe directement et que vous ne voulez pas vous fier à leur honnêteté, Vous pouvez envisager d'utiliser la fonction ChangePassword de LDAP comme ceci:

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

cela oblige l'utilisateur à connaître le mot de passe évolution vers le nouveau.

je espère que cette aide,

Merci!

10
répondu Scott 2009-12-10 23:34:07