Intellitrace como tu sistema de rastreo

Hace ya un pequeño tiempo, observé desde la distancia una “discusión” acerca de las implementaciones de logging y tracing en nuestras aplicaciones. Lógicamente, muchos de los argumentos de este tipo de discusiones ya son más que de sobra conocidos, unos tiran por AOP otros les gusta la intercepción etc, etc.. Mi compañero Rodrigo, metido en esa conversación intentó primero hacer una diferenciación entre lo que realmente es logging, como información del proceso, y las trazas como información de rastreo únicamente válida para nosotros como desarrolladores. Después de este pequeño, pero importante inciso, alegó que pensar hoy en dia en “inventar” el sistema de trazas caía un poco dentro de “Reinventent the wheel” puesto que si trabajábamos en Visual Studio 2010 teníamos algo llamado Intellitrace.

Seguramente muchos conoceis intellitrace de vuestros procesos de depuración con VS, sin embargo, también es posible utilizar Intellitrace fuera de visual studio y llevarlo por ejemplo a un entorno de producción para hacer una sesión de depuración en caso de necesitarlo. A lo largo de la siguiente entrada veremos los pasos necesarios para realizar esta tarea, y como, gracias a Intellitrace, nuestras posibilidades en cuanto a las trazas se verán incrementadas enormemente:

 

  • Requisitos

Lo primero siempre es lo que necesitamos, y en este caso, los requisitos necesarios para correr intellitrace viene marcados por una serie de archivos que tendremos que llevar a nuestro entorno, es importante notar que no requiere instalación tradicional ninguna.

  1. Intellitrace.exe, %ProgramFiles%Microsoft Visual Studio 10.0Team ToolsTraceDebugger Tools.
  2. Intellitrace.exe.config,  %ProgramFiles%Microsoft Visual Studio 10.0Team ToolsTraceDebugger Tools.
  3. TraceLogProfiler.dll, %ProgramFiles%Microsoft Visual Studio 10.0Team ToolsTraceDebugger Tools.
  4. Microsoft.VisualStudio.Intellitrace.dll %ProgramFiles%Microsoft Visual Studio 10.0Common7IDEPublicAssemblies.
  5. CollectionPlan.xml,%ProgramFiles%Microsoft Visual Studio 10.0Team ToolsTraceDebugger Tools.
  • Puesta en marcha

Una vez que hemos llevado estos requisitos hasta nuestro entorno, veremos como ejecutar intelligrace para un proceso, en mi caso, para el ejemplo he creado una pequeña aplicación de consola que trabaja con una base de datos, escribe un fichero, y accede a registro. La idea, es poder observar todo este trabajo desde el resultado de la ejecución de intellitrace.

Levantaremos una linea de comandos y ejecutaremos algo como lo siguiente:

Intellitrace.exe launch cp:/CollectionPlan.xml /f:Out.itrace “pathsample.exe”

Si se fija, los dos parámetros importantes de esta llamada son cp:/CollectionPlain y /f:Out.xml. CollectionPlan.xml nos permite especificar que es lo que queremos recopilar en nuestra sesión de trazas, es decir, la información que deseamos ver. El segundo parámetro, por otro lado, nos permite establecer el fichero de salida, el cual después llevaremos hasta un entorno con Visual Studio sobre el que podamos ver y analizar los resultados. Antes de empezar la ejecución, abriremos nuestro fichero de collectionplan.xml, buscaremos el elemento TraceInstrumentation y estableceremos el atributo enabled a true.

  <TraceInstrumentation enabled="true">

  • Análisis de resultados

Bien, una vez que ya hemos ejecutado Intellitrace y obtenido el fichero de resultado ( nuestro *.iTrace) lo llevaremos hasta un equipo con Visual Studio, en este podremos ver algo similar a lo siguiente:

Untitled1

Realmente, aquí ya es similar a como si estuviésemos en una sesión de Visual Studio normal, podéis probar a ver los eventos de intellitrace, las llamadas a métodos, rebobinar etc etc….

 

  • Queremos más

La información de llamadas a métodos, variables, hilos o módulos cargados no siempre es suficiente. Gracias a nuestro archivo CollectionPlan.xml podemos ir configurando la información que deseamos incluir en nuestros ficheros de Intellitrace. Algunos eventos importantes son acceso a disco, ADO.NET, uso de registro etc etc… A continuación se puede ver la interacción con ADO.NET de nuestra pequeña aplicación de ejemplo.

untitled2

 

  • Ojo con el licenciamiento

En principio el uso de Intellitrace en producción es algo que se escapa a la licencia de Intellitrace, aunque es algo que no tengo tan claro si es solamente al soporte o una prohibición por algún motivo. Hay un post aquí dónde tocan este tema y se pueden extrar algunas conclusiones.

  • ´Más información

Sobre la linea de comando de intellitrace hay mucha información repartida en la web, para aquellos que deseais saber más os recomiendo empezar con algunos enlaces que os ayudarán en las primeras dudas:

http://blogs.msdn.com/b/ianhu/archive/2009/11/16/intellitrace-itrace-files.aspx

//especialmente interesante si quieres hacer intellitrace de algo que no sea un .exe, por ejemplo  IIS, un servicio de windows, etc..

http://blogs.msdn.com/b/msaffer/archive/2010/12/07/using-intellitrace-outside-the-ide.aspx

http://blogs.msdn.com/b/ianhu/archive/2010/05/25/intellitrace-links.aspx

Espero que esto os resulte de interes

 

Saludos

Unai

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