• Sign In
 
  • MSDN Blogs
  • Microsoft Blog Images
  • More ...
Common Tasks
  • Blog Home
  • Email Blog Author
  • About
  • RSS for comments
  • RSS for posts
Blog - News
Search
  • Advanced search options...
Recent Posts
  • Corrupción de las claves RSA y la importancia de hacer backup

    Posted 1 day ago
    by Daniel Mossberg
      0 Comments
  • Modelos de programación en ASP.NET: Web Forms, MVC y Web Pages

    Posted 19 days ago
    by Daniel Mossberg
      0 Comments
  • HttpException: An error occurred while attempting to impersonate

    Posted over 2 years ago
    by Daniel Mossberg
      1 Comments
  • Problemas al subir ficheros a una aplicación ASP.NET

    Posted over 2 years ago
    by Daniel Mossberg
      0 Comments
  • Cómo reutilizar el código de una biblioteca de clases .NET desde una aplicación Silverlight

    Posted over 2 years ago
    by Daniel Mossberg
      1 Comments
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
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 > HttpException: An error occurred while attempting to impersonate

HttpException: An error occurred while attempting to impersonate

HttpException: An error occurred while attempting to impersonate

Daniel Mossberg
26 Nov 2010 5:11 AM
  • Comments 1

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

  • 1 Comments
ASP.NET, Seguridad, Ejemplos de Código, Common Language Runtime (CLR)
Leave a Comment
  • Please add 5 and 1 and type the answer here:
  • Post
Comments
  • Marc
    3 Mar 2011 10:50 AM

    Wow, this is exactly what I've been hunting for for hours.  Thank you so much for this post, saved my butt!

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