Autenticación con AgilePoint y el uso de Surrogate (2ª Parte)

En un artí­culo anterior hablábamos de la autenticación con AgilePoint y la surrogación. Echaba en falta algíºn gráfico que dejara algo más clara la forma de trabajar, así­ que lo adjunto en esta segunda parte.

Esquema Surrogate
Esquema Surrogate

Como véis, se aprecian las tres combinaciones de las que se habla en la primera parte.

  • Opción A: Usuario a través de un navegador web, el servidor web tiene que impersonar al usuario llamante.
  • Opción B: Usuario a través de aplicación de escritorio que trabaja contra una capa de servicios, el servidor de negocio tiene que impersonar al usuario llamante.
  • Opción C: Usuario a trvés de aplicación de escritorio que trabaja directamente con servicios de AgilePont, no hace falta impersonación, el propio usuario pertenece al dominio y se autentica directamente con sus credenciales de red.

Pocos artí­culos íºltimamente. Mucho trabajo.
Saludos!
Miguel.

Autenticación con AgilePoint y el uso de Surrogate

Una de las principales capacidades que ofrece AgilePoint como producto, es la orientación a servicios que han dado a la solución de software. Para ello, en la versión 4.0 de la herramienta ofrecen en concreto dos servicios que agrupan todos los métodos que permiten acceder a la funcionalidad del motor.
workflow.asmx
Servicio que encapsula todos los métodos asociados a la manipulación de los flujos (incluyendo por ejemplo servicios para instanciar plantillas, obtener información de un proceso, establecer el valor de una de las propiedades de un proceso…).
admin.asmx
Servicio que encapsula todos los métodos asociados a la administración del propio motor (incluyendo por ejemplo servicios especí­ficos para la creación de usuarios, permisos, roles…).
A priori, con estas dos piezas, y desde cualquier tipo de tecnologí­a cliente, podrí­amos manipular el BPM desde una aplicación cliente creada por nosotros mismos.
La pieza que aquí­ nos falta es conocer cómo se protege AgilePoint para que no todos los usuarios que tengan acceso a dichos asmx puedan utilizarlos para acceder al motor y manipularlo a su gusto. Como comprenderéis, si no existiera dicha autenticación estarí­amos hablado de un fallo de seguridad como la copa de un pino.
El requerimiento indispensable para poder acceder a los servicios, es que el mismo objeto que está realizando la conexión al servicio cuente con las credenciales de red del usuario que está haciendo la llamada. Esto ya en principio garantiza que la persona que está llamando al servicio está autenticada en el dominio, que quieras que no, supone una primera barrera de seguridad. Pero esto, no es suficiente, ya que necesitaremos que el usuario que esté haciendo la llamada también esté dado de alta en la propia base de datos de usuarios de Agilepoint. Como curiosidad, remarcar que la propia herramienta de gestión de usuarios de AgilePoint provee de facilidades para sincronizarse con el directorio activo e importar la información de los usuarios de dicho directorio a la base de datos de usuario de AgilePoint.
Resumiendo, si disponemos de nuestras credenciales de red validadas, se las pasamos a AgilePoint y nuestro usuario está también incluido en el repositorio de usuarios de AgilePoint, olé, ya podemos usar los servicios sin problemas.
Pongamos por ejemplo que estamos trabajando con una aplicación de escritorio que referencia los servicios web de AgilePoint directamente. Siguiendo este procedimiento, conseguiremos autenticarnos sin problema.
La casuí­stica complicada viene cuando por ejemplo trabajando en web, o en el caso de que no conectemos directamente con nuestra aplicación al servicio, si no que tengamos otra aplicación que haga la conexión en nuestro nombre. Estarí­amos hablando de una tí­pica aplicación web, donde el usuario que la está ejecutando es del del pool del servidor de aplicaciones y no la persona que ha abierto el navegador en su casa… o en el caso de que nuestra aplicación de servicios no ataque directamente a los servicios de AgilePoint si no que llame a una capa de negocio con orientación a servicios que sea la que se encargue después de llamar a Agilepoint. En ambos casos tenemos “algo”por enmedio que tiene sus propias credenciales que no son precisamente las nuestras.
Ante este problema tenemos una primera solución para lograr la autenticación, nos creamos un usuario para ese “algo” intermedio en nuestro directorio activo, lo damos de alta también en la base de datos de Agilepoint, y ala, cuando llamemos al “algo” este se podrá autenticar y hacer el trabajo sin problemas. Esto funciona, pero tiene un problema de base, que todos los usuarios trabajarán contra el BPM usando el mismo usuario, y esto va en contra del funcionamiento basado en flujos.
Como hemos tratado ya en otros artí­culos, uno de los componentes principales de un motor de flujo es el responsable de cada una de las tareas definidas en el flujo de trabajo. Parte de la gracia de este sistema de trabajo es que la persona que conoce el negocio define las responsabilidades de cada uno de los pasos a seguir, y a partir de esta responsabilidad, los usuarios asignados tendrán constancia de que tienen que realizar cada una de las tareas. Imaginaos entonces que siguiendo un flujo determinado se asigna la responsabilidad de las tareas generadas a una serie de usuarios. ¿Cómo voy a conseguir entonces preguntarle al motor de flujo que me de las tareas de dicho usuario especí­fico si siempre estoy haciendo login a través de un usuario intermedio comíºn a todos? En este caso todos serí­amos el mismo usuario y recibirí­amos siempre las mismas tareas.
Después de toda la puesta en situación inicial llegamos entonces al punto clave y objetivo del artí­culo, el Surrogate. Mediante la “surrogación” (no creo que esté este palabro en ningíºn diccionario) conseguimos decir en la autenticación que el usuario intermedio comíºn a todos hable en nombre de otro. Es decir, nos autenticamos igual, pero en un momento dado dicho usuario le dice a AgilePoint: “Oye tí­o, yo soy el que me autentico siempre, estas son mis credenciales y seguro que además me tienes en tu base de datos, y, a partir de ahora mismo todas las operaciones que voy a mandarte las voy a hacer en nombre de Pepe, por lo tanto, cuando te pida que me des todas las tareas en estado ofrecido me estoy refiriendo a las de Pepe, y cuando te diga que proceses una tarea lo vas a hacer también en nombre de Pepe”.
Claro está, “Pepe” va a tener que estar dado de alta en el repositorio de usuario de AgilePoint, o si no por mucho que le diga “el de siempre” que va a hablar en nombre de “Pepe”, AgilePoint va a responder: “no sé de quién me estás hablando”.
A partir de aquí­, para ver a nivel de código cómo funciona esto, os dejo un link de la página de Ascentn donde podéis ver el ejemplo:
Ejemplo KB-Ascentn
Para acabar, y como podréis ver en el link que os acabo de dejar, no todos los usuario disponibles en el repositorio de usuarios de AgilePoint tienen la capacidad de hablar en el nombre de otros. Para disponer de dicha capacidad, se debe dar de alta el usuario como “Impersonator” a través de la herramienta de configuración del servidor de AgilePoint.
Espero haberme explicado con suficiente claridad, no es precisamente fácil intentar trasladar el uso del Surrogate.
Saludos.
Miguel.

Ejemplos Prácticos del uso del Principio de KISS

En posts anteriores hablamos ya alguna vez del Principio de KISS. Hoy toca un ejemplo práctico. íšltimamente no paro de cruzarme con situaciones en las que el principio resulta una premisa básica. Para qué complicarse cuando hay soluciones sencillas y facilmente mantenibles que cumplen el requerimiento funcional suficientemente y hacen que el cliente obtenga su objetivo.
Como ejemplo, un botón, no sé si disponéis de una cuenta de Gmail, si es así­, podréis comprobar que en las opciones de un e-mail tenéis la de imprimirlo. Hay miles de formas diferentes de provocar una impresión desde web, y la que ha elegido Google es la siguiente:
1) Al pulsar sobre el botón de imprimir se abre una ventana emergente y se carga el texto relacionado al e-mail más información básica de las direcciones implicadas, además aparece también en la parte superior el logo de Gmail
2) A continuación, tras la carga, se lanza una sentencia javascript que provoca que en el cliente se lance el cuadro de diálogo de selección de impresora.
3) El cliente selecciona la impresora y se imprime el contenido actual.
Ala fin. Así­ de simple. Si quieres imprimir un e-mail, lo imprimes sin problemas, que ese era tu objetivo.
¿Para qué complicarse más?
Saludos.
Miguel.

¿Servicios Web Polimórficos? (Parte 2 – Solución con WCF y Framework 3.5)

Hace ya bastantes artí­culos atrás estuvimos hablando de Servicios Web y Polimorfismo (aquí­). Introdujimos el tema y le dimos alguna vuelta a la necesidad de poder aplicar el concepto de polimorfismo a las llamadas de un servicio web. Es más, incluso lo intentamos utilizando Servicios Web en .NET mediante el Framework 2.0… y… comprobamos que no era posible.
Quedaron abiertas otras soluciones, pero hasta el momento no habí­a podido invertir tiempo en este tema, así­ que ahora que ya tengo algo que mostraros, allá vamos!
Para empezar, como habréis podido observar la solución parte del uso de WCF (Windows Communication Foundation). En concreto para la solución he empleado Visual Studio 2008 y el Framework 3.5 (remarco lo de la versión del Framework, ya que esta misma solución utilizando el WCF y el Framework 3.0 no os va a funcionar, ya que no se hace igual). Estamos de suerte y la solución con el Framework 3.5 la verdad es que es sencillí­sima.
Paso a mostraros fragmentos de código sueltos y luego os adjuntaré el proyecto para que podáis ver y probar vosotros mismos que funciona. Eso sí­, avanzo que el código del proyecto es simplemente para probar el funcionamiento así­ que le faltarán comentarios y demás cosas que intentaré añadir directamente aquí­.
Bien, antes de nada empezar diciendo que voy a intentar seguir la guí­a del primer intento que hicimos de Servicios Web Polimórficos, en la que la idea era conseguir tener un íºnico Servicio Web que nos ofreciera la posibilidad de realizar el mantenimiento de infinitas entidades de datos, en lugar de tener un servicio diferente para cada una de ellas. Para hacerlo necesitábamos que el cliente que consume el servicio recibiera en la definición de su WSDL las clases que implementaban la interfaz IDTO, pero no habí­a manera de que la aplicación de servicios al generar el WSDL lo hiciera de forma automática.
La idea serí­a tener un servicio web que tuviera métodos como los siguientes (para los que no conozcan la teorí­a de los DAO, DTO y Factorí­as, podéis encontrar literatura en la categorí­a de patrones de este mismo blog):
public void Insert(IDTO dto)
{
    Factory.GetDAO(dto).Insert(dto);
}
public void Update(IDTO dto)
{
    Factory.GetDAO(dto).Update(dto);
}
public void Delete(IDTO dto)
{
   Factory.GetDAO(dto).Delete(dto);

Como véis esto serí­a la leche ya que cualquier llamada al servicio serí­a capaz de ejecutar la acción independientemente del DTO que le llegue…
Por aquí­ dejo el código de la factorí­a, que como véis, segíºn el DTO que recibe, retorna el DAO correspondiente.
public class Factory
{
   public static IDAO GetDAO(IDTO dto)
   {
       if (dto is CocheDTO)
       {
          return CocheDAO.GetInstance();
       }
       else if (dto is MarcaDTO)
       {
          return MarcaDAO.GetInstance();
       }
       throw new Exception(“no existe este dto”);
    }
}
Además, como podréis observar, todos los DAO heredan de IDAO, que es quien define los métodos con los que un DAO puede trabajar, y es lo que usa la factorí­a para actuar con independencia.
Pero bueno, vamos al grano y a lo que interesa, que es cómo conseguir que se entere el cliente que recibe el servicio de los DTO que pueden heredar de IDTO. La clave está cuando definimos la clase IDTO.
[DataContract]
[KnownType(typeof(DTO.CocheDTO))]
[KnownType(typeof(DTO.MarcaDTO))]
public class IDTO
{
}
Sobre la clave DataContract, ya hablaremos cuando hagamos la introducción a WCF, en lo que quiero que os fijéis es en las claves KnowType. Aquí­ es donde estamos marcando al servicio que IDTO tiene como tipos conocidos otras clases, que son las que heredan de ella. Por cierto, habréis visto que IDTO es una clase y no un interfaz… por lo visto el atributo KnowType no puede utilizarse con interfaces, pero bueno nos da lo mismo en este caso.
Con todas estas combinaciones que os he presentando, y si probáis el ejemplo donde tenéis más código, veréis que en el cliente que se ha montado (que es una aplicación de escritorio con un botón), podréis leer el siguiente código:
Servicio.MiServicioClient cliente = new Servicio.MiServicioClient();
Servicio.CocheDTO coche = new Servicio.CocheDTO();    
Servicio.MarcaDTO marca = new Servicio.MarcaDTO();     
coche.Codigo =1;
coche.Matricula=”IB-4444-TRT”;
coche.NumeroPuertas=1;
cliente.Insert(coche);
marca.Codigo = 4;
marca.Nombre = “Mercedes”;
marca.Pais = “España”;
cliente.Update(marca);
Bingo! El cliente es capaz de instanciar objetos que no son retornados o pasados por parámetro explí­citamente por un método de un servicio (que era uno de los problemas que tení­amos con el Framework 2.0). “Mágicamente” podemos utilizar los DTO en cliente, rellenarlos y pasárlos a los correspondientes métodos de Insert y Update. Al llegar la petición al servicio, la factorí­a decide el DAO a llamar en tiempo de ejecución y a correr.
Con un íºnico servicio podrí­amos realizar toda la fachada para mantener y consultar infinitas entidades de negocio. ¡Objetivo cumplido!
Os invito a descargar la solución de ejemplo que os adjunto y a lanzarla en modo debug, veréis que si lo seguí­s la ejecución mantiene el flujo que hemos definido sin problemas.
Servicio WCF Polimórfico
Saludos.
Miguel.

AIR

¿Habí­ais soñado alguna vez con la posibilidad de convertir vuestras aplicaciones web directamente como ejecutables en vuestro escritorio? Pues parece que alguien ha escuchado vuestras plegarias.
AIR (Adobe Integrated Runtime) es la nueva baza de Adobe para poder desarrollar fácilmente aplicaciones de escritorio a partir de aplicaciones web. ¿Parece el mundo alrevés verdad? Esta nueva forma de producir software intenta resolver los siguientes problemas:
1) Conseguir que el coste de formación de un desarrollador píºramente web sea mí­nimo cuando se deba poner a trabajar con aplicaciones de escritorio.
2) Totalmente multiplataforma, íºnicamente debemos tener el runtime de AIR instalado en la máquina a ejecutar (linux, windows, iphone…)
3) Crear aplicaciones todo-terreno que sean capaces de ejecutarse tanto como si existe conexión a internet como si no.
4) Dotar a aplicaciones puramente web y desarrolladas con HTML, Ajax, Flex (también de Adobe) o Flash de habilidades píºramente de escritorio, como acceso a recursos locales, portapapeles, base de datos local, etc).
A mi en principio me ha dejado algo fuera de sitio la noticia, sobre todo porque sigo creyendo que aquí­ en España lo normal es que exista mucha más experiencia en desarrollo de aplicaciones de escritorio que aplicaciones web. Es más, lo normal es tener dificultades en encontrar profesionales con experiencia web suficiente… entonces, claro está, la mejora que hemos catalogado como níºmero 1 deja de tener valor.
Sobre la multiplataforma, chapó, está claro que es una ventaja indiscutible.
En cuanto a las aplicaciones todo-terreno, chapó también, ahora veremos qué tipo de aplicaciones son las que realmente le sacan partido a esta particularidad. Tengo verdadera curiosidad en averiguar como gestionan las actualizaciones de las propias aplicaciones instaladas ya en la máquina (que es de los mayores inconvenientes de las aplicaciones instaladas en local).
Aplicaciones web que acceden a recursos locales, suena cuanto menos peligroso, veremos cómo gestionan los permisos.
Me llama sobre todo la atención la posibilidad de combinar Flash y AIR, ya que se permite crear aplicaciones visualmente muy atractivas que permitan además aplicar conceptos avanzados de programación con capacidad además de interactuar contra los recursos de la máquina cliente y contra máquinas remotas.
Dejo links:
https://www.adobe.com/products/air/
Saludos.
Miguel.

Reutilización y Mantenibilidad en HTML

Nos cansamos de hablar de la mantenibilidad del código, de paquetizar, de reutilizar, de estándares de nomenclatura, de estilos definidos de programación, de separar entre el Modelo la Vista y el Controlador, de separar las aplicaciones en capas…
Pero no hay manera de que se nos meta en la cabeza que a la hora de maquetar una aplicación web tí­pica, en la que existen millones de formularios de entrada (formularios que en una aplicación de escritorio se llevan a cabo arrastrando, soltando y colocando con el ratón elementos en el formulario), se haga siguiendo también un patrón, se aplique la reutilización y se defina una estructura que esté preparada para el cambio en caso de necesitar modificar el diseño por cambios en los requerimientos.
¿Consecuencias? Cada jsp, asp, aspx, php o html son de su padre y de su madre. Algunos resuelven problemas por javascript, otros con posts, otros con request, unos maquetan con tablas, otros con capas, otros <br> y &nbsp… Otros usando class, otros con style a pelo o asignando valores a las propiedades de los controles HTML.
¿Y con el tiempo que supone hacer todo eso… por qué no somos capaces de metérnos en la cabeza de la necesidad imperiosa de definir también una forma de trabajar con HTML?
Un saludo.
Miguel.

¿Servicios Web Polimórficos? (Parte I – Intentando solucionar el problema mediante .NET Framework 2.0)

No sé si os habéis planteado alguna vez la posibilidad de aplicar el concepto de polimormisfo en un servicio web.
Es curioso pero así­ como cuando hablamos de la programación orientada objetos lo del polimorfismo está en boca de todos, cuando se habla de servicios web dicho concepto parece que se pierde y que no tenga sentido aplicarlo.
¿Se os ocurre un ejemplo de cómo sacarle utilidad? Seguro que sí­. De todas maneras, os he preparado un ejemplo de lo que serí­a uno de los usos, para que tengáis una idea de cómo serí­a la forma de un servicio web polimórfico. El ejemplo está escrito en VB.NET utilizando el framework 2.0 de .NET.
Servicio Web Polimorfico
Antes de nada (y sobre todo antes de que alguno se emocione con la idea) avanzaros que el ejemplo no es efectivo, porque con la versión 2.0 no se puede aplicar el polimorfismo en servicios web (de ahí­ el tí­tulo del post). Pero, seguro que servirá para haceros una idea de lo que se intenta transmitir en el post. Además, para poder seguir bien el ejemplo tendréis que conocer el funcionamiento de los patrones de diseño DAO y DTO (en el blog hay unos cuantos posts al respecto los cuales podéis consultar para poneros al dí­a).
En el ejemplo podréis ver que tenéis un de servicio web en el que se presentan dos capas, la de negocio (BL) y la de acceso a datos (DL).
En la capa de acceso a datos está implementada una factorí­a de DAO implementando el patrón factorí­a.
Public Class DAOFactory
    Public Shared Function GetDAO(ByVal dto As IDTO) As IDAO   
      If TypeOf (dto) Is Coche.CocheDTO Then
          Return Coche.CocheDAO.GetInstance   
      ElseIf TypeOf (dto) Is Marca.MarcaDTO Then
          Return Marca.MarcaDAO.GetInstance   
      Else
          Throw New DAONoDefinidoException   
      End If
    End Function
End Class
Veréis además que los DAO a parte de heredar de la clase BaseDAO implementan la interfaz IDAO la cual define cuáles son los métodos que debe implementar obligatoriamente cada DAO.
Public Class MarcaDAO : Inherits BaseDAO : Implements IDAO
Para finalizar, los DTO heredan todos de la clase IDTO la cual define una propiedad comíºn a todos los DTO, la propiedad Id, que define el valor que identifica a un DTO de forma íºnica. He dejado medio implementados dos DAO, CocheDAO y MarcaDAO para que se vea un poco mejor la forma de todo.
En la capa de lógica de negocio veréis que hay un íºnico servicio, llamado service.vb. En el se definen los siguientes métodos
Execute
Recibe por parámetro un IDTO y una acción posible a ejecutar. Con el IDTO recibido y utilizando la factorí­a de DAO’s genera un DAO mediante el cual lleva a cabo la acción a realizar.
Public Sub Execute(ByVal dto As IDTO, ByVal theAction As ExecuteAction)
GetUnique
A partir de una id y la factorí­a de DAO retorna un DTO.
Public Function GetUnique(ByVal dto As IDTO) As IDTO
GetMoreThanOne
A partir de un IDTO y una posible acción a ejecutar retorna una lista genérica de IDTO.
Public Function GetMoreThanOne(ByVal dto As IDTO, ByVal theAction As SelectAction) As List(Of IDTO)
Qué fantástico serí­a que funcionara esto ya que como véis desde la capa de presentación no dispondremos de un servicio web de Insert, Update, Delete y consultas restantes por cada entidad en la capa de acceso a datos, si no que tenemos un íºnico servicio, un íºnico interfaz, que luego internamente, una vez recibido el DTO correspondiente lanzará en tiempo de ejecución (mediante polimorfismo) la llamada al método de la capa de acceso a datos correspondiente. ¿Mola no? ¡Nos estarí­amos ahorrando un montón de tiempo de desarrollo y de mantenimiento!
Ahora empieza el chiste de todo esto, ya que, ¿qué ocurre cuando mediante un cliente intentamos referenciar al servicio web? Pues que no sabe qué leches es un IDTO. Esto es debido a que el WSDL que se genera automáticamente no ha definido cuáles son las clases que están en el servicio y que heredan IDTO. Esto es un problemón y es lo que tira para abajo toda esta solución. Probad a referenciar el servicio desde un cliente, añadiendo la referencia y veréis que en el parámetro IDTO lo define así­ “<idto/>” y santas pascuas, no sabe nada más.
Qué penita, esto no nos vale para nada, pero al menos ha servido para introducir el tema y plantear con los siguientes posts soluciones alternativas al mismo 🙂
Nos vemos en la siguiente parte.
Un saludo.
Miguel.

Etiquetas HTML colgroup y col

Dos etiquetas HTML que pasan bastante desapercibidas son <colgroup> y <col>.
La verdad es que es una pena porque son bastante íºtiles para trabajar con tablas.
Ilustro su uso con un ejemplo.
<table>
<colgroup span=”4″>
<col style=”width:100px”/>
<col style= “color:red”/>
<col style= “width:30px;”/>
<col style=”background-color:blue; font-weight:bold”/>
</colgroup>
<tr>
    <td>Hola</td>
    <td>qué</td>
    <td>tal</td>
    <td>estás</td>
</tr>
<tr>
    <td>Pues</td>
    <td>bastante</td>
    <td>bien</td>
    <td>sabes</td>
</tr>
</table>
Mira tíº por donde estamos definiendo las propiedades de las columnas de la tabla sin necesidad de marcarlas por cada una de sus filas.