Como cambiar el puerto default en que se ejecuta una aplicacion de grails.

Simple… estoy desarrollando dos aplicaciones en grails que necesito ejecutar simultáneamente.

Por default, grails utiliza el puerto 8080 para todas las aplicaciones, entonces no se pueden tener dos aplicaciones a la vez si no se le cambia el puerto a una de ellas.

Hasta hoy, utilizaba un comando al estilo grails -Dserver.port=8081 run-app pero siempre me olvidaba de agregar esos parámetros… en fin quería buscar una solución más práctica.

Aunque no lo encontré por ningún lado en la documentación de grails, gracias a google encontré que desde alguna versión bastante vieja, no se cual, también se pueden agregar al BuildConfig.groovy la siguiente linea:

grails.server.port.http = 8081

Funciona a la perfección en grails 2.0.1 (y al menos a partir de grails 1.3.0 debería funcionar)

Google como calendario por defecto usando gnome-shell

Lo que quiero es que los eventos creados en google calendar, aparezcan en el calendario de gnome-shell sin utilizar thunderbird o evolution.

Encontré un pequeño script de python que hace justo lo que deseo: https://github.com/vintitres/gnome-shell-google-calendar

Primero hay que bajarlo y descompactarlo, (o clonarlo si se sabe que significa)
Luego para ejecutarlo hay que tener algunas dependencias de python instaladas. En mi instalación solo debí ejecutar

sudo apt-get install python-gdata python-iso8601

En la página del script figuran otras dependencias pero yo ya las tenía instaladas…. a saber python-gtk, python-dbug y python-gnomekeyring

Luego se ejecuta el script con ./gnome-shell-google-calendar y listo. Luego de un rato si se accede al calendario se verán los eventos definidos en google calendar.

Lamentablemente si cerramos la ventana o reiniciamos el computador, esto se pierde y hay que volver a ejecutar la aplicación. Por esto la agregué a la lista de aplicaciones a ejecutar al iniciar.

Luego de tener esto, lo único que falta arreglar es el botón de abrir calendario que sin importar como configurase las aplicaciones, siempre intentaba abrir evolution el cual ni siquiera esta instalado.

También googleando encontré la solución más simple: http://askubuntu.com/questions/69349/how-to-change-gnome-shell-calendar-default-application

La unica diferencia, es que yo use firefox para abrir el calendario. Entonces el comando que debí ejecutar es:

gsettings set org.gnome.desktop.default-applications.office.calendar exec "firefox 'https://www.google.com/calendar'"

supongo que si se quiere usar el explorador por default se puede usar el comando:

gsettings set org.gnome.desktop.default-applications.office.calendar exec "/usr/bin/x-www-browser 'https://www.google.com/calendar'"

Efectos de la manipulación de metaClass en Groovy / Grails

Groovy Logo

Haciendo unas pruebas unitarias en grails me encontré con un comportamiento de Groovy que desconocía.

Desde la versión de Groovy 1.6 se puede manipular el metaclass de una instancia (al menos fácilmente) además de hacerlo para toda la clase como es costumbre.

Para realizar un test, debía agregar por metaClass dos métodos, uno sobre la clase y otro sobre una instancia particular de dicha clase.

Misteriosamente para mi, al ejecutar el test, me decía que el método que agregaba a la clase no existía. Entonces escribí el siguiente caso de prueba para entender que era lo que estaba pasando

class MyTestClass {
}

def myTestInstance = new MyTestClass()

myTestInstance.metaClass.testInstanceMethod = { true }
MyTestClass.metaClass.testClassMethod = { true }

assert myTestInstance.testInstanceMethod() == true, "La instancia tiene el método declarado en el metaClass de la instancia"
assert myTestInstance.testClassMethod() == true, "La instancia tiene el método declarado en el metaClass de la clase"

A simple vista este test pareciera funcionar. Agrego a la instancia un método, luego le agrego a la clase otro método y luego testeo que esos métodos existan y que retornen true.

Para mi sorpresa, al ejecutar este script, el resultado fue

groovy.lang.MissingMethodException: No signature of method: MyTestClass.testClassMethod() is applicable for argument types: () values: []
Possible solutions: testClassMethod(), testClassMethod(java.lang.Object)

Investigando encontré que si invertía el orden de las líneas 06 y 07, que se encuentran resaltadas en el script anterior, se solucionaban todos los problemas y funcionaba como se esperaba el test.

¿Qué supongo que está sucediendo?

Cuando se modifica el metaclass de una instancia, se copia el estado actual del metaclass de la clase a la que dicha instancia pertenece y se modifica esta copia que queda como una copia privada de la instancia y sin relación con la metaclass de la partió.

Por lo tanto, luego, cuando se modifica el metaclass de la clase, agregándole un nuevo método, este cambio no se ve reflejado en las instancias que previamente fueron modificadas.

Moraleja: siempre modificar el metaclass de las clases primero y luego, cuando ya no quedan modificaciones a nivel clase, se pueden hacer las modificaciones a nivel instancia.

Seguridad en sitios web… o como Oracle apesta

Bueno, antes que nada aviso que estoy muy enojado, asi que no esperen un post educativo o tranquilo.

Aviso también que no hablaré sobre bases de datos Oracle (que también apestan por motivos diferentes según mi criterio) sino sobre las contraseñas que nos obligan a poner en páginas webs.

Continuamente en diarios, televisión, comentarios de amigos, spam de antivirus, emails, radio, conocimiento popular, me dijo un amigo de un amigo de un primo, etc que con solo conectarte a internet podes desde contagiarte hepatitis a, hasta que te roben la tarjeta de crédito, te hipotequen la casa y quedes en la ruina…. sin haber presionado si quiera una tecla.

Es verdad, estoy exagerando un poco, pero muchísimas personas tienen paranoia con la seguridad. Si tan solo se supiera que con un poco de conocimiento y buenas prácticas se les acabaría el negocio a tanta basura pseudo llamada antivirus que esta dando vueltas por ahí..

Pero lo que me molesta en este momento es que me obliguen a tener cuidado con la seguridad en sitios que no lo merecen!

Por ejemplo, que en el banco me obliguen a poner una clave alfanumérica de al menos 8 dígitos, que tenga que cambiarla cada 3 meses y en cada operación deba además escribir un código que saco por una tarjeta de coordenadas… bueno… podría decirse que es un banco, debe tener la mayor seguridad del mundo.

En mi opinión NO ! Es uno el que debe darle el valor de seguridad a cada sitio en particular sin que el sitio te lo tenga que venir a imponer tan alegremente hasta el punto de ser inutilizable. Por ejemplo, sin ir mas lejos, a mi me parece más importante tener asegurada la contraseña de mi correo electrónico que la del homebanking… si total necesito una tarjeta de coordenadas que es un medio físico para hacer cualquier operación que involucre dinero.

Pero esa es mi opinión. Incluso no es lo que me molesta, lo que en verdad me enerva es que sitios totalmente inconsecuentes tengan esa misma política.

Hoy necesitaba bajar el Oracle Java Development Kit 6, y para bajarlo era obligatorio registrarme en la pagina web de Oracle! ya vamos mal… para que quiero registrarme en ese sitio? para que me llenen aún más de spam?

Pero no termina ahí. Ya estaba registrado (no es la primera vez que necesito descargar un jdk) pero no recordaba la clave… probé todas las claves habituales.. y nada.. así que debí seguir el procedimiento de recuperación de contraseña.

Lo bueno es que esto fue rápido… pero cuando quería cambiar la que me habían asignado totalmente in-memorizable por la que yo tenía ganas… que sorpresa la mía que me obligaran a poner una clave que contenga letras y números y además al menos una letra mayúscula y una minúscula. Menos mal que no obligaron a poner caracteres no alfanuméricos ! Creo que eso se les pasó, no me extrañaría que pronto deba hacerlo.

Y todo esto para que.. para descargar una aplicación que antes de que Oracle comprara la empresa por unos servidores, se la podía descargar gratuitamente y sin registración !

Oracle no es la única que tiene esta política totalmente estúpida con respecto a la complejidad de contraseñas. Esta plagado de sitios así… Todo bien con que avisen que la contraseña que estoy ingresando no es segura, pero no me obligues a poner una contraseña que SEGURO me voy a olvidar.

Nunca faltará el que diga que si me olvido la contraseña puedo solicitar su reseteo como hice anteriormente, ¿pero entonces para que corno me dan una contraseña? No tiene sentido tener que elegir una contraseña para que siempre tenga que resetearla.

Ahora bien.. si yo fuera no se.. partner de Oracle y puediera con esa contraseña gestionar pagos, cuentas corrientes, o descargar aplicaciones no gratuitas al menos, esta bien que use una contraseña más segura. Pero sería yo el que elegiría una contraseña de mayor complejidad evaluando que tan critica considero la información que ahi guardo en cada caso en particular.

Para mi es más confidencial y peligrosa la información que tengo en mi cuenta de Facebook que la que tengo en Oracle. Por Dios…facebook sabe hasta con que personas, en que lugares y que comí durante mis últimas vacaciones, donde vivo, donde estudio, donde trabajo, con la información que tienen pueden inferir hasta mi sueldo y grupo sanguíneo y no tiene semejante política de contraseñas !

En fin, estoy muy muy enojado con una estupidez como esta. (obviamente estoy de mal humor por otros motivos, y pobre Oracle fue la gota que rebasó el vaso)

N2CMS, NHibernate (o Hibernate), Oracle y ORA-01461 (LONG y NCLOB)

En esta entrega voy a compartir algunos problemas que tuvimos con la bendita conexión a Oracle.

Uno de ellos, fue la existencia de un Rack de servidores en el cliente, es decir, más de un servidor funcionando en paralelo. Además, tenían dos versiones del cliente de Oracle conviviendo en el servidor (cosa que no habían indicado cuando nos dieron las especificaciones técnicas del servidor y que aparecieron “oh caramba!”, cuando se hizo el primer despliegue). Uno era Oracle8i, otro Oracle10g. Nuestra aplicación “misteriosamente” se conectaba a veces si, otras veces no… Como N2CMS (en realidad Hibernate) no soporta el conector 8i, obviamente, esto ocasionaba errores, cuelgues y cosas muy muy raras :)

Bueno… no tanto, pero explotaba :)

En fin, el problema fue el siguiente: cuando en el web.config seleccionamos la conexión, elegimos “Oracle10g”, el cual, en el código fuente del N2 usaba el driver “default” de Microsoft para conectarse, y este driver, funciona mal. De hecho, el mismo Visual Studio te recomienda no usarlo :S. Conclusión, le modificamos el siguiente código:

ConfigurationBuilder.cs

case DatabaseFlavour.Oracle:
case DatabaseFlavour.Oracle10g:

Properties[NHibernate.Cfg.Environment.ConnectionDriver] = typeof(NHibernate.Driver.OracleDataClientDriver).AssemblyQualifiedName;
Properties[NHibernate.Cfg.Environment.Dialect] = typeof(NHibernate.Dialect.Oracle10gDialect).AssemblyQualifiedName;
break;

Usando OracleDataClientDriver toma el driver proporcionado por el cliente y no el default de Microsoft. Y con eso, se solucionó ese problemita.

mision cumplida

Otro problema que tuvimos fue el largo de los textos. Por algún motivo, el mapeo de los strings no estaba funcionando correctamente y los valores se convertían a un tipo de dato inválido. El error que teníamos era

ORA-01461: can bind a LONG value only for insert into a LONG column

Eso lo solucionamos modificando la siguiente linea en el código:

ConfigurationBuilder.cs

ca.Property(x => x.StringValue, cm => { cm.Type(NHibernateUtil.AnsiString); cm.Length(stringLength); });

flawless victory

Espero que les sirva, al menos para que no padezcan los mismos sobresaltos que nosotros si tienen los mismos errores.

¡Hasta la próxima!

Redirigir un puerto en Linux utilizando IPTables

Para los entendidos, esto se llama Port Forwarding y se lo utiliza, cuando tenemos una sola computadora conectada a internet y una o más computadoras conectadas en una red interna, a la primera.

Si alguna de las computadora de la red, quiere ser accedida desde internet, no se puede porque la conexión directa a internet solo la tiene la primera computadora. Entonces esta debe configurarse para redirigir (forwardear) el trafico correcto a la computadora correcta.

Los routers traen una opción para hacer esto fácilmente, y es mi consejo que si pueden comprar un router para conectarse a internet, y este estar conectado a varias computadoras, es lo más fácil que podrían hacer. Pero a veces esto no es posible y no nos queda otra que configurar una pc.

Sin explayarme mucho, los comandos necesarios para hacer esto fueron:

sudo sysctl net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -p tcp --dport <puerto_origen> -j DNAT --to-destination <ip_destino>:<puerto_destino>
sudo iptables -t nat -A POSTROUTING -j MASQUERADE

Donde hay que reemplazar con un puerto que será al que nos conectaremos desde internet e y con la ip y el puerto de la pc a la que queremos conectarnos realmente.

Esto es muy simple y fácil, pero siempre me lo olvido, por eso es que lo dejo aqui para futura referencia.

Mi experiencia con n2cms, Episodio II (Instalación N2CMS y Oracle 10g)

En esta oportunidad me voy a dedicar a contarles sobre la instalación del Framework y los problemas que tuvimos a la hora de ejecutarlo en el cliente.

Chef

“Comencemos con la preparación de los ingredientes…”

Como había adelantado en el post anterior, el archivo web.config es de vital importancia a la hora de instalar correctamente el sitio. Para poder realizar la instalación se debe setear la propiedad allowInstallation en true:

<installer checkInstallationStatus="true" allowInstallation="true" />

Si la aplicación está desarrollada en la versión 4 del Framework de .NET, se debe agregar la siguiente línea:

<httpRuntime requestValidationMode="2.0" />

(No escribirla si la aplicación es 3.5, para más info ->http://www.asp.net/whitepapers/aspnet4/breaking-changes )

Ahora que tenemos todos los ingredientes iniciamos la instalación, entrando a (host)/n2/Installation, nos va a pedir que creemos un usuario y su clave (el cual se guarda en el web.config y es conveniente quitarlo luego).

Luego, se nos preguntará si queremos crear una base de datos nueva. Acá vamos a hacer una pequeña pausa.

stop

Acá es sumamente importante tener bien armada la connection string en el web.config. En nuestro caso, si recuerdan del post anterior, la conexión debía ser contra una base de datos Oracle 10g.  Afortunadamente en el web.config vienen escritos varios ejemplos de connection strings para distintas db, pero lamentablemente no para Oracle. Intentamos una connection string standard para Oracle, pero por algún motivo no funcionaba. Luego de muchas pruebas y gotas de sudor, la que funcionó tiene la siguiente estructura:

<add name="N2CMS" connectionString="Data Source=SERVER;User Id=USUARIO;Password=PASS;Pooling=True;Max Pool Size=10;" providerName="Oracle.OdpClient"/>

name => desde el código se suele obtener la conexión por este nombre (N2CMS)

Pooling, Max Pool Size => esto lo pusimos por el cliente, no es fundamental

providerName => ESTO FUE CLAVE, el cliente por defecto de Microsoft no nos funcionó bien

Con esto pudimos continuar la instalación, aunque nos toparíamos con otro problema, un Rack de servidores… tema que abordaré en otro post. Por último, nos daba la opción de importar la información, o de crear un nodo nuevo como inicio. Nosotros elegimos esta última opción, y para que nos deje elegir el tipo de nodo que nosotros queríamos, agregué este código a la clase del modelo:

[PageDefinition("Home", Description = "Página estilo home.",
TemplateUrl = "~/UI/HomePage.aspx", <strong>InstallerVisibility = N2.Installation.InstallerHint.PreferredStartPage</strong>)]

Con eso ya cumplimos lo referente a la instalación. Seguiremos en el próximo capítulo !

bye

Hasta la próxima !

HTTP Request usando C++ puro

Necesitaba realizar un POST sobre una página que estaba en un dominio de un servidor que utilizaba VirtualHost para tener configurados varios dominos sobre una misma ip.

Hasta acá parece simple para cualquier persona con cierto conocimiento de programación de hoy en día. De hecho con lenguajes como Java o .NET es casi trivial hacerlo.

Pero se me complicó un poco cuando en el requerimiento estaba que debía hacerse con C++ usando la mínima cantidad de dependencias (inclusive librerías externas).

Busqué en internet algún código que hiciera lo que necesitaba, que no tenga una licencia prohibitiva (costosa, inusable, o sencillamente demasiado compleja para resolver el problema en cuestión), y que sea simple y funcionara. Me costó, pero encontré una implementación que parecía cumplir con mis requisitos.

Pero cuando la fui a probar, no funcionaba. La página que debía acceder me decía forbidden. ¿Pero cómo era posible esto si cuando accedía con Firefox veía bien la página?

Entonces recurrí el viejo y querido telnet para ver que estaba pasando de la siguiente manera:

fernando@fernando-laptop:~$ telnet dominio-en-shared-hosting.com 80
Trying xx.xx.xx.xx...
Connected to dominio-en-shared-hosting.com.
Escape character is '^]'.
GET /

Y para mi sorpresa, lo que veía con telnet era el mismo forbidden.
Investigando un poco sobre el protocolo entendí lo que estaba sucediendo.

Para que los VirtualHost de apache funcionen correctamente, en la petición HTTP se tiene que especificar cual es el dominio al que se intenta acceder, si no se especifica se intenta acceder al default, que es el primero de los virtualhost definidos.

¿Pero como se especifica el dominio? Bueno, la forma más facil es escribir en lugar de GET / la url completa del recurso, por ejemplo GET http://dominio-en-shared-hosting.com/ de esta forma Apache puede diferenciar el VirtualHost al que se quiere acceder.

Otra forma, es especificando una versión del protocolo 1.0 o superior y agregando el header Host. Ya no sería un GET y nada más, sino que habria que escribir dos lineas.

GET / HTTP/1.0
Host: dominio-en-shared-hosting.com

Al usar esta forma, es necesario dejar un enter despues de ingresar la linea de Host (o si se quieren más headers, despues del último header) para que el servidor entienda cuando se dejó de escribir el request y procese la página.

Mi experiencia con n2cms, Episodio I

Seguramente quienes desarrollen aplicaciones web se habrán topado con la necesidad de elegir un buen Administrador de Contenidos, o CMS para los amigos. En este caso, no sólo teníamos un proyecto de tamaño considerable (una importante universidad argentina), si no que además estábamos “atados” a los siguientes requisitos:

Nuestra impresión fue…

Frustracion

Luego de analizar varias alternativas (en la mayoría de los casos, los requisitos eran limitantes) decidimos probar la siguiente que resultaba muy atractiva (con cierto grado de desconfianza): http://n2cms.com/

Entre las cosas que prometía (http://n2cms.com/Features.aspx) nos habían llamado la atención las siguientes:

  • Cómoda interfaz de usuario (importante para el usuario final del sitio)
  • Código abierto y “sencillo” para leer y extender (importante para el desarrollador, sobre todo si hay que realizar alguna modificación para agregar funcionalidad)
  • Persistencia con NHibernate, que por ende, daría soporte para Oracle (o cualquier otra base de datos soportada)
  • Integración con Membership (que además, es configurable para usarse con Active Directory y Oracle)

Contento

Nos lanzamos entonces a la aventura de probar este framework, que sinceramente nos dió más satisfacciones (y muchas !) que disgustos. Poco a poco iré contando los problemas que tuvimos durante el desarrollo y cómo los fuimos solucionando, sobre todo lo apuntado a la integración de Oracle y AD.

Vean cómo armar una aplicación, después del corte.

(more…)

Configurar Subversion Server, con autenticación de usuarios por OpenLDAP y permisos por path utilizando Authz

En Ubuntu 11.04 (y mas nuevos también) ya no se suele utilizar el archivo de configuración de LDAP sino que se usa una base de datos de configuración Esto tiene la ventaja de que no es más necesario reiniciar el servicio al cambiar algún seteo.

Por defecto esta base de datos se puede consultar utilizando SUDO ya que no tiene un usuario y contraseña. Se puede crear uno o crear una nueva base de datos donde configurar esos usuarios

Información adicional para instalación de OpenLDAP en Ubuntu 11.04: Ubuntu Server Guide – 11.04 – OpenLDAP Server

En esta guia iré relatando los pasos que fui haciendo desde una instalación de Ubuntu 11.04 en blanco con Apache, Subversion y LDAP instalados pero con escasa configuración, hasta culminar con un sistema que me permite agregar usuarios por ldap y actualizar un archivo Authz para poder especificar permisos de SVN con granularidad.

(more…)