viernes, septiembre 30, 2011

Módulo de login personalizado para Tomcat (II)

Hola de nuevo a todos.

En una de nuestras entradas del año 2009 (Módulo de login personalizado para Tomcat), comentábamos cómo modificar el modo de autenticar y autorizar a nuestros usuarios en aplicaciones para Tomcat, para adaptarlo a nuestras necesidades concretas.

Si leéis dicha entrada, veréis que lo último que teníamos que hacer es crear un archivo de configuración (jaas.config) e indicar la ubicación de dicho archivo, pasándola como parámetro a la máquina virtual
(por ejemplo: -Djava.security.auth.login.config=C:"/jaas.config").

Este parámetro se incluiría en el archivo catalina.bat o catalina.sh, dependiendo del sistema operativo.

El problema es que a veces es complicado manejar este archivo de configuración, sobre todo en sistemas en producción, ya que se requieren permisos, reiniciar el servidor, etc...

Bien, pues existe un modo de saltarse estos problemas con el archivo de configuración. Básicamente, lo que tenemos que hacer es:


  • Añadir un context listener (o usar uno que ya exista).
  • Incluir el archivo "jaas.config" en el mismo paquete que el context listener.
  • Obtener la ruta física del archivo en el despliegue de la aplicación. Esto se hace recuperando el archivo empaquetado como un recurso de la clase, y pasando el URI del recurso al constructor de un objecto File. Finalmente, la ruta física del archivo se obtiene mediante el método getAbsolutePath() del objeto File.
  • Pasar la ruta física del archivo como propiedad del sistema. La propiedad en concreto es "java.security.auth.login.config".
Puedo asegurar que lo he probado y funciona. Os pongo un ejemplo sencillo:

Supongamos que creamos un context listener (MyContextListener) el el paquete "com.test.listeners".
Creamos o copiamos el archivo "jaas.config" también en el paquete "com.test.listeners".

La clase MyContextListener quedaría de esta forma:


package com.test.listeners;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
 * Web application lifecycle listener.
 * @author pedrop
 */
public class MyContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        File jaasConfigFile = null;
        try {
            jaasConfigFile = new File(getClass().getResource("jaas.config").toURI());
            System.setProperty("java.security.auth.login.config", jaasConfigFile.getAbsolutePath());
        } catch (Exception e) {
            Logger.getLogger(MyContextListener.class.getName()).log(Level.SEVERE, null, e);
        }
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
}

Por si a alguien le interesa, existe otra solución en la que no es necesario usar un archivo "jaas.config". Para dar alguna pista, os diré que requiere extender el objeto LoginContext.

Saludos

2 comentarios:

FiTe dijo...

Muy buen aporte pedrop, pero yo le veo un inconveniente.

El utilizar este método para establecer el fichero jaas implica el que, en el caso de cambiar las políticas de acceso, tendrías que hacerlo en todas las aplicaciones que tengas desplegadas.

De todos modos, creo que este sistema (el login personalizado), una vez que le coges el "truquillo", es de lo más efectivo.

pedrop dijo...

¿Cambiar las políticas de acceso? No termino de entenderlo.

Ten en cuenta que el archivo jaas.config alude explícitamente a una clase concreta que extiende la clase LoginModule.

En caso de que el módulo cambie, tendrías el mismo problema independientemente de que el archivo de configuración esté fuera o dentro de la aplicación.

Además, si el .war está desplegado, se puede parar la aplicación, modificar el jaas.config dentro de la carpeta desplegada de la aplicación e iniciarla de nuevo, nada diferente de lo que tendrías que hacer en caso contrario, de modo que no entiendo muy bien el "pero".