• Sign In
 
  • MSDN Blogs
  • Microsoft Blog Images
  • More ...
Common Tasks
  • Blog Home
  • About
  • RSS for posts
  • Atom
Blog - News
Search
  • Advanced search options...
Twitter (@dmossberg)
Tags
  • ASP
  • ASP.NET
  • Common Language Runtime (CLR)
  • Debugging
  • Ejemplos de Código
  • Failed Request Tracing
  • Herramientas
  • IIS 6.0
  • IIS 7.0
  • Kerberos
  • Log Parser
  • Pages
  • Seguridad
  • Silverlight
  • SSL/TLS
Recent Posts
  • HttpException: An error occurred while attempting to impersonate

    Posted over 2 years ago
    by Daniel Mossberg
Archives
Archives
  • May 2012 (2)
  • November 2010 (1)
  • August 2010 (1)
  • April 2010 (1)
  • March 2010 (2)
  • February 2010 (2)
  • January 2010 (2)
  • December 2009 (5)
  • October 2009 (1)
  • September 2009 (3)
  • August 2009 (1)
  • July 2009 (2)
  • May 2009 (2)
  • April 2009 (4)
  • February 2009 (1)
  • January 2009 (1)
  • December 2008 (1)
Blogs de ASP.NET / IIS
  • If broken it is, fix it you should

  • Notes from a dark corner

  • Never doubt thy debugger

  • Speaking of which...

Otros blogs recomendados
  • Blogs de Soporte en España

MSDN Blogs > The code is out there > November, 2010

November, 2010

  • Subscribe via RSS
Sort by: Most Recent | Most Views | Most Comments
Excerpt View | Full Post View
  • The code is out there

    HttpException: An error occurred while attempting to impersonate

    Posted over 2 years ago
    by Daniel Mossberg
    • 1 Comments

    Pasados más de tres meses desde mi último post, ya es momento de retomarlo. Hoy voy a escribir sobre un problema con el que me he encontrado en varias ocasiones en los últimos meses. Básicamente, el problema se produce cuando tenemos una aplicación ASP.NET configurada para impersonar al usuario autenticado, y en algún punto de la aplicación se trata de impersonar programáticamente a un usuario distinto. En estas circunstancias, la aplicación va a fallar con el siguiente error:

     

    Exception Details:

    System.Web.HttpException: An error occurred while attempting to impersonate. Execution of this request cannot continue.

     

    Stack Trace:

    [HttpException (0x80004005): An error occurred while attempting to impersonate. Execution of this request cannot continue.]

    System.Web.ImpersonationContext.GetCurrentToken() +8845961

    System.Web.ImpersonationContext.get_CurrentThreadTokenExists() +58

    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +193

    System.Web.ApplicationStepManager.ResumeSteps(Exception error) +501

    System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +123

    System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +379

    …

     

    Básicamente, el problema radica en que al llamar al método Impersonate (o llamando directamente a la API LogonUser que es la que se termina llamando desde Impersonate), se intenta acceder al token del proceso (por ejemplo, w3wp.exe), y la cuenta del usuario autenticado (el que está siendo impersonado debido a la configuración del web.config) no tiene permiso para acceder a dicho token.

     

    Por lo tanto, para poder impersonar una cuenta distinta programáticamente, necesitamos deshacer la impersonación inicial antes de impersonar una cuenta distinto. Para ello, podemos llamar a la API RevertToSelf para deshacer la impersonación antes de llamar a LogonUser.

     

    En el siguiente ejemplo se ilustra cómo podríamos hacerlo:

     

    const int LOGON32_PROVIDER_DEFAULT = 0;

    const int LOGON32_LOGON_INTERACTIVE = 2;

    const int SecurityImpersonation = 2;

     

    int win32ErrorNumber = 0;

     

    //Mostramos por pantalla la identidad inicial (la impersonada mediante en el web.config):

    Response.Write("Identidad inicial: " + WindowsIdentity.GetCurrent().Name.ToString() + "<BR>");

     

    //Guardamos esa identidad inicial para poder restaurarlo posteriormente

    WindowsIdentity _initialIdentity = WindowsIdentity.GetCurrent();

     

    //Llamamos a la API "RevertToSelf" para deshacer la impersonación configurada en el web.config:

    RevertToSelf();

     

    //Volvemos a mostrar la identidad, y ahora vemos que ha cambiado a la identidad del application

    //pool: (NETWORK SERVICE) por defecto.

    Response.Write("Después de llamar a RevertToSelf: " + WindowsIdentity.GetCurrent().Name.ToString() + "<BR>");

     

    //Realizamos la impersonación deseada.

    IntPtr _tokenHandle = IntPtr.Zero;

    IntPtr _dupeTokenHandle = IntPtr.Zero;

     

    string _domainname = "CONTOSO";

    string _username = "demo";       

    string _password = "P@ssw0rd!";

     

    if (!LogonUser(_username, _domainname, _password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out _tokenHandle))

    {

        win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error();

        throw new Exception(win32ErrorNumber.ToString());

    }

     

    if (!DuplicateToken(_tokenHandle, SecurityImpersonation, out _dupeTokenHandle))

    {

        win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error();

     

        CloseHandle(_tokenHandle);

        throw new Exception(win32ErrorNumber.ToString());

    }

     

    System.Security.Principal.WindowsIdentity newId = new System.Security.Principal.WindowsIdentity(_dupeTokenHandle);

    WindowsImpersonationContext _impersonatedUser = newId.Impersonate();

     

    //Mostramos por pantalla la identidad impersonada

    Response.Write("Después de impersonar: " + WindowsIdentity.GetCurrent().Name.ToString() + "<BR>");

     

    //Desahacemos la impersonación cuando ya no lo necesitemos.

    _impersonatedUser.Undo();

     

    //Mostramos por pantalla la identidad, que otra vez será la del application pool

    Response.Write("Deshacer impersonación: " + WindowsIdentity.GetCurrent().Name.ToString() + "<BR>");

     

    //Volvemos a impersonar con la identidad inicial (la del web.config) que hemos mantenido referenciada

    //con la variable _impersonatedUser:

    _impersonatedUser = _initialIdentity.Impersonate();

     

    //Por último volvemos a mostrar la identidadMostramos por pantalla la identidad

    Response.Write("Volver a impersonación inicial: " + WindowsIdentity.GetCurrent().Name.ToString() + "<BR>");

     

    Tras ejecutar el código anterior, el resultado emitido por pantalla sería el siguiente (en mi ejemplo):

     

    Identidad inicial: CONTOSO\daniel
    Después de llamar a RevertToSelf: NT AUTHORITY\NETWORK SERVICE
    Después de impersonar: CONTOSO\demo
    Deshacer impersonación: NT AUTHORITY\NETWORK SERVICE
    Volver a impersonación inicial: CONTOSO\daniel

     

    Estas son las signatures de C# para llamar a las APIs del ejemplo mediante platform invoke:

     

    [DllImport("advapi32.dll", SetLastError = true)]

    public static extern bool LogonUser(

        string lpszUsername,

        string lpszDomain,

        string lpszPassword,

        int dwLogonType,

        int dwLogonProvider,

        out IntPtr phToken);

     

    [DllImport("advapi32.dll", SetLastError = true)]

    static extern bool RevertToSelf();

     

    [DllImport("advapi32.dll", SetLastError = true)]

    public extern static bool DuplicateToken(

        IntPtr ExistingTokenHandle,

        int SECURITY_IMPERSONATION_LEVEL,

        out IntPtr DuplicateTokenHandle);

     

    [DllImport("kernel32.dll", SetLastError = true)]

    [return: MarshalAs(UnmanagedType.Bool)]

    static extern bool CloseHandle(IntPtr hObject);

     

    Espero que os sea de utilidad.

    - Daniel Mossberg

Page 1 of 1 (1 items)
  • © 2012 Microsoft Corporation.
  • Terms of Use
  • Trademarks
  • Privacy Statement
  • Report Abuse
  • 5.6.402.223