ASP.NET MVC + WIF

Últimamente tengo poco tiempo para postear, mucho menos de lo que debería seguramente, y entre tarera y tarea a veces surgen temas como el que voy a contaros que quizás sean de ayuda para otras personas, eso espero por lo menos. En casi toda la documentación  y ejemplos de WIF se tocan los RP pasivos con clientes de ASP.NET tradicional. Si bien, seguramente aún hoy por hoy estos serán mayoría en los desarrollos actuales, seguro que, muchos estaréis pensando empezar vuestros proyectos en ASP.NET MVC e intentar integrar Windows Identity Foundation para delegar todo el trabajo de autenticación. A continuación intentaré mostraros los pasos necesarios para realizar esta tarea y aquellos detalles que debéis de tener en cuenta.

Lo primero que haremos será partir de una aplicación MVC, cualquiera de los tipos de aplicación vale(internet,intranet,empty), una vez hecho esto, procederemos a agregar la referencia al STS con el que queremos trabajar. Como hemos hecho otras veces, esto lo realizaremos con la integración de las tools de WIF en Visual Studio, gracias a las cuales en los menus contextuales de nuestros proyectos web tendremos la entrada “ Add STS Reference” ( si no has visto nada de WIF, te recomiendo las entradas siguientes ( 3-1 y 3-2) antes de seguir)

 

Seguiremos el asistente de WIF como hasta ahora hemos hecho en todos los ejemplos, en nuestro caso, creando un nuevo STS y adjuntándolo a la solución, imagen siguiente:

Untitled

Una vez completado el asistente podremos ver como en nuestra solución se ha incluído el nuevo proyecto del STS y además, se ha modificado “notablemente” el archivo de configuración de nuestro cliente MVC. Intentareamos ir desgranando todo lo que ha pasado con este asistente poco a poco:

 

Modificación del web.config del cliente mvc

 

Una vez terminado el asistente, FedUtil.exe, nuestro web.config ha cambiado en unos cuantos puntos para agregar aquellos elementos necesarios para trabajr con WIF. En primer lugar, se ha incluído una nueva sección de configuración, llamada Microsoft.IdentityModel tal y como podemos ver a continuación:

 

 

Esta sección de configuración, nos permite establecer la configuración necesaria para trabajar con wif, por defecto la que vemos a continuación:

 

<microsoft.identityModel>

  <service>

    <audienceUris>

      <add value="http://localhost:1477/" />

    </audienceUris>

    <federatedAuthentication>

      <wsFederation passiveRedirectEnabled="true" issuer="http://localhost:2511/MVCRP_STS/" realm="http://localhost:1477/" requireHttps="false" />

      <cookieHandler requireSsl="false" />

    </federatedAuthentication>

    <applicationService>

      <claimTypeRequired>

        <!–Following are the claims offered by STS ‘http://localhost:2511/MVCRP_STS/’. Add or uncomment claims that you require by your application and then update the federation metadata of this application.–>

        <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />

        <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />

      </claimTypeRequired>

    </applicationService>

    <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

      <trustedIssuers>

        <add thumbprint="6C6CE1DA53CE9F34F9DB4FFFAADDA8D84468C6BF" name="http://localhost:2511/MVCRP_STS/" />

      </trustedIssuers>

    </issuerNameRegistry>

  </service>

</microsoft.identityModel>

 

Algunos de estos elementos ya los hemos comentado, aún así, para no tener que andar viajando de entrada a entrada, volveremos a destacar los más importantes:

  • audienceUris: Nos permite indicar la URI del cliente ( Relay Party), de forma general, el STS comprueba si el RP es válido para trabajar con el STS por medio del AudicenUri que se establece aquí.
  • IssuerNameRegistry: Mecanismo para comprobar que el certificado que utiliza el STS para cifrar los tokens es admisible por el RP, por defecto siempre se incluye un mecanismo que comprueba el thumbprint. El asistente, al crear un nuevo STS nos ha incluido un certificado llamado STSTestCert ( certificado autogenerado ) cuyo thumbprint es el que se ve aquí. Hablaremos más adelante sobre algún detalle de este certificado.

Otro de los detalles importantes en cuanto al cambio de la configuración de nuestro web.config, es que se han incluído dos nuevos módulos WSFAM y la SAM:

 

Estos módulos se encargan realmente de todo el trabajo, de redirigir las peticiones de usuarios no autenticados al STS, de guardar el token en la sesión, de recuperar este token entre distintos Request, y alguna cosa más que por ahora no es necesario comentar. Llegados hasta aquí, parece que todo el trabajo está hecho y comentado o sea que vamos a probar nuestro ejemplo, hacemos F5 y vemos que nuestro cliente MVC ( el RP ) automáticamente hace una redirección al STS para autenticarse en esta pieza, en nuestro ejemplo la uri de redirección sería algo como la siguiente:

http://localhost:2511/MVCRP_STS/Login.aspx?ReturnUrl=%2fMVCRP_STS%2fdefault.aspx%3fwa%3dwsignin1.0%26wtrealm%3dhttp%253a%252f%252flocalhost%253a1477%252f%26wctx%3drm%253d0%2526id%253dpassive%2526ru%253d%25252f%26wct%3d2011-10-06T08%253a46%253a50Z&wa=wsignin1.0&wtrealm=http%3a%2f%2flocalhost%3a1477%2f&wctx=rm%3d0%26id%3dpassive%26ru%3d%252f&wct=2011-10-06T08%3a46%3a50Z

Fíjese que en la query string hay elementos importantes como dwsignin ( nos vamos a autenticar ) wtrealm ( el audience uri) y alguno más como el contexto de la fecha etc etc… Esta redirección nos lleva hasta la página por defecto del STS, en la cual podremos incluir nuestras credenciales. Si hemos creado el STS, lógicamente tendremos que tocar esta pieza, tanto para todo lo que tenga que ver con estilo como la implementación correcta de la autenticación, selección del repositorio etc.

Untitled2

 

Bien, una vez auténticados, en el STS por defecto no es necesario poner una password podemos ver que nos encontramos con un error de lo más explícito. Concretamente el error es:

“System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (wresult="<trust:RequestSecuri…").”

 

Esto, es debido a que el proceso de autenticación y creación del token implica un post a nuestro RP, concretamente podeis ver este proceso dentro del Default.aspx.cs del STS

Para arreglar este problema tenemos dos opciones, la más rápida y también la mas mala es cambiar el modo de validación de los request a 2.0 y establecer el validateRequest de la página a false. Lógicamente esto representa un compromismo de seguridad importante que no deberíamos admitir. La otra solución, es crearnos un RequestValidator personalizado. Para ello, lo único que tendremos que hacer es agregar una entrada en el system.web de nuestro config como la siguiente:

Dónde WsFederationRequestValidator es el siguiente validador ( básicamente comprueba que en el request hay una clave de coleccón “wa” y es una respuesta de SignIn de un STS):

Ahora parece que si, que ya lo tenemos todo. Volvemos a probar y efectivamente, después de la redirección y el sigin ya podemos entrar a nuestro RP MVC:

 

Untitled3

Hasta ahora hemos visto casi todo lo relacionado con nuestro RP, y como solucionar el problema de los request no válidos, sin embargo, no sabemos por ahora nada de lo que el asistente haya hecho con respecto a nuestro nuevo STS. Algunas consideraciones interesantes son las referidas al uso de los certificados y como manejar estos en producción.  A continuación detalleremos esto un poco más.

 

Como seguramente ya sabéis el STS genera un colección de claims y las envuelve en un token de seguridad. Este token, para mantener su privacidad y que no se pueda alterar suele ( siempre ) ir firmado con un certificado digital. Por defecto, cuando creamos un STS automáticamente el asistente FedUtil nos crea e incluye en el almacén un certificado llamado STSTestCert.

 

Untitled4

 

Este certificado, se utiliza, como demuestran las siguientes lineas de código, dentro del Custom Security Token Service creado por el STS para encriptar los claims:

 

Un problema habitual, es que cuando pasamos a producción y seguimos utilizando un certificado autogenerado es que la raiz de certificación no sea de confianza, por eso, si vais a hacer algun despliegue, por ejemplo en vuestro entorno de build, con un certificado de prueba tenéis que aseguraros que este certificado también se encuentre en los certificados de confianza de la máquina ( Trusted People). A mayores, si el despliguen en vuestro entorno de build lo hacéis en IIS, tenéis también que aseguraros que el usuario que corra el pool de IIS tenga permisos para acceder a la clave privada del certificado.

 

 

Ahora, que ya hemos cerrado el tema de los certificados nos quedan algunos  elementos importantes que ver:

 

  • Gestión de los claims en el cliente MVC: Bien, ahora ya hemos delegado la autenticación, pero como utilizamos el token resultado para validar por ejemplo la ejecución de uná acción de un controlador o retrigir controles en las vistas?. Respuestas a esto hay muchas, en realidad tantas como variantes de implementación podamos dar, puesto que, una vez que nos hemos autenticado con nuestro STS dentro de nuestro RP HttpContext.User contendrá un elemento de tipo IClaimsPrincipal con la información de la identidad autenticada y la lista de claims de las que dispone, es decir, con toda la información que necesitemos. De forma general, el trabajo de filtrado de acciones de controladores lo podemos hacer de forma declarativa utilizando algún filtro de autorización personalizado basado en las claims del usuario autenticado..( esto lo dejo para otra ocasión ).
  • Elementos no autenticados en un RP: Por supuesto, no todas las secciones de una cliente necesitan estar autenticadas, sin embargo, tal y como lo hemos hecho en nuestro ejemplo si tenemos este comportamiento. Para modificarlo, y decidir que controladores necesitan autenticación podríamos realizar los siguientes pasos:
    • Establecer el allow users a todos en nuestro elemento authorization de configuración del RP ( <allow users="*"/>)
    • Crear un filtro de autenticación que obligara a los controladores (o acciones ) en los que lo situemos a realizar la autenticación con el STS, es decir, algo similar a lo siguiente:

 

Os cuelgo una aplicación de ejemplo aquí.

 

Espero que os resulte de interés

 

Unai

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *