Identity & .NET 4.5 - II

En la anterior entrega hablamos sobre como Claims Identity / Principal pasaban a ser elementos fundamentales de .NET 4.5. Junto con esta entrada también vimos como los mecanismos de autorización legacy seguían funcionando, aunque ahora interpretando claims. Pues bien, a lo largo de esta entrada trataremos de hablar de dos elementos fundamentales en nuestros RP, ClaimsAuthenticationManager y ClaimsAuthorizationManager.

 

ClaimsAuthenticationManager

Tal y como se puede leer en la documentación de esta clase, la idea de esta pieza es la de poder dar soporte a la transformación, modificación y agregación de las claims obtenidas en el proceso de autenticación de un usuario. Un ejemplo podría ser en un sitio web con un carrito en el que querramos agregar a cualquier usuario autenticado alguna claim procedente de nuestro sistema y no del repositorio/pieza de autenticación. Su uso, como puede verse a continuación es tremendamente sencillo.

 

public class PassThrougClaimsAuthenticationManager
    :ClaimsAuthenticationManager
{
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {
        if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
        {
            var identity = (ClaimsIdentity)incomingPrincipal.Identity;
 
            //TODO: Add, remove or change identity.Claims property
        }
 
        return incomingPrincipal;
    }
}

Si observa, lo único que hemos hecho es sobreescribir el método Authenticate, para, si el usuario está autenticado trabajar sobre la colección de Claims de la identidad obtenida por el método seleccionado. Para establecer esta implementación como el ClaimsAuthenticationManager por defecto solamente tendremos que agregar la siguiente sección de configuración dentro de nuestro programa.

<configSections>
  <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>
<system.identityModel >
  <identityConfiguration name="MyIdentity">
    <claimsAuthenticationManager type="ClaimsAuthentication.PassThrougClaimsAuthenticationManager,ClaimsAuthentication"/>
  </identityConfiguration>
</system.identityModel>

Una vez establecida la configuración, tendremos que indicar que se utilize el sistema de transformación de claims, para ello, dependiendo  del tipo de aplicación lo haremos de forma diferente. Por ejemplo, para una aplicación de escritorio solamente tendríamos que cambiar el sitio en el que hagamos la asignación de nuestro principal al hilo de ejecución, incorporando el siguiente código:

 

Thread.CurrentPrincipal =  FederatedAuthentication.FederationConfiguration
                                                  .IdentityConfiguration
                                                  .ClaimsAuthenticationManager
                                                  .Authenticate("app", principal);

 

En el caso de la web, es un poco diferente, sobre todo, porque generalmente no intervenimos en este proceso de asignación del principal al HttpContext. Para resolver esto, podemos crear un sencillo módulo Http que nos haga este trabajo, un código de ejemplo podría ser el siguiente:

 

public class ClaimsTransformationHttpModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
    }
 
    void Context_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var context = ((HttpApplication)sender).Context;
 
        // no need to call transformation if session already exists
        if (FederatedAuthentication.SessionAuthenticationModule != null
            &&
           FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookies))
        {
            return;
        }
 
        var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
        if (transformer != null)
        {
            var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);
 
            //set new principal in http context and thread current principal
            context.User = transformedPrincipal;
            Thread.CurrentPrincipal = transformedPrincipal;
        }
    }
 
    public void Dispose() { }
}

 

Si observa, en lineas generales, con un poquito más de amor, hemos hecho el mismo trabajo que anteriormente, asignar al hilo ( y en el caso de la web al HttpContext ) el principal obtenido de la transformación. Por supuesto, una vez creado tenemos que registrar este módulo dentro de nuestro sitio, adicionalmente, también tenemos que hacer el registro del móduglo SessionAuthenticationModule, ahora veremos para que..

 

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <add name ="ClaimsTransformationModule" type="ClaimsTranformation.ClaimsTransformationHttpModule,ClaimsTranformation"/>
    <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    <!--<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>-->
  </modules>
  <validation validateIntegratedModeConfiguration="false" />
</system.webServer>

Bien, supongamos que ya hemos hecho todo el trabajo. Si navegamos un poco por el sitio, nos daremos cuenta de que el método Authenticate es llamado de forma continua, si, por ejemplo, hacemos lo que comentamos anteriormente de buscar en nuestro repositorio claims adicionales el impacto de rendimiento sería alto. Para evitarlo, podemos guardar en sesión este principal de tal forma que no sea ejecutado tan frecuentemente. Para ello, modificaremos nuestro ClaimsAuthenticationManager para incluir lo siguiente

 

public class PTTransformer 
    : ClaimsAuthenticationManager
{
    public PTTransformer() { }
 
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {
        if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
        {
            var identity = ((ClaimsIdentity)incomingPrincipal.Identity);
            identity.AddClaim(new Claim("time", DateTime.Now.ToLongTimeString()));
 
            incomingPrincipal = new ClaimsPrincipal(identity);
 
            if (HttpContext.Current != null)
            {
                var token = new SessionSecurityToken(incomingPrincipal);
                FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
 
            }
            
        }
 
        return incomingPrincipal;
    }
}

 

Como podrá observar se hace uso del modulo SessionAuthenticationModule para emitir una cookie que será posteriormente utilizada para evitar el proceso de transformación de nuevo.

 

Bueno, hasta aquí llegaremos por hoy, espero que os esté resultando interesante..

 

Saludos

Unai

Published 19/7/2012 21:20 por Unai
Comparte este post:
http://geeks.ms/blogs/unai/archive/2012/07/19/identity-amp-net-4-5-ii.aspx

Comentarios

# Identity & .NET 4.5 - III

En la anterior entrega de esta serie vimos como extender el mecanismo de claims para hacer uso de un

Tuesday, July 24, 2012 5:04 PM por O bruxo mobile