miércoles, 28 de abril de 2010

Un poco de usuarios y permisos

En esta ocasión me gustaría hablar un poco sobre un tema que tiende mucho a confundir, pero a la vez es muy útil de conocer ya que se da en diversas situaciones dentro del desarrollo de aplicaciones ASPNET. Para empezar me gustaría diferenciar que principalmente hay tres usuarios asociados a una aplicación Web. El usuario autenticado que puede ser visualizado a través de la siguiente sentencia:

System.Threading.Thread.CurrentPrincipal.Identity.Name

, el usuario del contexto de seguridad, por lo general es el que va a tener acceso a algunos recursos, esta se puede ver a través de:

System.Security.Principal.WindowsIdentity.GetCurrent().Name

, y el usuario encargado de correr el proceso.

El usuario autenticado prácticamente puede tener cualquier cosa desde “vacío” en el caso de que se utilice autenticación anónima en el IIS o la aplicación esté configurada para no utilizar autenticación del todo (); hasta cualquier usuario customizado. El usuario del servicio, sí deberá poseer una cuenta de Windows válida siempre, ya sea como usuario de una máquina local o de un Active Directory, este usuario por defecto es ASPNET en IIS 5 (Windows XP, 2000) o NETWORK SERVICE en IIS 6 o 7 (Windows 2003, Vista, 7). Inicialmente y por lo regular el usuario que corre el proceso es el mismo del contexto de seguridad. Recordemos que en este caso, el proceso (Worker Process), es el proceso que ejecuta el IIS para el sitio y se llama “aspnet_wp” en IIS 5 y “w3wp” en IIS 6/7, por lo que usuario que lo ejecuta podría se visualizado desde el administrador de tareas de la máquina que hostea la aplicación Web.

Otro punto importante es la impersonificación (Impersonate). Si a través del web.config habilitamos la impersonificación () el usuario del contexto de seguridad, asume la identidad del usuario autenticado, esto puede ser útil en casos donde se necesitan accesar recursos especiales como un archivo de texto, el log de eventos, un WebService, una cola, una base de datos, etc. y el usuario por defecto (ASPNET o NETWORK SERVICE) al ser un usuario de bajos privilegios no tendría permisos para dicho fin. Pero hay que tener mucho cuidado al llevar a cabo esta acción, solo debería utilizarse para recursos en los que efectivamente el acceso es por usuario, porque de no ser así no tendría mucho sentido asignar permisos a todos los usuarios de la aplicación sobre un recurso en particular. Esta situación no se presentaría en el caso de que se asigne un usuario específico en la impersonificación (), pero igualmente sería un asunto de cuidado, además de que como sabemos la sentencia anterior no es muy segura.

En ambientes con IIS 6 o superior todo sitio Web se ejecuta bajo un aplication pool, el default application pool tiene asignada la cuenta de NETWORK SERVICE, es por esto que esta es la cuenta que corre el proceso por defecto, así las cosas, otra opción para resolver el problema anterior podría ser utilizar un pool customizado con una cuenta específica.

También hay situaciones en las que el acceso al recurso específico es por usuario, pero como medida de seguridad, no se desea impersonificar siempre, en estos casos se podría llevar a cabo una impersonificación temporal a través del objeto WindowsImpersonationContext, esto se ilustra en el siguiente ejemplo, accesando un WebService:

localhost.Service proxy = new localhost.Service();

IPrincipal p = this.User;
WindowsIdentity wi = (WindowsIdentity)p.Identity;
WindowsImpersonationContext wic = wi.Impersonate();
try
{
// Recurso que requiere cierto permisos
proxy.Credentials = CredentialCache.DefaultCredentials;
retorno = proxy.HelloWorld();
}
finally
{
wic.Undo();
}


Y ya que estamos con un ejemplo de acceso a un WebService cabe destacar que al accesar un WebService desde un sitio Web el usuario del contexto de seguridad, pasaría a ser el usuario autenticado dentro del mismo, por ejemplo si el usuario autenticado es “rzumbado” y el usuario del contexto de seguridad es ASPNET, al llamar al servicio Web, dentro del contexto del mismo, ASPNET pasaría a ser el usuario autenticado, siempre y cuando se utilice la sentencia se asignen las DefaultCredentials a las credenciales del proxy (proxy.Credentials = CredentialCache.DefaultCredentials;). De no asignarse las credenciales, el servicio Web se estaría accesando de forma anónima.

Una vez explicado esto se puede entender porqué, un WebService sin autenticación anónima por lo general da un error de acceso denegado si no se setean las credenciales y porqué en un WebService sobre el que no tiene acceso ASPNET o NETWORK SERVICE hay que impersonificar temporal o permanente o utilizar un usuario customizado a través de un aplication pool en IIS 6.