AAL y Web API, una mezcla casi perfecta

 

En el post anterior empezamos a ver un poco sobre AAL, y como empezar a trabajar con este simple paquete. En esta ocasión, continuaremos hablando de AAL y de como juntarlo con ASP.NET Web API. Cuando uno diseña sus servicios utilizando Web API uno de los elementos que siempre entran en juego es la autorización en los mismos, de hecho, dándonos un pequeño paseo por la propia Web de ASP.NET Web API podemos ver diferente documentación acerca de este tema. A mayores, por supuesto, buceando en la web podemos obtener diferente información acerca de como realizar los procesos de authenticación, desde API Keys hasta OAuth . Todos estos procesos técnicamente se hacen de una forma o en otra, pero, tienen en común que ninguno externaliza el proceso de autenticación teniendo que incorporar nosotros este dentro de nuestras aplicaciones y por lo tanto, cuando necesitamos diferentes proveedores de identidad la cosa se complica. A lo largo de esta entrada intentaremos ver como construir un servicio de Web API que soporte a usuarios autenticados con diferentes proveedores de identidad como por ejemplo Azure AD, Office 365,ADFS 2,Windows Live, Google, nuestro propio STS etc, de una manera sencilla y sin apenas desarrollo.

Diseño

Una vez marcado el objetivo vamos a ver como realizamos esta tarea. En primer lugar necesitaremos que nuestro servicio disponga de un mecanismo para obtener y validar los tokens en las diferentes peticiones que al mismo se le realicen. Al igual que para el resto de ejemplos que hemos puesto en los enlaces anteriores, el mejor mecanismo para esto parece la creación de un DelegatingHandler. Tal y como podemos ver en la documentación mediante estas piezas podremos agregar procesamiento al pipeline de ejecución de ASP.NET Web API. Por lo tanto, nuestro objetivo es crear un manejador capaz de interceptar nuestro token y validarlo. Por supuesto una vez validado crearemos los correspondientes ClaimsPrincipal en el hilo de ejecución y el contexto Http para que puedan ser usados / revisados por el resto de elementos que componen la petición. Para seguir la norma, utilizaremos la cabecera Authorization como contenedor del token a validar. Una vez dicho esto el esqueleto de nuestra pieza podría ser algo como lo siguiente:

webapi_handlers_02

    public class AALMessageHandler
        : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorization = request.Headers.Authorization;

            if (authorization != null && authorization.IsAuthorizationSchema())
            {
                var token = authorization.Parameter;

                if (IsValidToken(token))
                {
                    //set thread principal and http context user
                }

            }

            return base.SendAsync(request, cancellationToken);
        }

        bool IsValidToken(string token)
        {
            //validate the token
        }
    }

 

Con respecto a la parte de cliente no tenemos que hacer mucho más que en la anterior entrada, si acaso, lo único es ver como convertir nuestro Assertion Credential en un bearer token, pero esto con AAL es tan sencillo como podemos ver a continuación, gracias al método CreateAuthorizationHeader.

 

            string tenant = ConfigurationManager.AppSettings["tenant"];
            string realm = ConfigurationManager.AppSettings["realm"];
            using(AuthenticationContext context = new AuthenticationContext(tenant))
            {
                var credential = context.AcquireUserCredentialUsingUI(realm);

                return credential != null ? credential.CreateAuthorizationHeader() : null;
            }

 

El resultado de las líneas anteriores es que una vez un usuario es autenticado usado cualquiera de los proveedores de identidad configurados en nuestro Azure Access Control obtenemos un bearer token, representado en una cadena de texto. Un bearer token no es más que un token con la propiedad de que cualquier portador puede usar el token en los otros lugares, es decir, se elimina la necesidad de disponer de material criptográfico ( proof-of-possesion).

La implementacion

Bien, ahora que ya tenemos más o menos claro como haremos nuestro trabajo llega la hora de la implementación. Empezaremos por la parte más sencilla que es la parte de cliente, en la que además de las líneas anteriores pare obtener un token con AAL simplemente haremos una petición a un servicio de Web API cualquier, por ejemplo GET /API/Some.

            //get the bearer token using AAL
            var token = CreateToken();

            if (token != null)
            {
                //create http client
                var httpClient = HttpClientFactory.Create();
                httpClient.BaseAddress = new Uri("the base address of your web api project");

                //add default media type 
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));

                //add the token
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", token);

                //perform the request
                var request = new HttpRequestMessage(HttpMethod.Get, "api/some");

                httpClient.SendAsync(request)
                        .ContinueWith((t) =>
                        {
                            if (t.Result.IsSuccessStatusCode)
                            {
                                var content = t.Result.Content.ReadAsAsync<IEnumerable<string>>().Result;

                                //display the secret content...
                            }
                        }, TaskContinuationOptions.OnlyOnRanToCompletion);
            }

Del código anterior, la nota a destacar es el uso de la cabecera con el token recuperado de la autenticación del usuario. Cabecera que viajará en todas las peticiones realizadas con nuestro HttpClient. En el caso del servidor, del esqueleto anterior tenemos que hacer dos trabajos fundamentales. La validación del token y el establecimiento de las credenciales recuperadas. Empezemos por la primera de las tareas. Gracias a AAL, la validación de un token es casi tan sencilla como la obtención del mismo, puesto que solamente tendremos que realizar lo siguiente:

 

         //if token is bearer remove text ”Bearer ”

if ( token.StartsWith(“Bearer “) )

token =token.Substring(7);

      var tenant = ConfigurationManager.AppSettings["tenant"];
            var authenticationContext = new AuthenticationContext(tenant);
            authenticationContext.Options = options;

            principal = authenticationContext.AcceptToken(token);

Antes de nada, disculpad por el pequeño toque con el texto Bearer  del token, pero creí que era más entendible ponerlo así que tratarlo como sería en un código normal por medio de algún método de sanitización. Por supuesto, al método anterior tendremos que indicarle cuales son las opciones de autenticación, mediante nuestro objeto options, el cual podría ser algo similar a lo siguiente:

 

            var certString = ConfigurationManager.AppSettings["CertificateForAAL"];
            var certificate = new X509Certificate2(Convert.FromBase64String(certString));
            var options = new AuthenticationOptions();
            options.Audiences.Add(audience);
            options.Issuer = tenant;
            options.SigningCredential = new X509CertificateCredential(audience, certificate);

Por supuesto, el certificado seleccionado, está dado de alta en el portal de ACS en la sección Certificates and Keys, como se ven en la siguiente imagen.

 

Untitled

 

 

El casi

Umm. el casi. Bueno, el primer motivo por el que esto no está perfecto es porque AAL solamente está compilada para WIF 3.5 y por lo tanto tendremos esta dependencia. Esto es una pena si trabajamos en VS 2012 y .NET 4.5 puesto que los elementos de Microsoft.IdentityModel ya los tendremos incluídos como hemos dicho ya muchas veces. A mayores, me queda por jugar un poco con el api de cliente para otras plataformas para ver como está y de verdad darle una nota sobresaliente… amén de que estamos en beta aún :-(.

 

 

Bueno, como siempre, espero que os sea de utilidad…

 

saludos

Unai

14 Responses to AAL y Web API, una mezcla casi perfecta

  1.  

    Pingback frenmobile.com

  2.  
  3.  

    Pingback bucket trucks

  4.  
  5.  

    Pingback grapple trucks

  6.  

    Pingback security cameras

  7.  
  8.  
  9.  
  10.  

    Pingback sciatic pain

  11.  

    Pingback Ballet Workout

  12.  
  13.  
  14.  

    Pingback Fire Trucks