.NET Tiers

.NET Tiers es un conjunto de templates de CodeSmith que te permite generar las capas de acceso a datos en cuestión de minutos. Lee directamente desde la metadata de la base de datos y genera todos el código necesario para mapear las entidades y los datos.


Lo más interesante de estos templates es que siguen los patrones de desarrollo sugeridos por Microsoft e implementan los Application Blocks de la Enterprise Library.


Pueden generar código compatible con VS2003 o VS2005.


Vale la pena mirarlo: http://www.nettiers.com/default.aspx


 

Captura de Eventos en Sharepoint

Luego de instalar, configurar y rellenar documentos en Sharepoint, el administrador del portal asume tareas más complicadas como crear índices de búsqueda, optimizar seguridad y preformance, hacer backups, etc. Es un hombre feliz porque, sin mucho esfuerzo, ha logrado montar una solución de la que la mayoría de los usuarios hacen uso y, prácticamente, nadie se queja. Que maravillosa es la vida, piensa.


Cierto día, un usuario le consulta sobre como gestionar un sencillo workflow para la aprobación de documentos mediante el portal. Entonces, el administrador, busca en la documentación y descubre que lo único que puede hacer con una biblioteca de documentos es aprobar o no la publicación de un documento. Sin embargo, incursionando más en el tema, descubre que se puede anexar código a una librería de documentos para que gestione eventos tales como el agregado de un nuevo documento o la modificación de un documento ya existente. Bueno, lo primero que hace es investigar como funciona esta característica de Windows Sharepoint Services.


Se reúne con el usuario, quien le explica que se trata de un proceso de decisión muy sencillo: el documento solo puede tener tres estados: pendiente de publicar, publicado o rechazado. Cualquier usuario puede solicitar la aprobación de un documento, pero solo los editores (un grupo de usuarios en Sharepoint) pueden autorizar o rechazar la publicación de dicho documento.


El administrador decide crear tres librerías de documentos: una por cada estado. Es así que, al final de la tarea, obtiene las librerías: ParaAprobar, Aprobados, Rechazados. Luego, otorga permisos a todos los usuarios en la librería de documentos ParaAprobar de manera que cualquier usuario pueda colocar su documento para que sea revisado por los editores. En la librería de Aprobados, solo otorga permisos de escritura a los editores, mientras que solo proporciona permisos de lectura para el resto de los usuarios. Por último concede permisos de lectura para los usuarios en la librería de documentos Rechazados. Para esta misma librería, concede permisos de escritura nuevamente a los editores ya que tendrán que tener permisos para agregar todos aquellos documentos que no aprobaron.


Luego, para seguir con sus pruebas, coloca un web part de cada librería de documentos en un área que ha creado para tal fin. Parece que la cosa pinta bien. El aspecto del área de trabajo quedó como se muestra en la siguiente imagen:



Al llegar a esa instancia, se encuentra con que tiene que crear un pequeño assembly (librería en .NET) para que gestione los eventos que se produzcan en la librería de documentos. Como no tiene idea acerca de cómo hacer esto, le envía un mail de consulta a su amigo programador quien le responde lo siguiente:


 


Hola Administrador,


 


Los pasos que tienes que realizar para crear el assembly en .NET son los siguientes:


 


a)      Primero, iniciando Visual Studio, crea un nuevo proyecto de tipo Class Library.


b)      Necesitarás agregar la referencia a la biblioteca de clases de sharepoint. Para ello, agrega una referencia al proyecto y busca en la carpeta: C:Program FilesCommon FilesMicrosoft Sharedweb server extensions60ISAPI donde encontrarás el archivo Microsoft.SharePoint.dll.


c)       Luego escribe el siguiente código:


 


using System;


using Microsoft.SharePoint;


 


namespace WorkFlowCore


{


       public class Engine : IListEventSink


       {


             public void OnEvent( SPListEvent listEvent )


             {


                    if( listEvent.Type == SPListEventType.Update)


                    {


                           SPWeb web = listEvent.Site.OpenWeb();


                           SPFile file = web.GetFile(listEvent.UrlAfter);


                           SPListItem eventItem = file.Item;


 


                           if( (string)eventItem[«Estado»] == «Aprobado» )


                           {


                                  // Documento aprobado


                                                                                                            file.MoveTo(«http://localhost/Workflow/Aprobado/» +


                           file.Name,false);


                           }


                           else


                           {


                                 // Documento desaprobado


                                                                                                            file.MoveTo(«http://localhost/Workflow/Rechazado/» +


file.Name,false);


                           }


                    }


             }


       }


}


 


d)      Una vez lo tienes deberás firmar el assembly. Esto lo puedes consultar en la ayuda de Visual Studio.


e)      Recuerda cambiar el número de versión a 1.0.0.0 dentro del archivo AssemblyInfo.cs


f)        Por último, necesitarás desplegar este ensamblado en el GAC porque Sharepoint lo leerá desde ahí. Utiliza la herramienta GACUtil para hacer esta tarea.


 


Saludos.


 


Tu amigo, Programador.


 


El administrador, muy contento por haber creado el assembly sin problemas, se predispone a habilitar la captura de eventos en Sharepoint, ya que ha descubierto que esta funcionalidad, por defecto, está deshabilitada. Solo tiene que seguir los siguientes pasos:



Desde la herramienta central de configuración de Sharepoint (que se encuentra dentro de las Herramientas Administrativas) realiza lo siguiente:



·         Accede a la opción Configure virtual server settings from the Virtual Server List page desde la página principal.


·         Luego selecciona el servidor virtual sobre el cual quiere activar la gestión de eventos.


·         Selecciona la opción Virtual server general settings del grupo de opciones de Virtual Server Management.


·         Busca al final de la página el agrupado Event Handlers y lo coloca en On.


Luego, necesita enlazar el ensamblado que creó anteriormente con la librería de documentos que producirá los eventos en los cuales está interesado en atrapar. Para ello, realiza los siguientes pasos:



·         Abre el explorador de Windows y navega hasta la carpeta C:WINDOWSassembly.


·         Busca la librería que registró anteriormente y toma nota de la Versión, su cultura y la clave pública que corresponden al assembly en cuestión. Algo similar a la siguiente imagen:




 


·         Con estos datos en mente, abre el navegador y accede al portal


·         Selecciona la librería de documentos ParaAprobar y, luego, la opción Modify settings and columns


·         Luego, selecciona la opción Change advanced settings


·         Solo le resta rellenar las cajas de texto con la información que ha recolectado en los pasos anteriores. En esta página, dentro de la sección Event Handler se solicita:


o        Assembly Name: que rellena con el siguiente texto:


WorkFlowCore,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=9a1080f037b2abdd


o        Class Name: lo rellena con el nombre de la clase, es decir, WorkFlowCore.Engine


 


Ahora, lo que necesita es que cada documento tenga una propiedad que indique el estado en el cual se encuentra, es decir, si está pendiente de aprobar, está aprobado o rechazado. Para ello agrega la columna Estado a la biblioteca de documentos ParaAprobar. Los pasos detallados que administrador realiza son:


 


·         Selecciona la opción manage content desde el área en donde se encuentra la librería de documentos ParaAprobar.


·         Selecciona la librería ParaAprobar


·         Selecciona la opción Modify settings and columns


·         Selecciona la opción Add a new column


·         En column name ingresa: Estado


·         En The type of information in this column is: selecciona Choice


·         En Type each choice on a separate line ingresa Aprobado y luego Rechazado


·         Deja el resto de las opciones tal cual y presiona OK


El resultado se ve en la siguiente imagen:


 



Lo único que le resta es configurar la librería de documentos para que soporte aprobación de documentos. Para ello realiza las siguientes acciones.


 


·         Selecciona la opción Manage Content para poder acceder a la librería a configurar.


·         Luego selecciona la librería ParaAprobar


·         Una vez hecho esto selecciona la opción Modify settings and columns


·         Y, posteriormente, Change General Settings


·         En la sección Content Aproval verifica que la opción Require content approval for submitted items? está en Yes


 


Ahora ha llegado el momento de probar si su idea funciona. Para ello, agrega un nuevo documento a la librería de documentos por aprobar. Tal cual como se aprecia en la siguiente imagen:



Luego, para comprobar si el workflow funciona, accede como editor y aprueba el documento, como se muestra en la siguiente imagen:


Y, luego, al regresar al área en donde se muestran las tres librerías de documentos se puede observar que el documento ha sido movido a la biblioteca de documentos aprobados, tal como se aprecia en la siguiente imagen:



Y, luego, al regresar al área en donde se muestran las tres librerías de documentos se puede observar que el documento ha sido movido a la biblioteca de documentos aprobados, tal como se aprecia en la siguiente imagen:


 


 



Bueno, el Administrador se dice contento: tampoco ha sido tan complicado, ¿no?


 


 


 

Data Providers Factory en ADO.NET 2.0

Las versiones anteriores a ADO.NET 2.0 presentan ciertas complicaciones a la hora de gestionar distintos proveedores de datos para una misma aplicación. Parte de esta complicación sucede a raíz de que las referencias al proveedor están fuertemente tipeadas dentro del código. 


La salida está en utilizar un conjunto de clases que provean una capa de abstracción con respecto al proveedor que en definitiva se termine utilizando. ADO.NET 2.0 ya implementa esta funcionalidad a través de las Data Providers Factories. Gracias a estos constructores de instancias se puede utilizar un código agnóstico al origen de datos.


Dentro del namespace System.Data.Common están las nuevas clases que ofrecen esta funcionalidad. Para obtener una instancia de una clase se utiliza una factoría. En código:



Es recomendable utilizar una clase Helper para que encapsule el codigo de acceso a datos dentro de nuestra capa de datos.El siguiente código muestra un ejemplo muy simple:



Entonces ahora se puede utilizar el DbHelper en todos los argumentos que soliciten el proveedor de datos. Además, es posible utilizar otros elementos para abstraer las operaciones del proveedor de datos. Por ejemplo, DbCommand.



Suponiendo que el código necesitara utilizar otro proveedor de datos (por ejemplo Oracle) solo bastaría cambiar la string de conexión desde el archivo de configuración de la aplicación para que apunte al nuevo proveedor.

Developer Day 2006


El 31 de Mayo en Madrid, Microsoft organiza el Developer Day 2006.


Me ha tocado ser uno de los ponentes y mi presentación se basará sobre Seguridad en .NET.  Voy a contar sobre Role Based Security, Code Access Security y algunas cositas sobre criptografía.


Luego voy a colgar las transparencias para quien las quiera descargar.

Interceptando contraseñas de SQL

Cuando se desarrolla una aplicación Windows que acceda a una base de datos en SQL se afronta el problema de la metodología de conexión al servidor de base de datos. Es decir, ¿qué es mejor utilizar Autentificación Windows o Mixta (SQL)?



Si miramos las recomendaciones de Microsoft, no hay lugar a dudas, la conexión debe ser realizada con autentificación Windows. Sin embargo, esta opción requiere trabajo adicional y también presenta sus desventajas. 



El trabajo adicional consiste en configurar la seguridad para que cada usuario (o un grupo de ellos) pueda acceder a los recursos sin experimentar problemas de acceso por falta de permisos. También es recomendable que no se confieran a dichos usuarios más permisos de los necesarios. Y ahí está el problema, porque un usuario podrá acceder a la base de datos utilizando la aplicación pero, por desgracia, también podrá acceder desde cualquier otra aplicación menos restrictiva como por ejemplo el analizador de consultas (Query Analyzer). Esto quiere decir que un usuario podría manipular los datos de la aplicación directamente disparando comandos a la base de datos.



Estos motivos hacen que, la mayoría de los programadores, opte por utilizar una autentificación mixta y pasar el nombre de usuario y contraseña en la string de conexión. Esta forma de trabajar garantiza que solo la aplicación puede acceder a la base de datos independientemente de los permisos del usuario que la utiliza. Pero, ¿qué tanto riesgo existe en colocar las credenciales en la aplicación?



Si se utiliza una autentificación SQL para conectarse a un servidor, será necesario guardar la contraseña en algún lugar para proporcionársela al servidor cuando la aplicación necesite conectarse. Las alternativas pueden ir de una solución muy simple y poco segura (tal como almacenarla en el mismo código) a más compleja como por ejemplo utilizar archivos de configuración y cifrar su contenido.



No obstante, sea cual sea la mecánica que se utilice para almacenarla, la aplicación enviará, tarde o temprano, (por la red) esta información al servidor en texto “casi” plano por lo que puede ser interceptada por un hacker.



La intención de este artículo es demostrar lo simple que resulta obtener las credenciales de usuario utilizadas en una string de conexión que se utiliza para extraer información de un servidor SQL.



Para ello, lo primero que hace falta es una aplicación que se conecte a SQL Server utilizando la autenticación básica y luego utilizar una herramienta para interceptar el tráfico de red entre el servidor y el cliente.



En mi caso, voy a utilizar Network Monitor de Windows para monitorizar el tráfico entre las partes.



 


Nota: Esta herramienta viene con el sistema operativo, pero no se instala por defecto. Para agregarla se debe utilizar el panel de control. Los pasos son:


·          Star -> Control Panel -> Add/Remove Programs


·          Add Remove Windows Components


·          Seleccionar Management a Monitoring Tools


·          Hacer click en el botón Details


·          Marcar Network Monitor Tools


·          Presionar OK


·          Presionar Next



El escenario que he utilizado para escribir este artículo es muy simple: consta de un pc cliente con la aplicación que accederá al servidor de base de datos que se encuentra en otra PC. De ahora en más los llamaré PC Cliente y Servidor, respectivamente.



En el PC Cliente he instalado Network Monitor aparte de la aplicación que voy a utilizar para disparar consultas a la base de datos.



Por cuestiones de sencillez he guardado la cadena de conexión en el mismo código. Aunque recomiendo no hacer esto. Es muy fácil ver el código fuente a partir de un ensamblado (Ver http://www.aisto.com/roeder/dotnet/). Incluso se puede pensar que basta con utilizar el ofuscador de código que viene con Visual Studio para esconder el contenido de la cadena de conexión, pero esto no es así. En la versión gratuita del ofuscador no se pueden cifrar strings. Por lo que el código si queda ofuscado, pero el contenido de la string de conexión sigue siendo visible.



Mi aplicación tiene el siguiente código (porción que interesa):




Entonces, antes de ejecutarla, debo iniciar el Network Monitor e indicarle que escuche la información transmitida entre la PC Cliente y la PC Servidor.


Para ello sigo los siguientes pasos:


·          Start -> Programs -> Administrative Tools -> Network Monitor


·          Ya dentro de Network Monitor, selecciono Capture -> Start


·          Ahora que está monitorizando el tráfico, ejecuto mi aplicación cliente para que se conecte al servidor de base de datos.


·          Una vez ha concluido la consulta, vuelvo al Network Monitor y selecciono la opción Capture -> Stop and View


·          Network Monitor me muestra todo el tráfico capturado.



Dentro de esta información recolectada es donde, en alguna parte, se encuentran las credenciales de usuario enviadas por la aplicación cliente.


Es importante saber que, prácticamente, todos los datos de la cadena de conexión viajan en texto plano, por lo que es muy sencillo encontrar la información mirando los paquetes SMB, tal como se muestra en la siguiente imagen:


 





La parte más interesante es que la contraseña viaja cifrada, aunque el mecanismo que se utiliza para esconder su contenido es bastante simple y por lo tanto muy poco seguro.


Veamos como cifra el cliente la password cuando contacta con el servidor:



 



Si miramos con atención hay un conjunto de siglas prácticamente ilegibles que siguen un patrón bastante simple. Se trata de la contraseña que el cliente ha cifrado. En la siguiente imagen se puede apreciar que por cada byte, a la derecha, aparece un byte repetido (A5).


Es factible buscar este byte seleccionando las opciones: Display -> Find Next Frame. En la pestaña Property, seleccionar SMB -> Data y, verificando que la opción Contains está seleccionada ingresar el valor A5. Al presionar OK se visualiza la trama correspondiente.



Hasta aquí hemos obtenido el nombre de usuario utilizado por la aplicación y un conjunto de Bytes que representar el password. Si bien la contraseña parece estar cifrada se trata de un mecanismo muy sencillo de ofuscación utilizando la operación XOR. Para descifrarlo lo único que hace falta es realizar los siguientes pasos:



a)      Invertir todos los bytes que contienen la contraseña:


      Original: A2 B3 92 92 D2 53 82 E3


      Convertido: 2A 3B 29 29 2D 35 28 3E


b)      Aplicarles un XOR con 5A (que es el valor invertido de A5)


      2A (XOR) 5A =  70


      3B (XOR) 5A = 61


            29 (XOR) 5A = 73


            29 (XOR) 5A = 73


            2D (XOR) 5A = 77


            35 (XOR) 5A = 6F


            28 (XOR) 5A = 72


            3E (XOR) 5A = 64


 c)       Convertir a decimal y ver su representación ASCII:


            112,  p


             97,   a


            115,  s


            115,  s


            119,  w


            111,  o


            114,  r


            100,  d


Conclusión:



Si utiliza autenticación mixta debería utilizar simultáneamente algún mecanismo que cifre el tráfico entre el cliente y el servidor. Algunas opciones posibles son IPSec o SSL.

Se va la primera…!!!


Como consumidor habitual de los blogs me resulta un tanto extraño que sea hoy yo el propietario de este humilde chiringuito.


Seguramente estoy en deuda con todas aquellas personas que han dedicado desinteresadamente muchas horas de investigación y que me han ayudado, a través de sus publicaciones, a solucionar infinidad de problemas o me han maravillado con sus increíbles descubrimientos. Por este motivo, y gracias a la oportunidad que me ha brindado Rodrigo Corral y el grupo de MVPs al invitarme a esta empresa, quiero retribuir humildemente este esfuerzo mediante mis experiencias y conocimientos en el día a día con .NET y sus derivados.


He decidido titular este Blog .NET Storm (Tormenta .NET) porque refleja mi situación actual con la tecnología, siempre peleando con nuevos productos, sistemas o aplicaciones que entran de manera desordenada en mi vida clamando que mi pobre cabeza las entienda y les saque el máximo provecho. Aunque no siempre logro mi cometido, en el camino, recojo experiencias que creo que debo compartir con la comunidad de desarrolladores como muchos otros lo hacen.


Respecto al contenido seguramente encontrarán un collage de tópicos relacionados con productos tales como Biztalk Server, Sharepoint Portal Server, Reporting Services, Visual Studio, y cuanta cosa me caiga en las manos.


Este es mi granito de arena. Espero que ayude en la construcción de vuestro castillo.