JAAS (Java Authentication and Authorization Service)

12
82271

JAAS (Java Authentication and Authorization Service) y Jboss.

0. Índice de contenidos.

1. Introducción

JAAS (Java Authentication and Authorization Service) es una interfaz
que permite a las aplicaciones Java acceder a servicios de control de
autenticación y acceso. Apareció como paquete
opcional en la versión 1.3 y lleva siendo parte del estándar
desde la versión 1.4.

Puede usarse con dos fines:

    - la autenticación de
usuarios: para conocer
quién está ejecutando nuestro código
java,

    - la autorización de
usuarios: para
garantizar que quién lo ejecuta tiene los permisos
necesarios
para hacerlo.

En este tutorial vamos a ver un ejemplo de cómo implementar dicha interfaz desde una aplicación JEE, en la que la información sobre los usuarios y sus perfiles la mantenemos en una base de datos.

Comprobaremos que la tarea se limita a la parametrización de ficheros de configuración (*.xml): del lado del servidor de aplicaciones y del lado de nuestra aplicación web.

El objetivo es delegar el mecanismo de autenticación y autorización en el servidor de aplicaciones. En la práctica significa, que ya no será necesario implementar un filtro de autorización en todas nuestras aplicaciones web y no tendremos que copiar el LoginAction.java o el LoginBean.java de una aplicación a otra arrastrando posibles errores.

Al implementar una interfaz que forma parte del estándar, nos beneficiamos no solo del acceso a la información del usuario y su perfil a través de métodos que forman parte del mismo (del estándar), si no que, además, nos podemos beneficiar de otras implementaciones que encapsulan dichos métodos dentro de su librería de tags, como el proyecto tomahawk de apache, lo veremos en el último punto.

Por último, al tratarse de una interfaz podríamos decidir modificar la política de seguridad pasado mañana, para que vez de autenticarnos contra base de datos lo hiciésemos contra un servidor LDAP… y lo único que tendríamos que tocar es un fichero de configuración en el servidor.

2. Entorno.

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Sobremesa Dell Dimension 6400, 2.13 Ghz, 2 Gb RAM
  • Sistema operativo: Windows XP Media center Edition
  • JDK 1.6.0_2
  • Eclipse 3.3.
  • Jboss 4.2.1.GA
  • MySQL 5.0

3. Creación de tablas y carga de datos en MySQL.

Si la autenticación la vamos a realizar contra base de datos, lo primero que necesitamos es crear las tablas en MySQL.

Ni el nombre de las tablas es fijo, ni el nombre de los campos de cada tabla, con lo que si ya tenemos un modelo de datos que responde a esta estructura no será necesario migrarlo. Veremos que, tanto la consulta de usuario, como la consulta de perfil se realizan a través de una sentencia sql parametrizable.

El siguiente script crea dos tablas:

  • role: con una clave única y un nombre. El campo nombre será importante a la hora de definir la autorización.
  • user: con una clave única, un login, una contraseña y una clave foránea que vincula un usuario a un rol.

DROP TABLE IF EXISTS `user`;  
DROP TABLE IF EXISTS `role`;  
CREATE TABLE `role` (  
`id` int(10) unsigned NOT NULL,  
`name` varchar(64) collate utf8_spanish_ci NOT NULL,  
PRIMARY KEY (`id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;  
CREATE TABLE `user` (  
`id` int(10) unsigned NOT NULL auto_increment,  
`login` varchar(128) collate utf8_spanish_ci NOT NULL,  
`password` varchar(128) collate utf8_spanish_ci NOT NULL,  
`roleId` int(10) unsigned NOT NULL,  
PRIMARY KEY (`id`),  
KEY `ndx_user_roleId` (`roleId`),  
CONSTRAINT `fk_user_roleId` FOREIGN KEY (`roleId`) REFERENCES `role`  
(`id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

El siguiente script inserta dos usuarios y dos roles:

  • usuario:»admin», con contraseña:»admin», asociado al rol «ADMINISTRATOR»
  • usuario:»user», con contraseña:»password», asociado al rol «USER»

INSERT INTO `role` (`id`,`name`) VALUES  
(1,'ADMINISTRADOR'),  
(2,'USER');  
INSERT INTO `user` (`id`,`login`,`password`,`roleId`) VALUES  
(1,'admin','ISMvKXpXpadDiUoOSoAfww==',1),  
(2,'user','X03MO1qnZdYdgyfeuILPmQ==',2);  

Las contraseñas están encriptadas usando el algoritmo MD5 en Base64.

4. Definición del datasource y configuración de la política de seguridad en Jboss.

La definición de una fuente de datos en Jboss se realiza añadiendo un fichero con extensión -ds.xml en el directorio jboss-4.2.1.GA\server\default\deploy, con el siguiente contenido:

  
  
  
simpleDS  
jdbc:mysql://localhost:3306/test  
com.mysql.jdbc.Driver  
test  
test  
  

Tenemos que configurar:

  • jndi_name: con un id único para nuestro datasource, que usaremos para invocarlo desde nuestra política de seguridad (el siguiente punto),
  • connection-url: con la dirección y el nombre de nuestra base de datos MySQL
  • user-name: con el login de un usuario para acceder a la base de datos. Claro está que no se refiere a uno de los usuarios de las tablas antes creadas, sino a un usuario de MySQL con permisos de lectura para acceder a la base de datos.
  • password: con la contraseña de acceso del usuario anterior.

En nuestro caso tenemos un fichero jboss-4.2.1.GA\server\default\deploy\test-ds.xml para el acceso a la base de datos MySQL de test, con un usuario de MySQL test con contraseña test.

Jboss no viene con el driver para MySQL preinstalado, con lo que, si aún no lo tenemos, deberemos obtenerlo de la siguiente ubicación Download Connector/J 5.0: y copiar el jar, mysql-connector-java-5.0.*-bin.jar, en jboss-4.2.1.GA\server\default\lib\

En el fichero jboss-4.2.1.GA\server\default\conf\login-config.xml
debemos introducir la siguiente política de
seguridad:

  
  
  
  
java:/simpleDS  
select password  
from User where login=?  
select r.name, 'Roles'  
from User u, Role r where u.roleId=r.id and  
login=?  
MD5  
base64  
  
  
  

Tenemos que configurar:

  • <application-policy name=»simpleWebAuthenticationPolicy«>: con un id único que identifica nuestra política de seguridad, que usaremos desde la aplicación web para enlazarla,
  • <module-option name=»dsJndiName»>java:simpleDS<module-option>: con el nombre del datasource que hemos definido en el punto anterior,
  • <module-option name=»principalsQuery»>select password from User where login=?</module-option>: con la sentencia sql para la obtención de la contraseña del usuario que recibe como parámetro. Como comentaba, si vuestro modelo de datos no se corresponde con el de este ejemplo, aquí asignaríamos la sentencia correspondiente.
  • <module-option name=»rolesQuery»>select r.name, ‘Roles’ from User u,Role r where u.roleId=r.id and login=?</module-option>: con la sentencia sql para la obtención del nombre del perfil asociado al usuario, con las mismas consideraciones que en el punto anterior,
  • <module-option name=»hashAlgorithm»>MD5</module-option>:indica el nombre de algoritmo que hemos usado para guardar nuestras contraseñas en la tabla de usuarios,
  • <module-option name=»hashEncoding»>base64</module-option>: indica el tipo de encoding que usará el algoritmo para comprobar la contraseña.

En este punto hemos configurado el módulo JAAS de Jboss para que acceda a nuestra base de datos a través de un datasource, el mismo que debería usar nuestra aplicación web.

Cambiar de base de datos, para pasar a un entorno de producción, por ejemplo, es sencillo, basta con modificar el vínculo (el nombre del datasource) entre la política de seguridad y el datasource, o lo que es más común, al tener varios datasources (uno por entorno), tendríamos varias políticas de seguridad (una por cada uno de ellos).

5. Estructura de nuestra aplicación JEE.

Crearemos un proyecto web dinámico en Eclipse, en nuestro caso con nombre SimpleWeb, con la siguiente estructura de directorios:

SimpleWeb

La idea es que:

  • el contenido del directorio /pages no sea visible si no se ha accedido a la aplicación a través de la página de login, y
  • el contenido del directorio /pages/admin no sea visible a todos los usuarios, sólo a aquellos con perfil de administración.

Veamos primero el
código de nuestras páginas:

La página index.jsp,
tendría el siguiente código:

<%@page language="java" contentType="text/html;  
charset=UTF-8"%>  
<%request.getSession().invalidate();%>  
<%response.sendRedirect("pages/home.jsp");%>  

03. Limpia la sesión para eliminar el login de usuario si lo hubiese.
04. Redireccióna la petición a una página que estará protegida, la que se mostrará
después de un login satisfactorio.

El filtro de autorización de JAAS funciona de modo que, si se accede a una página protegida y no hay usuario en la sesión, te remite a la página de login. Teniendo en cuenta esto, lo que debe hacer nuestra página de inicio es redirigir la petición a una página protegida, para que salte la página de login y tras un login satisfactorio nos redirija a la página protegida.

Un error común es no llevar a cabo ésta primera redicción, y marcar como página de entrada el login.jsp, si hacemos esto (podemos probarlo), tras el login, nos intentará redirijir al login, apareciendo el siguiente error:

Estado HTTP 400 - Referencia directa al formulario de conexión (página de formulario de login) inválida

La página login.jsp,
tendría el siguiente código:

<%@page  
language="java" contentType="text/html; charset=UTF-8"%>  
  
  
login  
  
  
Usuario
Contraseña

Contiene el formulario de entrada de usuario y contraseña:

  • es obligatorio que el formulario tenga un name concreto (j_security_check) y un action concreto (j_security_check), el action invoca al filtro de autorización de JAAS,
  • el nombre del campo de entrada para el login de usuario debe llamarse j_username y el campo password j_password.

La página loginError.jsp,
contiene un mensaje de error
informando que el usuario y/o la contraseña introducidos no
son correctos:

<%@ page language="java" contentType="text/html;  
charset=ISO-8859-1"  
pageEncoding="ISO-8859-1"%>  
  
  
  
  
Login Error  
  
  

Usuario y/o contraseña erróneos

Volver

La página /pages/home.jsp,
contiene un título y un enlace para acceder a la
administración
del web:

<%@ page language="java" contentType="text/html;  
charset=ISO-8859-1"  
pageEncoding="ISO-8859-1"%>  
  
  
  
  
Home de SimpleWeb  
  
  

Home de SimpleWeb

Acceso a administración

La página /pages/admin/home.jsp,
contiene un título informando que estamos en la
administración del web:

<%@ page language="java" contentType="text/html;  
charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  
  
  
  
  
Home de la administración de  
SimpleWeb  
  
  

Home de la administración de SimpleWeb

Si arrancamos el servidor y accedemos a la aplicación en
éste punto del tutorial accediendo a al siguiente url: http://localhost:8080/SimpleWeb/ veremos que:

  • tenemos acceso al home (pages/home.jsp) de nuestro web a través de la página de inicio, sin necesidad de introducir el usuario y contraseña, y
  • desde la home tenemos acceso a la administración pulsando sobre el enlace.

6. Securizando nuestra aplicación.

En el fichero WebContent/WEB-INF/web.xml
añadiremos las siguientes restricciones de seguridad:

  
  
  
User Authentication  
Policy  
/pages/*  
  
  
*  
  
  
  
  
Administrator Authentication  
Policy  
/pages/admin/*  
  
  
ADMINISTRATOR  
  
 

El contenido del directorio /pages/* (06. <url-pattern>/pages/*</url-pattern>) será visible a todos los usuarios, independientemente de su perfil (09. <role-name>*</role-name>).

El contenido del directorio /pages/admin/* (16. <url-pattern>/pages/admin/*</url-pattern>) será visible solo para los usuarios con un perfil de administrador (19. <role-name>ADMINISTRATOR</role-name>), donde ADMINISTRATOR es el nombre del perfil en base de datos. Que debe corresponderse con el resultado de la sentencia sql definida en el parámetro rolesQuery del fichero login-config.xml.

En el mismo fichero WebContent/WEB-INF/web.xml
añadiremos la definición de los 2 roles que tenemos:

  
  
Administrator  
User  
ADMINISTRATOR  
  
  
Final User  
USER  
 

El contenido de los campos <role-name> se corresponde con el nombre de los perfiles en base de datos.

Por último, en el mismo fichero WebContent/WEB-INF/web.xml
añadiremos la definición del formulario de entrada de login y contraseña:

  
  
FORM  
Form-Based Authentication  
Area  
  
/login.jsp  
/loginError.jsp  
  
 

Definimos el método de autenticación (a través de formulario), la página de login y la página que aparecerá tras un error en el login.

El m&eacutetodo de autenticación puede ser también un diálogo de sistema con <auth-method>BASIC</auth-method>.

Para enlazar el filtro JAAS con el módulo de
autenticación de jboss, crearemos un fichero WebContent/WEB-INF/jboss-web.xml
con el siguiente contenido:

  
java:/jaas/simpleWebAuthenticationPolicy  
 

El nombre de la política de seguridad (simpleWebAuthenticationPolicy) es el definido en el campo <application-policy
name=»»> del fichero login-config.xml.

Si probamos de nuevo la aplicación veremos como «salta» la página de login al acceder al index:

  • si accedemos con el usuario admin:admin, veremos como tenemos acceso a la página de login y pulsando sobre el enlace accedemos a la página de administración
  • si accedemos con el usuario user:password, veremos como tenemos acceso a la página de login y pulsando sobre el enlace aparecerá un error de autorización, porque no forma parte del perfil de administradores.

      Estado HTTP 403 - El acceso al recurso pedido ha sido denegado
      

7. Obtención el usuario y su perfil asociado.

La interfaz HttpServletRequest nos proporciona dos métodos para acceder a información sobre el usuario autenticado:

  • getUserPrincipal: devuelve el usuario conectado,
  • isUserInRole: recibe como parámetro un string y devuelve un boolean, true si el usuario pertenece al rol que se pasa como parámetro,

Vamos a modificar la página pages/home.jsp para ocultar el enlace hacía la administración si el usuario no tiene un perfil de administrador, y para mostrar el name del usuario.

<%@ page language="java" contentType="text/html;  
charset=ISO-8859-1"  
pageEncoding="ISO-8859-1"%>  
  
  
  
  
Home de SimpleWeb  
  
  

Home de SimpleWeb

Usuario: <%=request.getUserPrincipal().getName()%>

<% if ( request.isUserInRole("ADMINISTRATOR")) { %>

Acceso a administración

<% } %>

8. Integración en la librería de componentes jsf de Apache Tomahawk.

Si estamos trabajando con la implementación de jsf de myfaces y añadimos a nuestra librería de tags la extensión de Apache Tomahawk, podremos comprobar como uno de los atributos de los tags es visibleOnUseRole.

Vamos a modificar la página pages/home.jsp:.

<%@ page language="java" contentType="text/html;  
charset=ISO-8859-1"  
pageEncoding="ISO-8859-1"%>  
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>  
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>  
  
  
  
  
  
Home de SimpleWeb  
  
  

Home de SimpleWeb

Usuario: <%=request.getUserPrincipal().getName()%>

El atributo visibleOnUserRole puede recibir varios perfiles separador por comas.

9. Conclusiones.

¿Para qué vamos a implementar un mecanismo de autenticación y/o autorización propio, si tenemos uno dentro del estándar JEE?. Si además, es relativamente fácil de configurar…

Para ampliar información sobre éste tutorial consultad el Capítulo 8 (Seguridad) del manual de Jboss:

  • buscar org.jboss.security.auth.spi.LdapLoginModule: para ver cómo configurar la seguridad contra un servidor LDAP,
  • buscar org.jboss.security.auth.spi.UsersRolesLoginModule: para ver cómo configurar la seguridad a través de ficheros de propiedades.

También podéis revisar éste tutorial de Roberto Canales sobre Seguridad en Tomcat.

Una reflexión para terminar: «Para entrar en casa ajena puedes, echar la puerta abajo a patadas (con más o menos perseverancia) o, simplemente mirar debajo del felpudo para ver si el dueño deja ahí una copia de sus llaves».

Un saludo.

Jose

12 COMENTARIOS

  1. Hola!
    Gran tuto pero tengo una duda:

    ¿No se puede personalizar el fichero login.jsp con algun css y usar imagenes?

    Utilizo imagenes y no las carga y tampoco me carga los estilos que tengo en el fichero css.

  2. Excelente tuto gracias, les dejo una observación:

    En la política definen el rol ADMINISTRATOR:

    ADMINISTRATOR

    Mientras que en la BD, definieron el rol ADMINISTRADOR 😉

  3. Muchas gracias por todos los comentarios.

    Efectivamente, hay que tener cuidado con el nombre de los roles.

    En cuanto a la personalización de los estilos de la página, sí se pueden personalizar, será un problema tuyo con las rutas relativas a los ficheros de recursos (css e imágenes).

    Un saludo.

    Jose.

  4. Hola de nuevo!
    sigo con el problema con imagenes y css.

    Mi estructura es la siguiente:

    web
    -css/
    –style.css
    -images/
    –logo.jpg
    -protected/
    –home.jsp
    -login.jsp
    -error.jsp
    -index.jsp

    También he probado metiendo los directorios de imagenes y css dentro de la carpeta protected y tampoco me funciona.

    ¿Alguna sugerencia? ¿Qué estoy haciendo mal?

    Gracias!!!

  5. Hola cómo estás, excelente tutorial, justamente ahora estoy tratando de implementar la seguridad en Java EE y me viene muy bien. Tengo una duda bien grande, estoy haciendo una aplicación en donde los roles se deben crear desde la misma aplicación, así como también los permisos que se asignen deben ser desde la misma aplicación. Es decir, no sólo debo contar con dos roles y permisos predefinidos, sino que estos deben ser dinámicos y el que use el sistema debe elegir qué roles hay y qué permisos asignarles. Cómo haría esto con JAAS, es posible, me pueden dar alguna idea. Recalco que estoy empezando en esto y tengo muchas dudas, me pueden ayudar…necesito implementar la seguridad de forma dinámica para mi tesis, ayúdenmen con sus ideas.

  6. Hola que tal muy bien tutorial solo que tengo un problema al securizar la aplicacion, me logueo y me aparece la leyenda usuario o contrasena incorrecta, alguien tendra de casualidad el codigo fuente que me pudiera facilitar ya revise todo y sigue sin funcionar saludos…

  7. Hola que tal se que es viejo el post pero
    me gustaria saber si puedo validar un usuario que ya esta conectado
    desde otro equipo y denegarle el inicio de sesion ???

  8. Lo primero es darte las gracias Jose Manuel por compartir tu conocimiento.

    Sé que es antiguo el post, pero me encuentro con un «reto» que me quita el sueño (trad. me está robando horas)

    He configurado una aplicación para que maneje la seguridad por contenedor.
    Se valida contra un directorio LDAP
    Toda la aplicación está securizada, salvo imágenes una pequeña sección de libre acceso.
    Hasta aquí todo va bien, si entro en la zona securizada, pide credenciales , caso contrario deja entrar.

    El tema es que quiero enlazarla desde otra aplicación. Realmente desde otro sistema. Ni siquiera es java. Es un entorno bastante heterogéneo. Lo máximo que puedo hacer es lanzar una URL.

    Para ello lo que hago es una llamada a una acción que recibe un token. (vamos a presuponer el token válido y que, a través de él se puede conseguir loggin y roles del usuario)

    En este escenario, la acción que recibe el token debería ser capaz de cargar la información del usuario (en particular user y roles) y redireccionar a la zona securizada.
    Lo deseable sería que entonces la aplicación diera al usuario como loggeado correctamente.
    El objetivo es controlar el acceso evitando loggearse entre varios aplicativos.

    El problema, es obvio, por mucho que se dé como válido el token, el sistema pedirá login/password ya que para la aplicación/contenedor el usuario no está loggeado.

    ¿Cómo podría hacer para evitar ese loggin?Es decir, hay alguna forma de «crear» esas credenciales del usuario?

    gracias por anticipado

  9. […] JAAS Reference Guide. Weld y Arquetipo de Maven para JBoss 7. Seguridad básica, JBoss 5.1. JAAS (Java Authentication and Authorization Service) JBoss autenticación basada en certificados cliente – Adictos al trabajo. Cómo asegurar una […]

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad