Spring Security
Spring Security
celebrado en Boadilla del Monte el día 19 de Febrero de 2010, y en el que Paradigma Tecnológico
fue partner del evento. A continuación, se expone brevemente, las características principales que
presenta Spring Security 3.0.
Spring Security se ha convertido en la librería de referencia dentro del mundo Java, para dar
soporte a los servicios de autenticación y autorización de una aplicación. Las razones del por qué
esta librería se ha convertido en referencia son:
- Proyecto enmarcado dentro de las soluciones de Spring Framework, y todo lo que ello conllleva:
Una vez definidas las características principales que han convertido a Spring Security en la librería
referente, para dar solución a la seguridad de aplicaciones, pasaremos a comentar las principales
funcionalidades que presenta la librería y una breve descripción de cada una de ellas.
Antes de nada, definir que un proceso de autenticación consiste en identificar a la “entidad” que
realiza una acción sobre la aplicación y garantizar que es quién dice ser. La entidad que realiza una
acción sobre la aplicación es conocida con el nombre de principal.
Como puede ver el lector, el parámetro de entrada authentication básicamente tendrá los datos
básicos del principal (en un ejemplo sencillo el nombre de usuario peticionario). Con este dato, se
procederá a obtener toda la información de credenciales asociadas con el principal, y se
comprobará si dichas credenciales son correctas. En el caso que el sistema de seguridad sea basado
en username y password, se comprobará que la password pasada por el usuario, es correcta
(buscando para ello la credencial dentro del repositorio de seguridad configurado en la aplicación).
En el caso que el proceso de autenticación no sea correcto (credenciales incorrectas o nombre de
usuario no válido) el componente lanzará la correspondiente AuthenticationException. En el caso
que el proceso de autenticación, por el contrario, sea correcto, se procederá a obtener los roles
(autoridades) asociadas al principal y serán guardadas en el objeto Authentication, que será
devuelto por el AuthenticationManager. Finalmente este objeto Authentication será guardado por
el componente SecurityContextHolder en el contexto de seguridad oportuno (normalmente el
ThreadLocal).
Como anteriormente se comentó, un modelo que se repite mucho en las soluciones de Spring es la
delegación de responsabilidades dentro de los distintos componentes de la arquitectura. En
el caso del AuthenticationManager, se dispone de un conjunto de componentes ProviderManager
los cuales son los encargados de implementar el proceso de autenticación. Los objetos
ProviderManager están más cercanos a la tecnología usada para implementar el repositorio de
seguridad de la aplicación. Así por ejemplo, si nuestra sistema de autenticación está soportado
mediante un directorio activo, dispondremos de un objeto LdapAuthenticationProvider encargado
de realizar las labores de autenticación contra dicho directorio activo.
En el último diagrama se puede observar como los distintos componentes colaboran entre sí para
implementar el proceso de autenticación de una aplicación.
Por suerte, Spring Security viene con la implementación de numerosos ProviderManager que
dan cabida a la integración con distintos sistemas de soporte para el proceso de autenticación.
Simplemente es necesario configurar dichos componentes para adaptarlos a la particularidad que
pueda tener la aplicación que estemos desarrollando.
Una de las principales ventajas introducidas en la versión 2.5 de Spring Security es la inclusión de
un namespace específico, que da soporte a la configuración de los distintos componentes que
forman parte de la solución de autenticación y autorización de aplicaciones. Anteriormente a esta
versión, era necesario definir un conjunto de beans muy extenso y existía la posibilidad de
error en la gestión de las dependencias de los distintos beans. Gracias a la incorporación de
namespace a la solución, al desarrollar se le abstrae de muchas particularidades internas de la
solución, proporcionando un fichero XML de configuración (namespace) que hace la labor de
parametrización mucho más sencilla. Así por ejemplo si queremos configurar un componente
AuthenticationManager que acceda a BBDD para la obtención de las credenciales y roles aplicación
bastaría con incluir la siguiente porción de código XML dentro del fichero de configuración de la
librería:
Como se puede ver en el ejemplo, el único parámetro necesario para configurar el gestor de
autenticación es el datasource que indicará donde está el esquema de Base de datos donde reside el
repositorio con los datos de seguridad.
Como iremos viendo en este post, el fichero de configuración permitiría la configuración de todos
los elementos necesarios para realizar la autenticación y autorización de una aplicación web sobre
protocolo http.
Bien, lo primero que es necesario definir para proceder a autenticar y autorizar una aplicación web
con Spring Security es la definición de un ServletFilter, concretamente DelegatingFilterProxy.
Básicamente lo que realiza este filtro es, como su propio nombre indica, de proxy entre un entorno
gestionado por el contexto de servlets y un entorno gestionado por el contexto de aplicación de
Spring. Lo que permite este filtro, por tanto es que todos los componentes que forman parte de
la arquitectura de Spring Security puedan ser definidos mediante los ficheros XML de
definición de beans típicos de Spring y las ventajas del uso del patrón DependencyInjection.
Como se comentó anteriormente, adicionalmente Spring Security permite una configuración de los
componentes mediante el uso de un namespace, el cual consiste básicamente en un fichero XML
que cumple un determinado esquema, el cuál está preparado para la configuración de los distintos
componentes de la solución de un modo sencillo.
Por tanto, lo único que se necesita para configurar los servicios de seguridad web es introducir la
siguiente configuración dentro del fichero XML de configuración:
Configuración de servicios de seguridad web
Dentro de la configuración, adicionalmente se puede ver como se pueden securizar urls mediante el
uso de la etiqueta . Básicamente esta etiqueta contiene el patrón de url que se quiere securizar y
una lista de roles que son necesarios para poder acceder al recurso. En el caso que se indiquen
varios roles, con que el usuario contenga uno de esos roles, sería suficiente para disponer de
permiso para dicha URL.
Funcionalidades remember-me las cuales darán soporte a permitir que el usuario pueda
guardar las credenciales en el navegador, y así no tener que volver a introducirlas en el
siguiente proceso de autenticación. Usa un soporte de cookies con aplicación de algoritmos
hash para la salvaguarda de la información de la credencial.
Selección del canal de seguridad. Mediante el uso del atributo requires-channel dentro
de la etiqueta se puede exigir que determinadas URL’s sean seguras dentro de la aplicación.
Spring Security hace las oportunas redirecciones que sean necesarias para el cambio de
canal.
Gestión de la sesión.
o Control de los timeouts de sesión. Se le puede indicar una página cuando se
realice una petición de una sesión que está invalidada.
o Control de la sesión concurrente. Es posible controlar el número de sesiones
activas para un mismo usuario. Esto supone una protección contra el ataque de
fijación de sesión: http://en.wikipedia.org/wiki/Session_fixation
Soporte para OpenID
Desde el punto de vista de la arquitectura, Spring Security mantiene una cadena de filtros, cada
uno de los cuales da cabida a una funcionalidad dentro de los procesos de autenticación y
autorización entre cada petición y respuesta. Es posible modificar y extender la cadena de filtros
para ajustarse a las necesidades particulares de cada aplicación. Así por ejemplo por destacar
algunos mencionar los siguientes filtros:
Como se puede ver en la figura, existen numerosos interceptores en la cadena, pero no vamos a
comentar todos ellos en este post, con el objetivo de disponer de una visión más global de la
librería. Para más detalle sobre dichos interceptores consultar la guía de referencia de Spring
Security.
En definitiva, toda la cadena de filtros es creada y aislada del programador mediante el uso del
namespace. No obstante, y como se ha comentado antes, es posible modificar y extender la
cadena de filtros para poder adaptarlo a las necesidades particulares de la aplicación.
Autorización en SpringSecurity
AccessDecisionManager
Como se puede ver en la figura, el sistema de autorización de Spring Security está basado en un
sistema de Votos. Concretamente SpringSecurity viene con tres implementaciones de
AccessDecisionManager:
RoleVoter: Este componente simplemente comprueba si para cada rol especificado para
proteger al recurso protegido lo presenta el principal que realiza la petición. En tal caso
emite un voto positivo. (Revisar el componente ). En el caso que el principal no tenga el rol
el componente realizará un voto negativo. En concreto para el caso del componente se
presenta un AffirmativeBased AccessDecisionManager, con lo que con que el principal
disponga de un rol de los especificados en la lista, se procederá a dar permiso al recurso
protegido (en este caso la URL).
AuthenticatedVoter. Este componente permite diferenciar entre acceso anónimo al
recurso, completamente autenticado u autenticado mediante mecanismos remember-me
(IS_AUTHENTICATED:ANONYMOUS, IS_AUTHENTICATED_REMEMBERED,
IS_AUTHENTICATED_FULLY). Así por ejemplo en el ejemplo expuesto anteriormente, se le
permitía a usuarios anónimos acceder a la página de autenticación del usuario. Esto
normalmente suele ser necesario para aquellas páginas que necesitan tener un
comportamiento diferente para usuarios autenticados, de usuarios no autenticad
En resumen, para securizar recursos HTTP, el sistema de votos aplica una lógica OR, de tal manera
que con que el principal disponga de al menos uno de los roles especificado en la lista de roles
asociados al recurso protegido, el AccessDecisionManager se procederá a dar acceso a dicho
recurso protegido.
Existen cuatro formas distintas de securizar las ejecuciones de métodos dentro de Spring Security:
Esta opción permite una securización centralizada de todos los métodos de la capa de servicio.
Adicionalmente presenta una expresión AspectJ de definición del pointcut, el cual permite aplicar
de manera flexible seguridad a varios objetos. En el ejemplo expuesto se están securizando todos
los métodos del paquete com.mycompany que acaben por Service e independientemente del
número de parámetros que tenga el método.
MethodSecurityInterceptor
Otra opción posible, aunque las expresiones no son tan potentes como el caso de AspectJ.
Directamente sobre la clase que se quiere securizar se introducen anotaciones específicas (propias
de Spring Security o las definidas por el estándar JSR-150). Es necesario dentro del namespace
configurar los atributos secured-annotations o jsr-250-annotations a “enabled” en el elemento mdel
namespace.
Con estas opciones, el nivel de seguridad disponible siempre es a nivel de rol (autoridad). Sin
embargo, Spring Security 3.o introduce un nuevo mecanismo mucho más potente que permite la
introducción de expresiones Spring-EL (nuevas en Spring 3.0) para securizar la invocación de
métodos. Con este modelo, lo que se permite es disponer de expresiones más completas para
definir la seguridad a nivel de método, existiendo la posibilidad de interactuar con los parámetros
de entrada. Así por ejemplo, con las expresiones Spring-EL, supongamos que disponemos de un
método de consulta de facturas de clientes. Resulta que dentro de los requisitos de seguridad de la
aplicación, se define que únicamente los administradores pueden imprimir facturas superiores a
5000 €.
Para este propósito Spring introduce las anotaciones @PreAuthorize, @PostAuthorize, @PreFilter y
@PostFilter . Para el ejemplo expuesto anteriormente, la anotación quedaría de la siguiente
manera:
En cuanto a las anotaciones @PreFilter y @PostFilter se usan para filtrar elementos de una
colección antes o después de la ejecución del método. Pongamos un ejemplo, supongamos que de la
lista de Facturas devueltas por un método, se quieren filtrar aquellas que sean mayores de 5000€,
para esta funcionalidad sería necesario implementar una anotación @PostFilter indicando la
condición anteriormente definida.
Para finalizar nuestro recorrido por SpringSecurity, a continuación se define cómo SpringSecurity
mediante su sistema de control de acceso permite la securización de los objetos de dominio.
Por tanto, para solucionar esta problemática, SpringSecurity viene con un esquema de tablas (4
tablas en total) que permiten guardar los objetos de dominio, los permisos de la aplicación y el
cruce entre los distintos permisos y objetos de dominio necesarios para implementar la seguridad.
Por defecto, el nivel de permisos que viene con la solución son: CREATE, DELETE, READ, WRITE y
ADMIN, aunque es sencillo implementar nuevos permisos.
Para más información de cómo se configura el módulo ACL, consultar la guía de referencia de
Spring Security o el ejemplo Contacts que viene incluido dentro del código de SpringSecurity. El
propósito de este post es comentar las posibilidades que presenta SpringSecurity sin entrar en los
detalles de configuración más específicos.
Conclusiones
Como se ha podido ver a lo largo del artículo, SpringSecurity proporciona una librería con gran
capacidad para la implementación de los servicios de autenticación y autorización de una
aplicación. Con una configuración mínima es posible realizar la autenticación de la aplicación en
BBDD, LDAP, integración con CAS para Single Sign On, etc… Asimismo mediante mecanismos
declarativos es posible la securización de los recursos de una aplicación web, con la potencia que
dan las expresiones AspectJ de definición de pointcuts. Asimismo todas las funcionalidades de
remember-me y de gestión de usuarios anónimos está implicita dentro de la solución, con lo que
prácticamente no es necesario implementar componentes para dar cabida a dichas funcionalidades.
En definitiva, enhorabuena de nuevo al equipo de Spring Framework, realizando una solución que
considero de referencia dentro de la tecnología Java para la seguridad de aplicaciones Java.
A los lectores de este post, agradecer que introduzcan todos los comentarios que crean
convenientes con el objeto de que el artículo sea lo más completo y útil posible, para que por lo
menos, alguien que no conociera SpringSecurity pueda tener un primer contacto con él y conozca
las posibilidades de esta magnífica librería.