miércoles, 18 de febrero de 2015

Claims Series 5: Autorizando!

Vamos a terminar esta serie dedicada a Claims autorizando, que es el objetivo final: Ver si un usuario puede o no realizar una operación en base al conjunto de claims que presenta.

Podemos utilizar atributos decorando métodos para indicar operaciones sobre recursos:

   1:  [ClaimsPrincipalPermission(SecurityAction.Demand, Operation="operacion", Resource="recurso")]

O bien podemos comprobar la seguridad programáticamente:

   1:   ClaimsPrincipalPermission.CheckAccess("operacion", "recurso");

Pero claro, ¿como realizamos la autorización?  Debemos codificar una clase que heredando de ClaimsAuthorizationManager sobrescriba el método CheckAccess:

   1:  public override bool CheckAccess(AuthorizationContext context)
   2:  {
   3:      return base.CheckAccess(context);
   4:  }

Aquí implementaremos la lógica de autorización en base a las claims presentadas por el usuario.

Vamos con un ejemplo

 
Supongamos que queremos autorizar dos operaciones, una se encarga de formatear mi laptop y otra mi desktop (vivo al limite!). Dichas operaciones quedarían así decoradas:

   1:  [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Format", Resource = "Desktop")]
   2:  protected static void Operation1 ()
   3:  {
   4:        Console.WriteLine("Operation1: Format Desktop");
   5:  }
   6:   
   7:  [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Format", Resource = "Laptop")]
   8:  protected static void Operation2()
   9:  {
  10:        Console.WriteLine("Operation2: Format Laptop");
  11:  }

Bien, para realizar la autorización vamos a basarnos en dos claims:

Claim
Valor
Significado
http://serginet.com/isUserUsingMyLaptop
true/false
Indica si el usuario puede formatear el laptop
http://serginet.com/isUserUsingMyDesktop
true/false
Indica si el usuario puede formatear el desktop


Tenemos, como he comentado antes, que crear una clase que herede de ClaimsAuthorizationManager  y sobrescriba el método CheckAccess:

   1:  public override bool CheckAccess(AuthorizationContext context)
   2:  {
   3:      string resource = context.Resource.First().Value;
   4:      string action = context.Action.First().Value;
   5:   
   6:      if (action == "Format" && resource == "Laptop")
   7:      {
   8:          bool isLaptopUser = context.Principal.HasClaim("http://serginet.com/isUserUsingMyLaptop", "true");
   9:          return isLaptopUser;
  10:      }
  11:      else if (action == "Format" && resource == "Desktop")
  12:      {
  13:          bool isDesktopUser = context.Principal.HasClaim("http://serginet.com/isUserUsingMyDesktop", "true");
  14:          return isDesktopUser;
  15:      } 
  16:      return false;
  17:  }

 
Como veis se comprueban los claims en base al par operación/recurso y se retorna un booleano indicando si la operación está permitida.
 
A continuación, y de modo similar a como vimos en la entrada anterior, debemos configurar nuestro manager de autorización en el archivo de configuración de la aplicación. Veréis que he configurado también un transformador, para que incluya las claims necesarias en el momento de la autenticación (si no lo hacemos el usuario nunca va a tener las claims necesarias):

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <configuration>
   3:    <configSections>
   4:      <section name="system.identityModel"
   5:          type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
   6:    </configSections>
   7:   
   8:    <system.identityModel>
   9:      <identityConfiguration>
  10:        <claimsAuthenticationManager type="Claims5_Autorizando.CustomClaimsTransformer,Claims5_Autorizando"/>
  11:        <claimsAuthorizationManager type="Claims5_Autorizando.CustomClaimsAuth,Claims5_Autorizando"/>
  12:      </identityConfiguration>
  13:    </system.identityModel>
  14:   
  15:    <startup>
  16:      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  17:    </startup>
  18:   
  19:  </configuration>

He utilizado el mismo transformador de la entrada anterior: Claims Series 4: Transformaciones
Se encarga de añadir una claim al usuario que ejecuta la aplicación siempre que dicho usuario sea un usuario de mi equipo (cambiadlo vosotros o no os funcionará). Es decir, en mi caso añade la siguiente claim: "http://serginet.com/isUserUsingMyDesktop" con el valor true
 
Una vez tenemos todo podemos probar a llamar a las operaciones. La primera funciona correctamente ya que el usuario tiene el claim necesario,. Sin embargo al ejecutar la segunda obtenemos una excepción:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:   
   6:          SetCurrentPrincipal();
   7:   
   8:          Operation1();
   9:          Operation2();
  10:      }
  11:   
  12:      [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Format", Resource = "Desktop")]
  13:      protected static void Operation1 ()
  14:      {
  15:          Console.WriteLine("Operation1: Format Desktop");
  16:      }
  17:   
  18:      [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Format", Resource = "Laptop")]
  19:      protected static void Operation2()
  20:      {
  21:          Console.WriteLine("Operation2: Format Laptop");
  22:      }
  23:   
  24:      private static void SetCurrentPrincipal()
  25:      {
  26:          WindowsPrincipal incomingPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
  27:          Thread.CurrentPrincipal = FederatedAuthentication.FederationConfiguration.IdentityConfiguration
  28:              .ClaimsAuthenticationManager.Authenticate("none", incomingPrincipal);
  29:      }
  30:  }
 
 
 
Con esto finalizamos la serie dedicada a claims. No es más que una introducción... habrá que profundizar!

Como siempre os dejo el código

Posts publicados en Claims Series:

No hay comentarios:

Publicar un comentario