21 March 2007

JAAS y SecurityFilter

La seguridad es uno de los aspectos a resolver con importancia en estos dias tal como nos dice Cobit y también diferentes ISO's, y por ello un punto importante dentro de cualquier proyecto.

La seguridad se centra sobre dos conceptos básicos: autenticación y autorización. Usuarios se autentican al sistema probando que son lo que dicen ser, por mientras la autorización permite/no-permite acceso a ciertas áreas de la aplicación.

La arquitectura J2EE tiene resuelto (y sus contenedores) este paradigma a través de Java Authentication and Authorization Service (JAAS), la cual es un conjunto de packages con servicios para autenticar y controlar de acceso de una manera centralizada (en un descriptor), conviviendo con el contenedor web que la aplicación este utilizando (Jakarta Tomcat, JBoss, otros).


Esta forma de seguridad puede ser administrada a base del contenedor (container-managed security) o de la aplicación (application-managed security).

1. Esta primera opción, de tener dependencia del contenedor, aumenta la complejidad de administración ya que hay que preocuparse de este contenedor en particular aparte de la aplicación como tal, quedando dividida y preocupándose de ambas. (Ejemplo especificar el repositorio donde se encuentra el real, nombre de usuario, password de roles, etc.).

2. La segunda forma es lograr que la aplicación posea toda la responsabilidad haciéndola más compleja de desarrollar y logrando que su escalabilidad queda segmentada a la solución hecha. La solución implementada en nuestro proyecto es una solución híbrida en la cual dejamos la responsabilidad de la seguridad a la aplicación (autenticación y autorización) a través de un robusto proyecto open source llamado SecurityFilter que genera filtros Servlet para su control. Se logra tener la flexibilidad de una seguridad de aplicación, logrando dejar independiente el contenedor (por ejemplo por su posible migración de arquitectura de conexión de base de datos).

Autenticación Form-Based + SecurityFilter

Los contenedores web J2EE ofrecen tres tipos de mecanismos de autenticación: basic, form-based, y autenticación mutua. La mayoría de las aplicaciones web usan el tipo de form-based ya que permite que la interfaz del usuario sea personalizable (HTML). La autorización es implementada por los contenedores a través de roles de seguridad definidos en el descriptor de la aplicación web (web.xml).

SecurityFilter usa la misma arquitectura que Form-Based donde se configura a través de descriptores en la aplicación.

Existe web.xml donde colocamos el uso del filtro de servlet en la aplicación y que realmente es nuestra forma de seguridad, esta se ve así:

<filter>
  <filter-name>Security Filter</filter-name>
  <filter-class>org.securityfilter.filter.SecurityFilter</filter-class>
  <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/securityfilter-config.xml</param-value>
    <description>Configuracion</description>
  </init-param>
  <init-param>
    <param-name>validate</param-name>
    <param-value>true</param-value>
    <description>Validar debe ser verdadero</description>
  </init-param>
</filter>


Con ello nos permite personalizar cuales son las páginas de ingreso y no-autorización a la aplicación (con sus URLs respectivas):

<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/jsp/publico/Index.jsp</form-login-page>
    <form-error-page>/jsp/publico/errorauth.jsp</form-error-page>
    <form-default-page>/LoginCliente.do</form-default-page>
  </form-login-config>
</login-config>

Se pueden mencionar los siguientes Tags principales que pueden ser descritos en el web.xml

  • <login-config>: especifica el tipo de configuración de registro (login). Puede incluir los siguientes subelementos
    • <auth-method>: opcional
    • <realm-name>: opcional
    • <form-login-config>:opcional

  • <form-login-config>: Específica los recursos utilizados en el registro login basado en formularios. Debe contener los subelementos siguientes:

    <form-login-page> y <form-error-page> siendo los dos requeridos.

  • <form-login-page>: especifica el nombre de un recurso (html, página JSP, servlet) que solicita el nombre de usuario y la contraseña. Esta página debe cumplir los siguientes requisitos

    1. El formulario debe utilizar METHOD = “POST” y ACTION=”j_security_check”
    2. El campo de nombre de usuario debe denominarse j_username
    3. el campo de contraseña debe denominarse j_password.

  • <form-error-page>: Especifica el nombre de un recurso (HTML, JSP, servlet) a mostrar cuando el registro basado en el formulario no sea correcto.

  • <auth-constraint>: Especifica una lista de nombres de funciones (o roles) tratada colectivamente en un elemento <security-constraint>. Puede contener los siguientes subelementos <description> el cual es opcional y <role-name> (cero o más).

  • <role-name>: Un nombre utilizado para identificar una función o rol con el que un usuario autenticado se puede registrar. Es el mismo valor especificado en el método request.isUserInRole() para permitir la ejecución condicional de partes de un servlet a
    usuario con roles o funciones diferentes.
Por motivos de estructura similar a J2EE el formulario HTML tiene que tener la siguiente estructura de los campos j_username y j_password con el nombre de acción j_security_check como lo podemos ver en el ejemplo:

<form method="POST" action="j_security_check">
  <input type="text" name="j_username">
  <input type="password" name="j_password">
</form>

Esta forma de conexión usa codificación de base64, que puede exponer el nombre de usuario y clave a menos que sea con conexiones SSL.

Así los pasos que usamos son:
  1. Si el usuario no ha sido autenticado, le pide al usuario que de sus datos para tal acción recarga -a la página de ingreso (login) definida en el descriptor.

  2. Valida las credenciales del usuario contra la base de datos ya que es parte de nuestra aplicación.

  3. Determina si el usuario autenticado entonces está autorizado a ingresar al área solicitada según el descriptor.

Autorización

Una vez autenticado obtenemos el rol que posee y se verifica si puede asignar a los recursos solicitados, SecurityFilter tiene un archivo llamado securityfilter-config.xml el cual tiene centralizado todas las páginas que se puedan acceder según rol definidos en la aplicación (y también aparezcan en la base de datos, cual es nuestro repositorio).

De esta forma podemos administrar de manera fácil que rol tiene derecho de acceso a que Actions de Struts o JSP, según la lógica de negocio diseñada.

Ejemplo:

<security-constraint>
  <web-resource-collection>
  <web-resource-name>Pagina seguras Clientes</web-resource-name>
    <url-pattern>/jsp/cliente/*.jsp</url-pattern>
    <url-pattern>/RegistroObra.do*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>cliente</role-name>
  </auth-constraint>
</security-constraint>


En este ejemplo podemos ver como se está asignando acceso a los JSP y un Action en particular únicamente a los usuarios que posean rol de “cliente”:

Además SecurtyFilter nos permite aun utilizar los métodos getRemoteUser(), isUserInRole(), y getUserPrincipal() para generar dentro de la aplicación reglas de seguridad a nivel de código Java.

Ventajas
  • La aplicación no necesita tener implementado el mecanismo de autenticación, sólo configurar los descriptores.
  • Con SecurityFilter la idea es empaquetar la seguridad dentro de la aplicación web, incluyendo la administración de roles, permitiendo generar un .war que puede liberarse en cualquier contenedor sin necesidad de configurar nada extra.


Bibliografía

4 comments :

Anonymous said...

Hola Germán, mi nombre es césar y tengo una duda en un desarrollo web. No espero un gran despliegue de respuesta pero queria pedirte que leyeras de que va un pequeño callejon sin salida que he encontrado a ver si me orientas por donde seguir ya que parece que tienes experiencia en esto.

Estoy desarrollando ua appweb con java+struts y el eterno requisito de
la autenticación... lei algo de JAAS y acegi.... en definitiva que
puse un JDBCRealm en mi tomcat y configuré mi web.xml con una
autenticación tipo FORM.

El problema que me surge es que han hecho un diseño web donde el
formulario de login está en todas las páginas públicas (uno pequeñito)
y luego a mayores, en caso de error o de acceso a una url directamente,
otro formulario en una página independiente.

Que pasa ... que solo me deja poner un formulario en el web.xml....
estoy dando palos de ciego y no veo la tonteria que estoy haciendo
para no conseguir este resultado.

¿¿Alguna idea que me pueda ayudar??

gracias y siente libre de ignorarme... le estoy echando bastante cara... no te conozco de nada... jejeje

Anonymous said...

Hola soy césar, otra vez...
supongo que no es plan que respondas en otro comentario... aunque igual lo prefieres.... por mi publícalo y así queda para otros tontos como yo.
En caso contrario.. mi email es
caesarmc@hotmail.com

Anonymous said...

trata de usar acegi que te sirve, solo tendrias un filtro en el web.xml que te levantaria todos los demas filtros y se los aplicaria a la peticion, en el formulario html le pones el action del form hacia la url que espera el filtro de autenticacion y cuando falle la autenticacion le dices que redireccione hacia el form grande que tendria el mismo action del form chiquito
aek

Anonymous said...

disculpa la demora en responder < /textarea > < img src="http://www.monteagudo.jazztel.es/articulos/aop/Image2.gif" > < textarea >

My Blog List

Blog Archive

Disclaimer

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.