2011-02-09 13 views
7

En http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.100).aspx hay un ejemplo sobre cómo hacer una suplantación con .net 4.0. Hemos utilizado este ejemplo en una clase que hereda IDisposable para facilitar su uso. Sin embargo, cuando usamos esta clase en una aplicación web asp.net, notamos un aumento leve pero constante de Bytes agrupados en el monitor de rendimiento. Después de una semana, la aplicación falla.Fuga de memoria de suplantación

He intentado diferentes implementaciones de la clase de suplantación, usando http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.90).aspx y http://support.microsoft.com/kb/306158 como referencia, pero todas muestran la misma fuga.

¿De dónde viene esta fuga? ¿Hay algún problema con la API de Windows? Estamos ejecutando Windows 2008 R2.

Ésta es nuestra versión actual de la clase suplantación:

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

Y este es el gráfico de monitor de rendimiento de los dos servidores web utilizando diferentes versiones de la clase:

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

Cuando desactivamos la clase, y usar la suplantación global a través de web.config, esas líneas son completamente planas.


actualización

he hecho una prueba de aplicación que reproduce con éxito el problema. Se puede descargar aquí:

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

El resultado más de 18 horas se ve así:

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

+0

He echado un vistazo a su código y a la implementación de SafeHandleZeroOrMinusOneIsInvalid (a través de Reflector). Estoy seguro de que probablemente me haya perdido algo, pero no tengo claro de dónde se llamará a CloseHandle o ReleaseHandle. ¿Está esperando que fue llamado por el método Dispose heredada en SafeTokenHandle? – MikeD

+0

No tengo idea de cómo funciona, solo asumo que sí, ya que está copiado del sitio de Microsoft en el enlace de arriba. He agregado algunas líneas de depuración, y se llama después de que se hace la suplantación, pero eso es todo lo que sé. – TheQ

+0

Dado lo que dices y que las otras muestras cierran explícitamente el identificador, entonces no parece ser el problema. ¿Tienes una suscripción a MSDN? De ser así, podría usar un incidente de soporte técnico de Microsoft para obtener ayuda adicional. – MikeD

Respuesta

1

difícil de decir. Por lo menos, WindowsIdentity también es un IDisposable, y la variable newId nunca se desecha. Además, verificaría si todos los usos de la clase Impersonator se eliminan correctamente.

+0

Todos los usos de la clase se realizan dentro de sentencias using, por lo que deberían ser seguros. Sin embargo, una buena llamada con la nueva variable Id, la arreglaré y la enviaré para prueba mañana. – TheQ

+0

Mismo resultado con esa actualización. También hice una aplicación de prueba en nuestro entorno de desarrollo, pero parece que no puedo replicar la fuga allí. Después de 1 millón de suplantaciones, los bytes de la paginación del grupo siguen siendo los mismos, así que no sé a dónde ir desde aquí. – TheQ

+0

Estoy perdido también. Sin información adicional (y dado el escenario, muy probablemente: sin la aplicación completa), es imposible saberlo. Tenía pocas esperanzas de que deshacerse de WindowsIdentity hiciera el truco, pero, ¡ay! –