Java Series – Authentication y Authorization en J2EE

Si hay algo de lo que no se pueden quejar las personas que desarrollan en web con asp.net es sobre lo fácil que es el manejo de seguridad a recursos protegidos (authorization) y lo intuitivo de los tipos de autenticación que ofrece .net (authentication), pero suele ocurrir que por razones laborales/educativas etc dan el salto a otra plataforma de desarrollo y oh! sorpresa… donde esta esa sección de configuración para proteger los accesos??? Y así empieza la odisea … El post de hoy expone justamente el manejo de seguridad en J2EE.
Para el ejemplo vamos a crear un proyecto web (El proyecto está con JSF 2) y vamos a definir directorios donde van a estar las páginas de administración para 2 roles de usuario: Administrador y Super Administrador, controlando el acceso al recurso que le corresponda. La estructura para el ejemplo es la siguiente:

Como se visualiza en el gráfico están claramente definidas las carpetas, en las cuales se supondría que están las páginas a las que sólo se puede tener acceso con ciertos privilegios.
Adicionalmente el proyecto cuenta con la página forbidden.xhtml que para el caso es la página a la que es redirigido el request cuando se trata de acceder a una sección protegida sin tener las credenciales requeridas, y la página index.xhtml que es la página de login.
El estándar casi por omisión para seguridad en J2EE es Spring Security, pero para alguien que viene de otra plataforma le introduce otro millón mas de conceptos (lo cual no es malo, sólo que a veces son tan amplios que nos apartan totalmente el camino de lo que realmente queremos implementar), así que desde la especificación de Servlets 2.3 tenemos un feature que permite interceptar los requests y de esa manera determinar quien está tratando de acceder a los recursos de la aplicación; este feature son los Filters.
Muchos son los casos de uso en los que nos sirve interceptar requests, pero vamos a enfocarnos en autenticacion y autorización.
Para definir un filtro simplemente, creamos una clase que implemente la interfaz javax.servlet.Filter, e implementamos los métodos que nos exige:

public void init(FilterConfig filterConfig);

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);

public void destroy();

Tenemos definido el filtro y para interceptar los requests tenemos que configurarlo en el web.xml y mapear las rutas en las que va actuar el mismo, para hacerlo colocamos la siguiente configuración:


    <filter>
        <filter-name>AuthAdminFilter</filter-name>
        <filter-class>demo.security.AuthAdminFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AuthAdminFilter</filter-name>
        <url-pattern>/administration/*</url-pattern>
    </filter-mapping>

El primer elemento filter-name es referencial, lo que si es importante es en filter-class colocar el nombre completo de la clase que está implementando el filtro, luego en el siguiente filter-name se hace referencia a la declaración anterior y colocamos la ruta que queremos que el filtro administre, al colocar * cualquier página que esté dentro de ese contexto será validada.
Para validar en el filtro si el usuario está autenticado y el rol que tiene, en la pantalla de login, una vez validadas las credenciales vamos a almacenar una variable de sesión con un objeto de tipo UserBean, que basicamente tiene el id del usuario y el rol:

        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext extContext = context.getExternalContext();
        String url = "";
        if(isAdmin(user, password))
        {
            url = extContext.encodeActionURL(
                    context.getApplication().getViewHandler().getActionURL
                    (context, "/administration/adminPanel.jspx"));
            extContext.getSessionMap().put(USER_KEY, new UserBean(user, "admin"));
            extContext.redirect(url);
            return;

        }
        if(isSuperAdmin(user, password))
        {
            url = extContext.encodeActionURL(
                    context.getApplication().getViewHandler().getActionURL
                    (context, "/superadmin/superAdminPanel.jspx"));
            extContext.getSessionMap().put(USER_KEY, new UserBean(user, "superadmin"));
            extContext.redirect(url);
            return;
        }

        }

En el código mostrado se valida si las credenciales son válidas, si es así lo redirige a la sección de administración correspondiente, y finalmente pone en una variable de sesión el objeto de usuario.

Como tenemos 2 secciones que queremos validar los requests vamos a crear 2 filtros, uno para validar si es “admin” y otro para validar si es “super admin”, por lo tanto configuramos otro filtro en el web.xml:


     <filter>
        <filter-name>AuthSuperAdminFilter</filter-name>
        <filter-class>demo.security.AuthSuperAdminFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AuthSuperAdminFilter</filter-name>
        <url-pattern>/superadmin/*</url-pattern>
    </filter-mapping>

Hasta ahora tenemos el mapeo de las url’s a los filtros que van a validar los request, ahora veamos el desarrollo de las clases que implementan el Filtro de los requests:

Filtro para Sección de Administradores

public class AuthAdminFilter implements Filter {

    private FilterConfig configuration;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.configuration = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (((HttpServletRequest) request).getSession().getAttribute(
                AuthBean.USER_KEY) == null) {
            ((HttpServletResponse) response).sendRedirect("../forbidden.jspx");
        } else {
            chain.doFilter(request, response);
        }

    }

    @Override
    public void destroy() {
        configuration = null;
    }

Filtro para Sección de Super Administradores

public class AuthSuperAdminFilter implements Filter {

    private FilterConfig configuration;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.configuration = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if (((HttpServletRequest) request).getSession().getAttribute(
                AuthBean.USER_KEY) == null || !((UserBean)((HttpServletRequest) request).getSession().getAttribute(
                AuthBean.USER_KEY)).getRole().equals("superadmin") ) {
            ((HttpServletResponse) response).sendRedirect("../forbidden.jspx");
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        this.configuration = null;
    }

}

Ambas implementaciones son casi idénticas salvo por el caso de que en la de superadmin validamos que además de que exista en sesión la variable que nos indica que está autenticado, el usuario tenga el rol de “superadmin”, en caso que no cumpla la condición se lo redirige a la sección de acceso restringido.
Bueno, eso es todo en el post 😀 para ver el ejemplo pueden descargar el código fuente desde aquí, es un proyecto netbeans 6.9 con glassfish.

Saludos,
gish@c

Java Series – Desmitificando Multithreading

Uuu ya con ese titulo ni ganas de leer este post verdad? xD  Pero tranquilidad que por la misma razón se llama “Desmitificando”, porque no es algo tan del otro mundo tener una aplicacion de esas caracteristicas en JAVA.
Hace algunos anhos cuando la tecnología de múltiples procesadores empezó a ubicarse en las maquinas de escritorio, no solo genero un impacto a nivel de hardware, sino también a nivel de software, ya que de alguna u otra manera nos dio la posibilidad de dar mas procesamiento a los equipos clientes, permitiéndonos mezclar el paradigma de Thin client, con un aprovechamiento real de todos los recursos de hardware sobre los que corren nuestras aplicaciones.
A estas alturas de la vida, el no utilizar al máximo los ciclos de CPU en nuestras aplicaciones no es solo un crimen tecnológico sino también un atentado al medio ambiente, y de esta premisa nacen conceptos como el Grid Computing, donde pones a disposición el tiempo ocioso de tu CPU para ser aprovechado por otros. En fin, el problema de trasfondo es que el hardware esta evolucionando mucho mas rápido que el software, y no todas las aplicaciones están preparadas para aprovechar la infraestructura sobre la que están siendo utilizadas, generando desuso de recursos.
En una experiencia previa, teníamos un cliente con un servidor de 8 procesadores y una cantidad considerable de RAM, y resulta que su personal de IT nos reporto como un Issue el hecho de que nuestra aplicación del lado servidor no estaba utilizando todos los recursos disponibles, es decir; le hicieron un monitoreo al uso de los procesadores cuando se ejecutaban procesos masivos y vieron que solo uno se utilizaba al máximo, el resto eran ciclos ociosos de cpu… Así que como buenos Ingenieros y Arquitectos de Software nos toco reestructurar la aplicación e identificar los procesos que se podían hacer de manera paralela para lanzar múltiples procesos y sacarle el jugo (como decimos por acá)  a los procesadores.
Si recordamos esas divertidas clases de Sistemas Operativos, se nos viene a la mente el gráfico del ciclo de un proceso donde la premisa era que un solo proceso corría a la vez, pero ahora eso varia dependiendo de la capacidad de los procesadores (Quad Core (4), I7(6), etc) y pues, como hacemos que nuestra aplicación utilice todos estos recursos??? A traves de Threads (Hilos).
(No podía omitir toda la historia anterior como introducción al tema, pero ya estamos en la parte interesante: el ejemplo! )
La mayoría de los lenguajes nos proveen las herramientas necesarias para cumplir con el objetivo de hacer aplicaciones multithreading (.Net, Scala, Google’s GO, etc, etc) y Java no es la excepción con sus clases para manejar threading.
El uso de threads implica básicamente identificar los procesos que se pueden ejecutar en paralelo, y una vez identificado no es complicado implementarlo; los dolores de cabeza se producen cuando tenemos que mezclar ese modelo con reacciones en UI (que levanten la mano los que alguna vez vimos una RED CROSS OF DEATH, o en .net el DataTable Index Corrupted) ya que los controles, y ciertas estructuras solo pueden ser manipuladas por un hilo a la vez.
El ejemplo de este post toma 2 procesos para realizar operaciones con threads:

  • Ejecutar asincronicamente una busqueda en iTunes de canciones por artista (Evita congelar el UI)
  • Simular un proceso de almacenamiento masivo de los resultados (Multithreading)

Es una molestia que se congele el UI mientras esperamos respuesta a la ejecución de un proceso, y un usuario es feliz si su aplicación le dice que esta haciendo, mientras que si se queda la pantalla congelada dirá “se colgó esta vaina” y seguramente le hara un kill como sea posible y llamara a service desk. Este caso esta representado en ejemplo de buscar a través del iTunes Store Search API, debido a que es una búsqueda en un servidor externo a través de la web, y dependemos básicamente de la latencia en la transmisión de datos para que la respuesta congele el UI hasta que se complete el request.
Hacemos la consulta esperando como resultado un texto en JSon y con la libreria Gson lo desarmamos en un abrir y cerrar de ojos, para luego mostrarlo en un JTable, así que fácilmente podemos identificar la parte del proceso que debe ser asincronica: La consulta al servidor web y el procesamiento de los resultados hasta que están en el formato esperado por el modelo del JTable.
Hasta ahí cumplimos con la primera parte de la premisa que era identificar la parte del proceso que podemos hacer asincronica, ahora la segunda parte es interactuar con el UI, para lo cual JAVA se ha encargado de abstraernos de este problema y desde su versión 6 incluye oficialmente al SwingWorker, el cual se encarga de ejecutarse en un contexto en el cual se ejecuta en background sin congelar el UI y permitiéndonos interactuar con los controles; la declaracion de la clase debe heredar de SwingWorker

public class iTunesSearchHandler extends SwingWorker<Object, Object>

Lo que queremos que se ejecute asincronicamente lo colocamos en el metodo doInBackground y para hacer alguna acción cuando termina el proceso utilizamos el metodo done

@Override
    protected Object doInBackground() throws Exception {
        label.setVisible(true);
        URL url = new URL(searchUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setReadTimeout(15 * 1000);
        connection.connect();
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        StringBuilder stringBuilder = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line + "\n");
        }
        parseJsonToList(stringBuilder.toString());

        return "";
    }

@Override
    protected void done() {
        super.done();
        label.setVisible(false);
    }

Las lineas donde cambia la visibilidad de un label es para mostrar el tipico “loading” en la pantalla mientras se ejecuta el request y así sabemos que esta haciendo la aplicación.
Como indique anteriormente la otra parte del ejemplo es simular un procesamiento masivo de la información que tenemos en memoria y típicamente es almacenarla en algún lugar; es importante identificar estas operaciones de base de datos como las típicas que podemos realizar paralelamente, (si son datos dependientes o referenciados entre si es vital manejar sincronizacion de procesos) ya que de nuestro DBMS esperamos un modelo ACID que nos garantice la integridad de la información. Por lo cual de manera descabellada vamos a lanzar un thread para grabar, el cual lanzara un nuevo thread por cada registro a guardar! 🙂

@Override
    protected Object doInBackground() throws Exception {
        label.setVisible(true);
        for(iTunesSearchResult item : data)
        {
            item.setRowIndex(data.indexOf(item));
            new iTunesSaveHandler(item).execute();
        }
        return "";
    }

Que conseguimos con eso? Pues que como ningún registro es dependiente del otro cada uno se ejecuta como una transacción independiente y ponemos a trabajar los procesadores al tener que ejecutar muchos procesos simultáneos 😛

Para mostrar el resultado del proceso, podemos ver con el jConsole los hilos que se ejecutan y ademas en el output vemos los mensajes donde el orden de almacenamiento no es necesariamente el orden en el que se fueron ejecutando los hilos:

Pantalla de aplicacion demo


Monitoreo antes de proceso masivo


Monitoreo despues de proceso masivo


Log de transacciones

Como conclusiones de los prints anteriores, podemos ver que en el monitoreo después de ejecutar la simulación de almacenamiento masivo se incrementan la cantidad de threads en la aplicación y el uso de cpu; mientras que en el log de transacciones podemos ver que los registros se van procesando no necesariamente en el orden que fueron lanzados, ya que cada transacción es independiente y finalmente depende de la prioridad que le asigne el cpu al thread para su ejecución.

Saludos,
gish@c

Descargar Proyecto Netbeans 6.8

Edición en JTable con Db4o

Una de las ventajas de una base de datos orientada a objetos como Db4o, es la simplicidad al momento de trabajar con modelos de objetos un poco mas complejos. Este post es para mostrar como usando la flexibilidad de Java junto con Db4o (v7.4) se puede hacer un mantenimiento en un grid, al final el resultado se verá más o menos asi:

Como base tome las clases Car y Pilot que vienen en el tutorial de Db4o, y como se puede ver tiene un combo de seleccion de pilotos ya que es lo minimo que se requiere cuando se tiene un modelo de objetos así.
Lo importante aqui es sacarle el provecho al sistema de referencias de la base de datos, ya que al estar editando los objetos en el grid solo basta con hacer un update a la referencia que es esta editando para que se guarden los cambios, Las clases del proyecto se pueden ver en el gráfico a la izquierda.

El proyecto está con Netbeans 6.5, y en el pkg com.sample.objects estan los objetos mas importantes, los del pkg com.sample son los que agrega por default el nb para proyectos java desktop.
Las clases DBManager, CarDB, y PilotDB son las que se encargan de las consultas y actualizaciones a la base de datos; las clases importantes en las que entraremos en mas detalle son las Model ya que son las clases que se encargan de todo detras del JTable y es donde pondremos lo necesario para persistir cualquier modificación que hagamos directo en la tabla.
Lo principal es comenzar con el modelo que vamos a proveer al JTable para que sepa con lo que está lidiando, asi que extendemos de AbstractTableModel, y se sobrecargan los métodos requeridos, la sobrecarga clave para el ejemplo es del método setValueAt ya que para éste caso luego de establecer el valor a la propiedad actualizamos el objeto que fue editado:

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
super.setValueAt(aValue, rowIndex, columnIndex);
Car car = getDatasource().get(rowIndex); //Aqui obtenemos la instancia del objeto que está siendo editado
switch (columnIndex) {
case 0:
car.setModel(aValue.toString());
break;
case 1:
car.setColor(aValue.toString());
break;
case 2:
car.setPilot((Pilot) aValue);
break;
DBManager.getInstance().getCarDB().storeCar(car);
}

Básicamente, fuera del código en Java para hacer edición en grid es el único llamado a realizar para persistir las modificaciones. Para que esto sea posible las clases model tienen una lista que utlizan como datasource


public class CarTableModel extends AbstractTableModel {
private List datasource;
.
.

public class PilotComboBoxModel extends AbstractListModel implements ComboBoxModel {
private Pilot current;
private List datasource;
.
.
.

En la clase EditPane se encuentra la carga de las listas con lo que se obtiene de la base, los objetos se mantienen en el sistema de referencias de Db4o:

//Se carga la lista de pilotos en el combo para el grid</span>
PilotComboBoxModel cmbModel = new PilotComboBoxModel(DBManager.getInstance().getPilotDB().getPilots());
cmbPilots = new JComboBox(cmbModel);
SetTableModel(cmbPilots);

private void SetTableModel(JComboBox cmbPilots) {
//Se carga la lista de carros a mostrar en la tabla
carTableModel = new CarTableModel(DBManager.getInstance().getCarDB().getCars());
//Al jtable carTable le seteamos el model y el editor para la columna de pilotos
carTable.setModel(carTableModel);
carTable.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(cmbPilots));
}

El código del ejemplo se lo pueden descargar aquí y Db4o por aca.

Para usar el ejemplo luego de ejecutar por primera vez el proyecto hay que comentar el llamado a la linea que llena la base de datos en la clase EditInTableDb4oApp.

public static void main(String[] args) {

DBManager.PopulateDatabase();// Comentar despues de primera ejecucion
launch(EditInTableDb4oApp.class, args);
}

En un siguiente post le agrego un par de cosas al ejemplo para cumplir con el CRUD, bueno… el Read es una busqueda que no es para el ejemplo asi que en realidad sera un CUD 😛

Saludos,
gish@c