2011-02-09 8 views
7

Sur http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.100).aspx il y a un exemple sur comment faire l'usurpation d'identité avec .net 4.0. Nous avons utilisé cet exemple dans une classe qui hérite d'IDisposable pour la facilité d'utilisation. Toutefois, lorsque nous utilisons cette classe dans une application Web asp.net, nous remarquons une augmentation légère mais régulière de Pool Paged Bytes dans le moniteur de performances. Après une semaine, l'application se bloque.Fuite de mémoire d'usurpation

J'ai essayé différentes implémentations de la classe d'emprunt d'identité, en utilisant http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.90).aspx et comme référence, mais elles montrent toutes la même fuite.

D'où provient cette fuite? Y at-il un problème avec l'API Windows? Nous utilisons Windows 2008 R2.

Voici notre version actuelle de la classe d'emprunt d'identité:

public class Impersonator : IDisposable 
{ 
    public Impersonator(string username, string domain, string password) 
    { 
     if (!ImpersonateValidUser(username, domain, password)) 
     { 
      throw new SecurityException("Could not impersonate. Wrong username/password"); 
     } 
    } 

    public void Dispose() 
    { 
     UndoImpersonation(); 
    } 

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); 

    private const int LOGON32_PROVIDER_DEFAULT = 0; 
    private const int LOGON32_LOGON_INTERACTIVE = 2; //This parameter causes LogonUser to create a primary token. 

    private WindowsImpersonationContext impersonatedUser; 

    private bool ImpersonateValidUser(string username, string domain, string password) 
    { 
     SafeTokenHandle safeTokenHandle; 

     // Call LogonUser to obtain a handle to an access token. 
     bool success = LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle); 

     if (success) 
     { 
      using (safeTokenHandle) 
      { 
       // Use the token handle returned by LogonUser. 
       WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()); 
       impersonatedUser = newId.Impersonate(); 
      } 
     } 

     return success; 
    } 

    private void UndoImpersonation() 
    { 
     // Releasing the context object stops the impersonation 
     if (impersonatedUser != null) 
     { 
      impersonatedUser.Undo(); 
      impersonatedUser.Dispose(); 
     } 
    } 
} 

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid 
{ 
    private SafeTokenHandle() : base(true) 
    { 
    } 

    [DllImport("kernel32.dll")] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [SuppressUnmanagedCodeSecurity] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool CloseHandle(IntPtr handle); 

    protected override bool ReleaseHandle() 
    { 
     return CloseHandle(handle); 
    } 
} 

Et voici le graphique du moniteur de performance de deux serveurs Web en utilisant différentes versions de la classe:

perfmon http://img222.imageshack.us/img222/5388/captureyog.png

Lorsque nous désactivons la classe, et utilisent l'usurpation d'identité globale via web.config, ces lignes sont complètement plates.


Mise à jour

J'ai fait un test-application qui reproduit avec succès le problème. Il peut être téléchargé ici:

http://rapidshare.com/files/447325211/ImpersonationTest.zip

Le résultat de plus de 18 heures ressemble à ceci:

testapp http://img689.imageshack.us/img689/2055/impersonationtest.png

+0

J'ai jeté un coup d'oeil sur votre code et l'implémentation de SafeHandleZeroOrMinusOneIsInvalid (via Reflector). Je suis sûr que j'ai probablement manqué quelque chose mais je ne suis pas sûr d'où l'on appelle CloseHandle ou ReleaseHandle. Attendez-vous que cela soit appelé par la méthode Dispose héritée sur SafeTokenHandle? – MikeD

+0

Je n'ai aucune idée de comment cela fonctionne, je suppose que c'est le cas, car il est copié à partir du site de Microsoft dans le lien ci-dessus. J'ai ajouté quelques lignes de débogage, et il est appelé après que l'usurpation d'identité soit faite, mais c'est tout ce que je sais. – TheQ

+0

Étant donné ce que vous dites et que les autres échantillons explicitement fermer la poignée, il ne semble pas être le problème. Avez-vous un abonnement MSDN? Si c'est le cas, vous pouvez utiliser un incident de support Microsoft pour obtenir de l'aide supplémentaire. – MikeD

Répondre

1

Difficile à dire. À tout le moins, WindowsIdentity lui-même est également un IDisposable, et la variable newId n'est jamais éliminée. Aussi, je voudrais vérifier si toutes les utilisations de la classe Impersonator sont correctement éliminées.

+0

Toutes les utilisations de la classe sont faites dans les instructions d'utilisation, ce qui devrait être sûr. Bon appel avec la variable newId, je vais corriger ça et l'envoyer demain pour un test. – TheQ

+0

Même résultat avec cette mise à jour. J'ai aussi fait une application de test dans notre environnement de développement, mais je n'arrive pas à reproduire la fuite là-bas. Après 1 million d'usurpations, les octets paginés en pool restent les mêmes, donc je ne sais pas vraiment où aller à partir d'ici. – TheQ

+0

Je suis à la perte aussi. Sans informations supplémentaires (et étant donné le scénario, le plus probable: sans l'application complète), il est impossible de le dire. J'avais peu d'espoir que disposer de WindowsIdentity pourrait faire l'affaire, mais hélas. –