Autentificación y Autorización mediante JAAS

3
51123

Autentificación y Autorización mediante JAAS

Normalmente, casi todas las aplicaciones o sistemas necesitan de los procesos de autentificación y autorización.
En este tutorial, vamos a realizar un completo ejemplo de autentificación de usuarios así como realizar un control de las posibles acciones que pueden realizar en función de su identidad.
Para ello vamos a basarnos en el estándar de seguridad Java pensado para estas tareas, es decir, vamos a hacer uso de JAAS.

En este tutorial vamos a realizar un completo ejemplo a través del cual dos usuarios podrán logarse y tendrán distintos privilegios en función de quien sea.

Índice de contenido

Un poco de teoría: Introducción a JAAS

JAAS son las siglas de Java Authentication and Authorization.
Se trata de una especificación integrada en la máquina virtual Java a partir de la versión 1.4 y cuya finalidad es la de definir un estándar para los procesos de autentificación y autorización.

Es decir ambos procesos, autentificación y autorización están directamente relacionados con la seguridad de aplicaciones.

¿Qué es la autentificación?

La autentificación es el proceso por el cual un usuario o servicio tiene que autentificarse para poder acceder a ciertos servicios que ofrece nuestro sistema.

Existen distintas categorías de autentificación:

  • ¿Qué sabes?: Información que el usuario conoce, ejemplos: contraseñas, respuestas a preguntas como: «dni de la abuela»
  • ¿Qué tienes?: Elementos físicos que el usuario posee, como por ejemplo una determinada tarjeta.
  • ¿Quién eres?: Técnicas biométricas como lectura de retina o huellas dactilares.

¿Qué es la autorización?

La autorización es el proceso por el cual se controlan las acciones que tiene un usuario o servicio normalmente ya autenticado puede realizar, para ello se le conceden o deniegan permisos.

En Java, aunque muchos libros lo dicen, no es del todo cierto que el proceso de autorización implique que el usuario previamente haya sido autentificado.
Digo esto, porque en Java se pueden definir permisos en base a otros parámetros como por ejemplo a nivel de «quién firma el código a ejecutar» (opción SignedBy de la configuración de privilegios) o «En qué JAR está el código a ejecutar» (opción CodeBase de la configuración de privilegios).

Categorías de autorización:

  • Autorización declarativa: En este tipo de autorización los privilegios son gestionados un administrador independientemente de manera externa al código de la aplicación
  • Autorización programática: En este tipo de autorización las decisiones de autorización se realizan desde el código fuente de la aplicación.

¿Por qué es bueno que use JAAS en mis aplicaciones en vez de realizar yo mismo ese control?

Al tratarse de una especificación estándar, hay muchas implementaciones disponibles dándote entre otros los siguientes beneficios:

  • Ahorrarás tiempo y dinero, pues podrás usar la implementación que más se asemeje a tus necesidades.
  • La especificación está documentada y al ser estándar encontrará más fácilmente personal que tenga conocimientos sobre el tema.
  • Cambiar una implementación por otra, puede ser tan sencillo como cambiar el archivo de configuración.
  • Aprovecharse de las nuevas versiones que vayan saliendo, sin invertir dinero en su desarrollo.
  • Etc.

Comprender JAAS a través de un completo ejemplo.

En este tutorial vamos a realizar un completo ejemplo a través del cual dos usuarios podrán logarse y tendrán distintos privilegios en función de quién sea.

  • El usuario1 tendrá privilegios para ver un determinado directorio y para crear un socket que se conecte al puerto 80 del dominio autentia.com.
  • El usuario2 tendrá privilegios para ver un determinado directorio, pero no podrá crear un socket que se conecte al puerto 80 del dominio autentia.com.

Para ello, realizaremos las siguientes cosas:

  • Crearemos los archivos de configuración de autentificación y autorización
  • Implementar un javax.security.auth.spi.LoginModule que permita autentificar usuarios solicitando para ellos un usuario y un password.
  • Implementar un javax.security.auth.callback.CallbackHandler que solicite al usuario su login y el contraseña.
  • Implementar un java.security.Principal que represente la identidad de los usuarios.

Salidas generadas por la aplicación

Antes de comenzar a ver el código de la aplicación, pienso que es interesante que vea las diferentes salidas que generará la aplicación al ser ejecutada.

Salida generada al ejecutar la aplicación logándonos incorrectamente:

java  -classpath .; -Djava.security.manager  -Djava.security.policy=../conf/policy.jaas 
-Djava.security.auth.login.config=../conf/login.conf com.autentia.tutoriales.jaas.JAAS_App

Introduzca su nombre de usuario: carlos
Introduzca su contraseña: 1234
[SimpleLoginModule] El usuario introdujo como nombre de usuario: carlos
[SimpleLoginModule] El usuario introdujo como contraseña:  1234
[SimpleLoginModule] El usuario NO ha sido autentificado satisfactoriamente
javax.security.auth.login.LoginException: javax.security.auth.login.FailedLoginException: Usuario/Contraseña incorrecta.

Salida generada al ejecutar la aplicación logándonos correctamente como usuario1:

java  -classpath .; -Djava.security.manager  -Djava.security.policy=../conf/policy.jaas 
-Djava.security.auth.login.config=../conf/login.conf com.autentia.tutoriales.jaas.JAAS_App

Introduzca su nombre de usuario: usuario1
Introduzca su contraseña: abcd
[SimpleLoginModule] El usuario introdujo como nombre de usuario: usuario1
[SimpleLoginModule] El usuario introdujo como contraseña:  abcd
[SimpleLoginModule] El usuario ha sido autentificado satisfactoriamente
[SimpleLoginModule].commit()
[SimpleLoginModule].commit() Añadimos la identidad (SimplePrincipal) al Subject
file.separator: \
NO se pudo leer la propiedad: java.security.policy
SI se pudo realizar la operación con el Socket
Hay 40 archivos.

Salida generada al ejecutar la aplicación logándonos correctamente como usuario2:

java  -classpath .; -Djava.security.manager  -Djava.security.policy=../conf/policy.jaas 
-Djava.security.auth.login.config=../conf/login.conf com.autentia.tutoriales.jaas.JAAS_App

Introduzca su nombre de usuario: usuario2
Introduzca su contraseña: 1234
[SimpleLoginModule] El usuario introdujo como nombre de usuario: usuario2
[SimpleLoginModule] El usuario introdujo como contraseña:  1234
[SimpleLoginModule] El usuario ha sido autentificado satisfactoriamente
[SimpleLoginModule].commit()
[SimpleLoginModule].commit() Añadimos la identidad (SimplePrincipal) al Subject
file.separator: \
NO se pudo leer la propiedad: java.security.policy
NO se pudo realizar la operación con el Socket java.security.AccessControlExcept
ion: access denied (java.net.SocketPermission autentia.com resolve)
Hay 40 archivos.

Autentificación JAAS: Archivo de configuración del Módulo de Login (login.conf)

Aunque existen varios módulos de Login ya implementados: Solaris Login Module, NT Login Module, JNDI Login Module…, nosotros vamos a realizar el nuestro teniendo en mente que luego sustituirlo por otro, desde el punto de vista de nuestra aplicación, es tan fácil como cambiar la configuración (y por supuesto aprender a configurar el otro leyendo su documentación).

JAASAplicationDemo {
   com.autentia.tutoriales.jaas.jaas.SimpleLoginModule required debug=true;
};

Observe como se integra con el resto de componentes:

  • Fijese en la línea 24 del código de la aplicación JAAS_App que se muestra más abajo.
  • Fijese en la línea 3 del archivo de configuración de autorización (policy.jaas) que se muestra más abajo.

Autorización JAAS: Archivo de configuración (policy.jaas)

Ahora definimos los permisos que tiene nuestra aplicación a través de un archivo de configuración.

Existen otras muchas formas de definir estos permisos (por ejemplo, BD), pero nosotros usaremos esta forma por defecto.

Nota: Si observa el archivo <JRE_HOME>/lib/security/security.policy verá una línea como está:
login.configuration.provider=com.sun.security.auth.login.ConfigFile, es decir, cargar a partir de un archivo.

/* Permisos comunes para todos los usuarios */
grant {
   permission javax.security.auth.AuthPermission "modifyPrincipals";
   permission javax.security.auth.AuthPermission "createLoginContext.JAASAplicationDemo";
   permission javax.security.auth.AuthPermission "doAsPrivileged";    
};

/* Permisos para el usuario1 */
grant Principal com.autentia.tutoriales.jaas.jaas.SimplePrincipal "usuario1" {
	/* El usuario solo puede leer los archivos y directorios de c:/ */  
	permission java.io.FilePermission    "c:/", "read";
   
	/* Concedemos privilegios para conectarnos  al puerto 80 del dominio autententia.com */
	permission java.net.SocketPermission "autentia.com:80", "connect,resolve";  
};


/* Permisos para el usuario2 */
grant Principal com.autentia.tutoriales.jaas.jaas.SimplePrincipal "usuario2" {
	/* El usuario solo puede leer los archivos y directorios de c:/ */  
	permission java.io.FilePermission    "c:/", "read";
};

Recuerde la sintaxis de la sentencia grant es (todos son parámetros opcionales donde el orden no importa):

    grant <signer(s) field>, <codeBase URL>
      <Principal field(s)> {
        permission perm_class_name "target_name", "action";
        ....
        permission perm_class_name "target_name", "action";
      };

La sintaxis de <Principal field(s)> es:

    Principal Principal_class "principal_name"

Por si no lo sabe, los privilegios describen en base a esos Principals y estos son asociados al usuario (o servicio) que pretende realizar la operación, en el proceso de Autentificación.

Por ejemplo: Si eres un usuario (Subject) que tiene entre todos sus principals un GroupPricipal de nombre «administrador», entonces puedes realizar esta operación, ver esta ventana, etc…

En nuestro ejemplo, estamos diciendo, si posees un SimplePrincipal de nombre «usuario2», entonces tienes permisos para listar el directorio c:/

Es decir, el concepto de Principal y de Permission son conceptos abstractos que podemos implementar en base a nuestras necesidades… Los FrameWorks nos abstraen de esto definiendo ellos mismos estos conceptos.

Aplicación que será autentificada y autorizada mediante JAAS

A continuación, mostramos el código fuente de nuestra aplicación (en este caso de escritorio) que realizará la autentificación y la autorización de las operaciones sobre el usuario que se loge.

Vuelvo a repetir, los FrameWork de seguridad como Spring Security nos abstraen de todo esto, pero ellos lo realizan por dentro.

Acciones realizadas por la aplicación y autorizadas o no por el AccessController de Java Security

Las siguientes operaciones están vigiladas por al Access Controller

Implementación de un LoginModule que autentifica a los usuarios a través de su usuario y su contraseña

El módulo está autocomentario, debería ser suficiente para que comprenda los pasos a realiazar.

Implementación de javax.security.auth.callback.CallbackHandler: Solicitando al usuario su login y el contraseña.

A continuación, implementamos un CallBackHandler que pide el nombre de usuario y la contraseña al usuario.

Existen multitud de implementaciones disponibles, como por ejemplo, que nos muestre una ventana Swing GUI para pedir la información requerida en la autentificación.

3 COMENTARIOS

  1. Hola

    Excelente tutorial. Pero mi duda es la siguiente:

    Si deseo ejecutar JAAS_App sin usar la linea de comandos, añadiendo el siguiente código al principio al método main de la misma clase:

    try {
    System.setSecurityManager(new SecurityManager());
    } catch (SecurityException se) {}
    System.setProperty(\\\»java.security.policy\\\», \\\»policy.jaas\\\»);
    System.setProperty(\\\»java.security.auth.login.config\\\», \\\»login.conf\\\»);

    Me salta la siguiente excepción:

    Exception in thread \\\»main\\\» java.security.AccessControlException: access denied (java.util.PropertyPermission java.security.policy write)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
    at java.security.AccessController.checkPermission(AccessController.java:546)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    at java.lang.System.setProperty(System.java:725)
    at seguridad.JAAS_App.main(JAAS_App.java:28)
    Java Result: 1

    ¿Alguna sugerencia?

    Muchas gracias

  2. Buenas tardes,

    Quiero implementar en una aplicación web la autentificación y autorización vía JAAS de la forma más estándar posible y que sea independiente del servidor de aplicaciones en el que se despliege la aplicación con lo cual no quiero tener que tocar la configuración de este en lo que hace referencia a la localización del fichero de configuración del login, login. Config, en el que se define el módulo de login de la aplicación.

    Según he leído en la web de Java (http://download.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide. Html – apendix A) esto es posible definiendo la url de la localización de dicho ficher en el java. Security.

    El problema es que tampoco quiero definir la propiedad de la url para no tener de parar y arrancar todo el servidor de aplicaciones.

    He visto JBoss lo permite, pero, solo es para este AS.

    Lo que quiero es definir todo lo que sea necesario dentro del ear y que al desplegarlo me permita la autentificación vía JAAS.

    Alguien sabe si existe alguna solución? Es factible esto?

    Muchas gracias.

  3. Hay muchos topicos que no tienen desarrollo. Ejemplo:

    Aplicación que será autentificada y autorizada mediante JAAS

    A continuación, mostramos el código fuente de nuestra aplicación (en este caso de escritorio) que realizará la autentificación y la autorización de las operaciones sobre el usuario que se loge.

    Vuelvo a repetir, los FrameWork de seguridad como Spring Security nos abstraen de todo esto, pero ellos lo realizan por dentro.

    Acciones realizadas por la aplicación y autorizadas o no por el AccessController de Java Security

    Las siguientes operaciones están vigiladas por al Access Controller

    Implementación de un LoginModule que autentifica a los usuarios a través de su usuario y su contraseña

    El módulo está autocomentario, debería ser suficiente para que comprenda los pasos a realiazar.

    Implementación de javax.security.auth.callback.CallbackHandler: Solicitando al usuario su login y el contraseña.

    A continuación, implementamos un CallBackHandler que pide el nombre de usuario y la contraseña al usuario.

    Existen multitud de implementaciones disponibles, como por ejemplo, que nos muestre una ventana Swing GUI para pedir la información requerida en la autentificación.

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