viernes, 29 de noviembre de 2013

Instalar un lector de tarjetas inteligentes y usar el DNIe en Arch Linux

Arch Linux
Ya desde hace un tiempo los documentos nacionales de indentidad que emite la administración pública española son en el formato de tarjeta inteligente (SmartCard), conocido como DNI electrónico o DNIe. Estas tarjetas inteligentes tienen la ventaja de que incluyen un certificado digital que nos permiten identificarnos en sitios que lo soporten y realizar diversos trámites y acciones.

El DNI electrónico nos puede servir para identificarnos en varias páginas de la administración pública, en las páginas de varios bancos y realizar diferentes trámites electrónicos. El DNIe como medio de identificación en una página tiene la ventaja de que no necesitamos tener un usuario y una contraseña específica para ese sitio sino que con el DNI físico y el PIN nos será suficiente. Para identificarnos necesitamos algo que poseemos (el DNI) y algo que conocemos (PIN) con lo que las posibilidades que de alguien que quiera realizar alguna acción en nuestro nombre suplantando nuestra identidad será más complicado, la seguridad es mayor ya que no basta con conocer únicamente el usuario y clave sino que se necesita algo físico. Conseguir ambas cosas es más difícil que solo la clave. Realizar tramites administrativos de forma electrónica tiene la ventaja que no necesitamos desplazarnos hasta la correspondiente ventanilla para realizar el trámite. Algunos bancos que permiten identificarnos con el DNIe son el Santander, BBK, el infame Bankia  y posiblemente muchos otros, también podemos consultar los puntos que poseemos en el carnét de conducir, seguro que hay muchas más cosas útiles en las que podemos dar uso al DNIe.

En esta entrada voy a explicar como instalar el DNI electrónico en Linux más concrétamente en Arch Linux. La primera cosas que necesitaremos será disponer de un lector de tarjetas inteligentes como el siguiente que yo adquirí por unos 12€:

Después en Arch Linux deberemos instalar los siguientes paquetes:

opensc-dnie (AUR) y ccid nos darán el soporte para acceder al DNIe, pcsc-tools nos proporcionará una herramienta (pcsc_scan) con la que podremos comprobar si el lector funciona correctamente y detecta la tarjeta o DNI. Una vez instalados los programas debemos modificar el archivo de configuración «/etc/opensc.conf» aplicando los siguientes cambios y valores en cada apartado y propiedad:

Después debemos iniciar el servicio de opensc, podemos hacer que se inicie con el sistema (enable) o cuando deseemos de forma manual (start):

Una vez hecho todo esto podemos comprobar el funcionamiento de nuestro lector con el DNIe, para ello utilizamos pcsc_scan que nos indicará si ha detectado un lector de tarjetas y si este tiene o no una tarjeta introducida:

Con el siguiente comando podemos ver los certificados del DNIe:



Y con el siguiente comando podemos exportar el certificado del DNI, se nos solicitará el PIN del DNI:

Si examinamos el certificado podemos darnos cuenta de una cosa curiosa y es que aunque el DNI físico se emite con una validez de 10 años el certificado incluido en él solo tiene una validez de 2 años y medio, con lo que pasado este tiempo deberemos acudir a la oficina de expedición para ampliar el periódo límite de uso.

Y esto debería ser parecido para otras distribuciones como Ubuntu, Debian, Mint, openSUSE, Fedora. Los paquetes pueden ser diferentes pero el proceso de instalación será similar a este

Cone esta entrada de momento solo hemos instalado el lector de tarjetas inteligentes en posteriores entradas explicaré como usar el DNIe para autenticarnos en una página usando Firefox, firmar documentos PDF con Sinadura o enviar correos electrónicos firmados digitalmente usando el cliente de correo Evolution. También puedes consultar como crear un parde claves GPG y usarlas para enviar correos firmados digitalmente.

Referencia:
Usar el DNI electrónico con Firefox en Linux
https://wiki.archlinux.org/index.php/Common_Access_Card
http://www.banot.net/?q=node/15

viernes, 22 de noviembre de 2013

Como usar GPG con Evolution

GnuPG
Evolution
Después de la introducción a la criptografía y crear una clave GPG ya sea a través de la linea de comandos en la terminal o con la herramienta Contraseñas y claves de GNOME además de usarla para cifrar y firmar documentos desde la terminal podemos usarla para firmar y cifrar los correos electrónicos que enviemos usando nuestro cliente de correo. La firma de los correos electrónicos permitirá conocer al receptor si el correo ha sido modificado por una tercera parte, comprobar la autenticidad del mensaje y si tenemos la clave pública del destinatario podremos enviarle el correo cifrado evitando que pueda ser leído salvo por el destinatario.

En esta entrada explicaré como firmar y cifrar el correo electrónico que enviemos usando nuestra clave GPG y el cliente de correo por defecto de GNOME, Evolution. Para firmar los correos electrónicos que enviemos deberemos conocer previamente el id de nuestra clave GPG, podemos averiguarlo con el comando:



Este comando nos mostrará todas las claves GPG que tenemos en nuestro sistema, buscaremos la nuestra y nos fijaremos en la segunda columna de la linea que empieza por pub. En mi caso el id de mi clave es E012C989 como puede verse en la captura de pantalla (en la segunda clave).

Una vez que conocemos del id de nuestra clave, vamos a las propiedades de la cuenta de correo de Evolution y lo introducimos en el campo preparado para ello del apartado Seguridad (Propiedades de la cuenta > Seguridad). Y esto será suficiente para que a partir de ahora los correos que enviemos con nuestra cuenta de correo vayan firmados si marcamos la opción «Firmar siempre los mensajes salientes cuando se use esta cuenta» o marcando la opción «Firmar on GPG» en el menu Opciones en la redacción de un mensaje.


La firma digital será añadida como un documento adjunto de nombre «signature.asc» que empezará con el contenido «-----BEGIN PGP SIGNATURE-----». Si evolution nos indica que la firma es válida pero que el remitente no puede ser validado nos falta confiar en la clave.


Con Seahorse accedemos a las propiedades de la clave y en la pestaña «Detalles» modificamos el nivel de confianza de «Predominar confianza del propietario», si confiamos en la clave podemos indicar el valor «Absoluta». Los diferentes mensajes que nos puede indicar Evolution dependiendo de si poseemos la clave pública del remitente, poseemos la clave pero aún no hemos confiado en ella y si tenemos confianza absoluta en la clave son:

Para enviar correos cifrados deberemos solicitar a cada destinatario su clave GPG o PGP pública e importarla en nuestro anillo de claves. También si queremos que nos envíen el correo cifrado deberemos distribuir entre nuestros remitentes nuestra clave pública. Para importar una clave pública de un contacto podemos hacerlo con el siguiente comando desde la terminal:

O también con la aplicación de GNOME Contraseñas y claves con la opción «Archivo > Importar...»

Con otros clientes de correo electrónico la forma de usar GPG varía, en esta entrada he explicado la combinación de GPG/Evolution. Con Thunderbird debemos usar la extensión Enigmail, para Outlook parece que la mejor opción es Gpg4win.

En siguientes entradas de esta serie sobre seguridad explicaré como crear certificados, SSL, servidores, firma digital con Sinadurasmart cards en linux y DNIe, ... y quizá alguna cosa más.


Referencia:
GnuPG
https://addons.mozilla.org/es/thunderbird/addon/enigmail/
http://www.gpg4win.org/

viernes, 15 de noviembre de 2013

Introducción a la criptografía e inicio con GPG

GnuPG
Internet está formado por una red de máquinas interconectadas que en conjunto permiten que un par de máquinas de esa red puedan comunicarse entre si aunque no estén directamente conectadas, el protocolo TCP/IP es el que posibilita esa comunicación. En la comunicación entre las máquinas que no están directamente conectadas la información de la máquina origen ha de ser transportada por un camino de varias máquinas hasta llegar a a la máquina destino y posteriormente de vuelta por el mismo camino u otro. En muchos casos la información que viaja a lo largo de ese camino de terceras máquinas no es relevante ni sensible pero en otros casos podemos necesitar o queremos evitar que esas terceras máquinas puedan acceder a la información que se está transmitiendo. En este último caso es donde entra en acción la criptografía.

Diagrama de enrutadores en internet, cada elipse (roja) es un enrutador por el que pasa la información transmitida entre el cliente (verde) y el servidor (azul)

La criptografía nos permite que el contenido de un mensaje solo sea legible para el emisor y receptor, aunque los datos sean transportados por terceras máquinas solo verán datos ofuscados (o cifrados) a cuyo contenido no se les podrá dar ningún sentido ni interpretación. La criptografía proporciona las siguientes propiedades:
  • Confidencialidad: garantiza que el mensaje solo pueda ser leído por su destinatario.
  • Integridad: garantiza que el mensaje no ha sido modificado por un tercero.
  • Vinculación: trata de asociar el emisor con una clave.
  • Autenticación: consiste en garantizar que el mensaje ha sido emitido por un determinado agente.
Para conseguir estas propiedades la criptografía usa diversos elementos como algoritmos de cifrado simétricos, asimétricos o híbridos, claves privadas o claves públicas y privadas, certificados digitales, huellas y firmas digitales. Los algoritmos de cifrado son los que garantizan la propiedad de confidencialidad, tienen la propiedad de que una vez cifrado los datos es muy difícil o se necesita una cantidad de cómputo y tiempo muy elevada para descifrar el mensaje. Hay varios tipos.

Los algoritmos simétricos

Estos algoritmos utilizan la misma clave tanto para cifrar la información como para descifrarla. Son rápidos y a misma longitud de claves más seguros que los de clave asimétrica pero plantea el problema de como intercambiar la clave privada de forma segura a través de la red, para ello se usan los algoritmos asimétricos.



Los algoritmos asimétricos o de clave pública y privada

Este tipo de algoritmos usan dos claves para realizar el proceso de cifrado. Cada usuario posee dos claves, una pública y otra privada. La clave pública de cada par de claves se puede compartir a cualquier otra persona, el que quiera enviarle un mensaje cifrado al propietario de esa clave pública lo cifrará con la clave pública, el mensaje solo puede ser descifrado con su clave privada asociada que solo conoce su propietario. De esta manera los algoritmos asimétricos evitan el problema de como compartir la clave de los algoritmos simétricos ya que en este par de claves hay una pública que puede ser compartida.



Sin embargo, los algoritmos de clave pública y privada no solucionan todos los problemas de seguridad por si solos, está el problema de confianza en la clave pública, es decir, estar seguros de que la clave pública es realmente del destinatario al que pretendemos enviar un mensaje y no la de alguien que se ha colacado en medio del emisor y receptor con la intención de realizar un ataque «man-in-the-middle». Para ello podemos confiar en una tercera parte en la que confiamos, si nosotros confiamos en esa autoridad y esa autoridad certifica que la clave pública es de quien dice ser podemos confiar en que el mensaje será solo legible por destinatario y propietario de esa clave pública, aquí es donde entran las autoridades de certificados. Para certificar las claves públicas se emplean certificados y firmas digitales.

Los algorítmos híbridos

Este tipo de algoritmos aprovechan y combinan lo mejor de los algoritmos simétricos y asimétricos. Para cifrar un mensaje se genera una clave simétrica, se usa un algoritmo simétrico para cifrar el mensaje con la clave generada y la clave usada para cifrar el mensaje se cifra a su vez con la clave pública (algoritmo asimétrico) del destinatario. Posteriormente cuando el destinatario recibe el mensaje descifra con su clave privada la clave con la que fue cifrada el mensaje y con la clave descifrada usando el algorítmo simétrico se descifra el mensaje. En el siguiente esquema se puede apreciar el proceso:

GPG (Gnu Privacy Guard)

Esa es la teoría básica, ahora veamos como utilizar GnuPG que es una implementación libre de PGP (Pretty Good Privacy) y sacar provecho de esta entrada y la criptografía. Crearemos una clave pública y privada, cifraremos y descifraremos un archivo y verificaremos su integridad. A continuación los comandos en orden para generar el par de claves (se nos guiará en el proceso), ver su huella digital, exportar la clave pública y exportar la clave privada para conservarla en un archivo.

El parámetro --armor sirve para codificar la salida en formato texto, con cualquier editor de texto podremos ver su contenido (aunque lo que veamos sea una sopa de letras). Este comando es combinable con otros con similar resultado. Entre usar o no usar armor depende de nuestras necesidades, sin --armor el resultado ocupa menos pero es dificilmente legible por un editor de texto y con --armor el resultado ocupa más pero es legible por un editor de texto.


Si enviamos la clave pública a un servidor de claves para que otros usuarios puedan descargarse nuestra clave y verificar los mensajes que enviamos es aconsejable generar un certificado de revocación para poder revocar la validez de la clave en caso de que su seguridad haya sido comprometida.

Como cifrar un archivo con GPG
Esto generará un archivo del mismo nombre que el que firmamos pero con las extensión .gpg añadida al final, en este caso se generaría un archivo de firma secret.zip.gpg (podemos usar el parámetro --armor y se creará el archivo con extensión .asc). Con -r indicamos el destinatario del mensaje, necesitaremos su clave pública para cifrar el archivo y que solo el destinatario pueda descrifrarlo con su clave privada.

Como firmar un archivo con GPG
Con -u indicamos la clave que realizará la firma. Si no necesitamos cifrar el archivo para garantizar su confidencialidad pero queremos garantizar que no es modificado hasta llegar al receptor y su origen, es decir queremos garantizar su integridad y autenticidad, podemos firmarlo digitalmente.

Como descifrar y verificar un archivo con GPG
Para descrifrar un archivo:

Si hacemos alguna modificación al archivo e intentamos descifrarlo veremos que el programa nos alerta de que el archivo ha sido modificado, tal como podría ocurrir si en la transmisión del mensaje hubiese sido interceptado y modificado. Para verificar la intergridad de un archivo hacemos:



Para crear la clave también podemos emplear la aplicación Seahorse o Contraseñas y claves de GNOME. O si la hemos creado mediante comandos con GnuPG importarla en esta aplicación además de almacenarlas en un depósito seguro de claves. Usando Seahorse para generar una par de claves GnuPG no necesitamos usar la terminal y los comandos anteriores pero el proceso nos pide los mismos datos.



Sehaorse también tiene opciones para importar y exportar las claves GnuPGP a y del anillo de claves.

Aunque enviemos los datos cifrados y hagamos inaccesible el contenido no es sinónimo de privacidad, a veces saber simplemente que un mensaje se envío, a que hora, de que longitud, duración, tamaño, desde donde, a donde y a quien puede ser información suficiente para extraer conclusiones, patrones o sobre que trataba la información entre otras cosas, sino preguntarle a la NSA/CSS que de esto saben bastante por las recientes informaciones de espionaje realizadas impunemente y en secreto por el gobierno de los EEUU, esa recolección ingente de datos son una muestra de ello.

En siguientes entradas de esta serie sobre seguridad explicaré como configurar un gestor de correo electrónico (evolution) para enviar mensajes de correo electrónico firmados o cifrados con las claves GPG creadas con los comandos de esta entrada, certificados, SSL, servidores, firma digital con Sinadurasmart cards en linux y DNIe, ... y quizá alguna cosa más.

Referencia:
PGP Web of Trust: Core Concepts Behind Trusted Communication
Criptografía
Manual de GPG: cifra, firma y envía datos de forma segura
Getting Started with GNU Privacy Guard
http://www.gnupg.org/gph/es/manual.html
https://wiki.archlinux.org/index.php/GnuPG

viernes, 8 de noviembre de 2013

Integración y transacciones con Spring en Apache Tapestry

Apache Tapestry
Spring
En otra entrada comentaba como hacer transacciones en una base de datos relacional con Apache Tapestry y como mejorar el soporte que ofrece de por si con la anotación CommitAfter mediante con una solución propia que proporciona la anotación Transactional. La solución propia mejora la anotación CommitAfter y es usable en más casos como cuando dos servicios distintos necesitan colaborar en una transaccion y compartirla. Sin embargo, si el correcto funcionamiento de las transacciones es una parte importante de la aplicación (y en una aplicación grande lo será) podemos evaluar si optar por Spring o los EJB en vez de la solución propia o la anotación CommitAfter.

Unos buenos motivos para optar tanto por Spring como por los EJB es que son soluciones ya desarrolladas con lo que solo tendremos que integrarlo en nuestros proyectos y no tendremos que preocuparnos de mantener nuestra solución en caso de que tenga errores, además ambas son ampliamente usadas incluso en proyectos grandes y complejos y están ya probadas lo que es una garantía. Entre optar por Spring o los EJB depende de varios factores como puede ser si la aplicación va ha ser desplegada en un servidor de aplicaciones con soporte para EJB (como JBoss/Wildfly, Geronimo, ...) o no (Tomcat, Jetty) o de nuestras preferencias entre ambas opciones. En esta entrada explicaré como integrar Spring con el framework Apache Tapestry y como hacer uso de las transacciones de Spring en los servicios que contienen la lógica de la aplicación.

Primeramente, decir que en cierta medida la funcionalidad proporcionada por el contenedor de dependencias de Tapestry y el contenedor de dependencias de Spring se solapan, ambos proporcionan Inversion of Control (IoC). Pero el contenedor de dependencias de Tapestry tiene algunas ventajas como permitir configuración distribuida, esto hace referencia a que cada librería jar puede contribuir con su configuración al contenedor de dependencias y que la configuración se hace mediante código Java en vez de xml como en Spring con la ventaja de que es más rápido, tenemos la ayuda del compilador para detectar errores y el lenguaje Java es más adecuado para expresar la construcción de objetos. De modo que si podemos es mejor usar el contenedor de Tapestry que el de Spring, sin embargo, Spring ofrece un montón de funcionalidades muy útiles y esto nos puede obligar a usar el contenedor de Spring para ciertos objetos. Una de ellas son las transacciones para cumplir con las reglas ACID de las bases de datos relacionales, para ello deberemos definir en el contenedor de Spring (y no en el de Tapestry) los servicios con la lógica de negocio con necesidades transaccionales y las dependencias referidas por esos servicios en la configuración del contexto de Spring. A pesar de todo en los demás casos podemos optar por la opción que prefiramos ya que tanto a los servicios de Spring se les pueden inyectar dependencias del contenedor de Tapestry y, el caso contrario, a los servicios de Tapestry se les pueden inyectar servicios de Spring.

Veamos en código un ejemplo de como conseguir integración entre Tapestry y Spring. La primera cosa que cambia es que hay que usar un filtro de Tapestry especial para integrarse con Spring con lo que deberemos modificarlo en el archivo web.xml. Si normalmente usamos el filtro org.apache.tapestry5.TapestryFilter para que Tapestry procese las peticiones que llegan a la aplicación, integrándonos con Spring usaremos un filtro especial, org.apache.tapestry5.spring.TapestrySpringFilter. También mediante una propiedad de contexto indicaremos el (o los) xml con la definición de los beans de Spring.

En el xml del contexto para Spring definimos la configuración para que Hibernate se conecte a la base de datos, definimos el SesionFactory que creará la sesiones de Hibernate, el gestor de transacciones y los servicios con la lógica de negocio. En este ejemplo he optado por definir las transacciones mediante anotaciones en los servicios con la lógica de negocio. Spring también permite definir la transaccionalidad de forma declarativa en este xml.

Como Spring se encargará de la configuración de Hibernate si incluimos la dependencia tapestry-hibernate tendremos un problema ya que este módulo de Tapestry también intenta inicializar Hibernate. Para evitarlo y disponer de toda la funcionalidad que ofrece este módulo como encoders para las entidades de dominio, la página de estadísticas de Hibernate o el objeto Session como un servicio inyectable en páginas o componentes hay que redefinir el servicio HibernateSessionSource. El nuevo servicio es muy sencillo, básicamente obtiene el la configuración de Hibernate mediante el bean SessionFactory definido en Spring y además mediante el mismo bean se crea el objeto Session que podrá inyectarse en los componentes y páginas de Tapestry en los que lo necesitemos. También deberemos añadir un poco de configuración en el módulo de la aplicación para redefinir este servicio.

Para definir la transaccionalidad de una operación debemos usar la anotación Transactional usando los valores por defecto o indicando la propagación, el aislamiento, si es de solo lecura, timeout, etc, ... según consideremos. Debido a lo simple de la lógica de negocio de la aplicación de este ejemplo la anotación se aplica al DAO, sin embargo, en una aplicación más compleja y con mas clases sería mejor definirlo a nivel de servicio de lógica de negocio o punto de entrada a la lógica de negocio y no al nivel de los DAO que están en una capa de la aplicación más baja.

Finalmente, debemos añadir o modificar las dependencias de nuestra aplicación. La dependencia tapestry-spring usa por defecto la versión 3.1.0 de Spring, en el ejemplo la sustituyo por la versión 3.2.4 más reciente. A continuación incluyo la parte relevante.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.

Referencia:
Transacciones en Apache Tapestry
Persistencia con JPA y Apache Tapestry
Acceso a base de datos con Hibernate y JPA
Transaction Management (Spring)

viernes, 1 de noviembre de 2013

Transacciones en Apache Tapestry

Apache Tapestry
Tapestry no proporciona de por sí un soporte completo a las aplicaciones que necesitan realizar operaciones en una base de datos relacional de forma transaccional. La dependencia tapestry-hibernate provee la anotación @CommitAfter para Hibernate y la dependencia tapestry-jpa otra del mismo nombre para JPA pero esta anotación en ambos casos proporciona una funcionalidad muy básica y probablemente no no sirva en casos de uso complejos. Esto ha sido objeto de discusión varias veces en la lista de distribución de los usuarios [1] [2] y el JIRA de Tapestry [3].

Con la anotación CommitAfter si se produce una excepción no controlada («unchecked») se hará un rollback de la transacción y, esto es importante, aún produciendose una excepción controlada («checked») se hará el commit de la transacción y es responsabilidad del programador tratar la excepción adecuadamente. Se puede usar en los métodos de los servicios y en los métodos manejadores de eventos de los componentes.

Sabiendo como funciona la anotación se nos plantean preguntas:
  1. ¿Cuál es el comportamiento cuando un método del servicio anotado llame a otro también anotado del mismo servicio?
  2. ¿Que pasa si cada método está en un servicio diferente?
Para el primer caso (métodos del mismo servicio) se hará una sola transacción ya que las anotaciones y los advices se aplican en el proxy del servicio no en la implementación. En el segundo caso (métodos en diferentes servicios) se iniciará una transacción pero haciendo un commit en la salida de cada método.

Si tenemos una aplicación compleja probablemente se nos planteará el caso de tener varios servicios que se llaman entre si y que ambos necesiten compartir la transacción, en esta situación la anotación CommitAfter probablemente no nos sirva por hacer un commit en la salida de cada método.

Tapestry no pretende proporcionar una solución propia que cubra todas las necesidades transaccionales que puedan tener todas las aplicaciones sino que con la anotación CommitAfter pretende soportar los casos simples, para casos más complejos ya existen otras opciones que están ampliamente probadas. Si necesitamos un mejor soporte para las transacciones que el que ofrece Tapestry debemos optar por Spring o por los EJB. Sin embargo, la solución de Spring nos obliga a definir los servicios transaccionales como servicios de Spring y los EJBs nos obligan a desplegar la aplicación en un servidor de aplicaciones que soporte un contenedor de EJB como JBoss/Wildfy, Gernimo, TomEE, ... Si nuestro caso no es tan complejo como para necesitar mucho de lo que ofrece Spring o no queremos o podemos usar un servidor que soporte EJB podemos aplicar el ejemplo ya comentado en Tapestry Magic #5: Advising Services.

En esta entrada pondré un ejemplo completo usando la solución de Tapestry Magic #5 pero con la adición de una anotación que permite definir más propiedades de las transacciones y la diferencia respecto a la anotación CommitAfter de que independientemente de si se produce una excepción checked o unchecked se hace un rollback de la transacción. La anotación Transactional permite definir si la transacción es de solo lectura, definir un timeout para completar la transacción o el nivel de aislamiento de la transacción además de la estrategia de propagación. Aunque no sea una solución tan buena como la de usar Spring o EJBs, puede ser suficiente para muchos más casos que la anotación CommitAfter.

La solución consiste en implementar una nueva anotación para los métodos transaccionales que he llamado Transactional, unos advices con las diferentes estrategias de transaccionalidad (REQUIRED, SUPPORTS, NEVER, NESTED, MANDATORY), un advisor que aplicará una estrategia transaccional en función de la anotación Transactional de los métodos y un poco de configuración para el contenedor IoC que define los servicios y aplica la decoración a los métodos anotados.

Hay que tener en cuenta que esta solución es una prueba de concepto que he probado en este ejemplo y puede presentar problemas que aún desconozco en una aplicación real. Una vez dicho esto veámos el código.

Primero la anotación, el enumerado de las estrategias de propagación de transacciones, el DTO (Data Transfer Object) con las propiedades de la anotación y la interfaz del servicio transaccional.

Ahora el advisor que usará el servicio transaccional y en función de la estrategia de propagación aplicará el advice adecuado.

El funcionamiento de las estrategias transaccionales son:
  • REQUIRED: si no hay una transaccion activa inicia una y hace el commit al finalizar. Si existe una al entrar en el método simplemente ejecuta la lógica usando la transacción actual
  • MANDATORY: requiere que haya una transacción iniciada, en caso contrario produce una excepción.
  • NESTED: inicia una nueva transacción siempre aún existiendo ya una, con lo que puede haber varias transacciones a la vez de forma anidada.
  • NEVER: es el caso contrario de MANDATORY, si existe una transacción produce una excepción.
  • SUPPORTS: puede ejecutarse tanto dentro como fuera de una transacción.
Probablemente con la anotación REQUIRED tengamos suficiente para la mayoría de los casos, para la estrategia NESTED necesitaremos soporte del motor de la base de datos que no todos tienen, el resto son otras posibilidades comunes en el ámbito de las transacciones: MANDATORY, NEVER, SUPPORTS.

Y ahora las implementaciones de las estrategias de propagación que iniciarán, harán el rollbak y commit de forma adecuada a la estrategia usando el servicio transaccional.

A continuación la implementación del servicio transaccional para el caso de Hibernate.

Finalmente el gestor de sesiones de Hibernate y la configuración necesaria en el módulo de la aplicación.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.

Referencia:
Integración y transacciones con Spring en Apache Tapestry