Capítulo 6: Spring Security Cómo hacer de nuestra aplicación un lugar seguro Este capítulo se centrará en la seguridad y cómo Spring a través de su proyecto Spring Security se hace cargo de ella. Javier Sevilla Sánchez Trabajo de fin de carrera de la Ingeniería Técnica en Informática de Gestión (I.T.I.G) Contenido ¿Qué es Spring Security? ............................................................................................................... 4 Autenticación en Spring Security .................................................................................................. 4 AuthenticationManager ................................................................................................................ 5 Seguridad en aplicaciones Web .................................................................................................... 7 Autorización en Spring Security .................................................................................................. 10 Seguridad de la capa de servicio ................................................................................................. 12 Configuración de seguridad a nivel global (namespace)......................................................... 12 Seguridad a nivel de bean ....................................................................................................... 12 Con el objeto MethodSecurityInterceptor .............................................................................. 12 Seguridad a nivel de anotación ............................................................................................... 13 ¿Qué es Spring Security? 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. Esto se debe principalmente a que es un proyecto proyecto enmarcado dentro de Spring y como ya hemos visto gracias a Spring podremos hacer código mantenible, reutilizable, ágil y robusto. El código y diseño del componente es inmejorable, es sabido que dentro de la comunidad de desarrolladores Java tiene un gran uso siendo un referente. Spring Security es un framework maduro que viene de otro proyecto llamado Acegi. Como la mayoría del framework de Spring, Spring Security ofrece una gran facilidad de configuración y parametrización, gracias al uso de mamespace y la inyección de dependencia. Permite la integración con los sistemas legacy de autenticación más importantes del mercado: BBDD, LDAP, CAS (para single sign-on), gestión de certificados, etc. Spring Security tiene un gran respaldo de la comunidad con lo que hay una gran cantidad de documentación y ejemplos. Autenticación en Spring Security Un proceso de autenticación consiste en identificar 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 como principal, en Spring es llamada AuthenticationManager, encargado de implementar el proceso de autenticación en las aplicaciones. Antes de describir cómo es el diseño de AutenticationManager, vamos a presentar otros componentes importantes y necesarios para poder comprender el proceso de autenticación. Authenticacion, este objeto guardará los datos asociados a AutenticationManager y sus roles. Así este objeto es en el que sea apoya el AuthenticationManager para implementar el servicio de autenticación. SecurityContextHolder, encargado de guardar los datos del principal y sus roles dentro del contexto de seguridad. Como hemos dicho, la información del principal la alberga Authentication, así que SecurityContextHolder guarda el objeto Authentication en el contexto de seguridad. Así la información que reside en el objeto Authentication pueda ser consultada en todo momento por cualquier componente dentro de la aplicación. Objeto UserDetailsService, Spring suele delegar responsabilidades en otros objetos, en este caso el objeto AuthenticationManger delega en el objeto UserDetails las labores de obtención de la información del usuario sobre el repositorio de seguridad. Así, si los usuarios están en una base de datos, el objeto UserDetails realizará las consultas necesarias para obtener la información del AuthenticationManager. AuthenticationManager Este interfaz sólo define un método: Authentication authenticate (Authentication authenticaction) throws AuthenticationException; El parámetro de entrada tendrá los datos básicos de autenticación. Con este dato se prodecerá a obtener toda la información de credenciales asociadas con el principal y se comprobará si dichas credenciales son correctas. En el caso de que las credenciales no sean correctas el proceso de autenticación lanzará una AuthenticationException. Si la autenticación es correcta se obtendrán las autoridades asociadas al usuario y serán guardadas en el objeto Authentication, el cual será devuelto por el método. Éste objeto será guardado por el componente SecurityContextHolder en el contexto de seguridad. Como hemos dicho, AuthenticationManager delega responsabilidades, teniendo un conjunto de componentes ProviderManager los cuales son los encargados de implementar el proceso de autenticación. Los objetos ProviderManer están más cercanos a la tecnología usada para impementar el repositorio de seguridad de la aplicación. Así si disponemos de un LDAP, tendremos el objetoLdapAuthenticationProvider, si accedemos a una base de datos tendremos un DaoAuthenticationProvider, etc, etc. En el siguiente diagrama se muestra la colaboración entre componentes para implementar el proceso de autenticación de la aplicación, en este caso se muestra para un delegado que buscará en una base de datos gracias al DaoAuthenticationProvider. Spring tiene un gran número de Providers así, podremos dar soporte a multitud de sistemas. Así podremos adaptar nuestras aplicaciones a distintas particularidades, presentes y futuras. Una de las grandes ventajas que tiene Spring Security es la inclusión de namespace específicos que da sopote a la configuración de los distintos componentes que forman parte de la solución de autenticación y autorización de aplicaciones. Antes, 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, al desarrollar se abstrae de muchas particularidades internas de la solución, proporcionando un fichero XML de configuración más sencillo. --TODO--CODIGO NAMESPACE ---FIN TODO---Como vemos en el ejemplo el único parámetro de configuración necesario es el gestor de autenticación donde está el esquema de base de datos donde reside el repositorio de seguridad. Este fichero permitirá la configuración de todos los elementos necesarios para realizar la autenticación y autorización de una aplicación web sobre HTTP. Seguridad en aplicaciones Web Lo primero es definir es el ServletFilter DelegatingFilterProxy. Este filtro lo que hace es un proxy entre los Servlets y el contexto de Spring. Así, este filtro permite que todos los componentes que forman parte de la arquitectura de Spring Security puedan ser definidos mediante los ficheros XML. Spring Security, como ya hemos dicho, se puede configurar mediante el uso de namespace, que es un fichero XML que cumple un determinado esquema, facilitando la configuración. Dentro del fichero de configuración incluiremos el siguiente código: ---TODO---- ---FIN TODO---- Dentro de la configuración se puede ver como se pueden securizar URL. La 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 se tenga uno de los roles será suficiente para disponer de permiso para dicha URL. Dentro de este fichero de configuración se puede configurar las siguientes grandes funcionalidades: Remember-me, así el usuarios puede 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 guardar la información. Selección de canal de seguridad, si usamos el atributo requires-channel dentro de la etiqueta, se puede exigir que determinadas URL 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, control de timeouts de sesión, y control de la sesión concurrente. El control de los timeouts de sesión sirve para indicar cuando esta invalidada. El control de sesión concurrente es para controlar el número de sesiones que están activas para un mismo usuario. Esto supone una protección contra el ataque de fijación de sesión. ---TODO--http://en.wikipedia.org/wiki/Session_fixation ---END TODO--Soporte para OpenId. ---TODO BUSCAR OPENID--- Spring Security mantiene una cadena de filtros que cada uno de ellos da cabida a una funcionalidad dentro de los procesos de autenticación y autorización entre cada petición y respuesta. Es posible modificar la cadena de filtros. Dentro de estos filtros destacan: FilterSecurityInterceeptor, el cual es encargado de manejar la seguridad de los recursos HTTP manejando los elementos definidos en el namespace. ExceptionTranslationFilter, encargado de manejar excepciones lanzadas por los interceptores de seguridad y proveer la respuesta HTTP correspondiente. SecurityContextPersistenceFilter, responsable de guardar el contexto de seguridad entre peticiones. Básicamente el contexto de seguridad es guardado a nivel de sesión. Como vemos en la figura, existen numerosos interceptores en la cadena. Toda la cadena de filtros es creada y aislada del programador mediante el uso de namespace. Sin embargo, es posible modificar y extender la cadena de filtros. Autorización en Spring Security El siguiente diagrama de clases define la arquitectura del módulo de autorización en Spring Security: En el centro del diagrama tenemos la clase abstracta AbstractSecurityInterceptor, ésta representa las capacidades de autorización básicas. Se pueden securizar peticiones HTTP gracias a FilterSecurityInterceptor e invocaciones a métodos gracias a MethodSecurityInterceptor y AspectJSecurityInterceptor. Este interceptor delega en el interfaz AccesDecisionManager la decisión de la autorización final. Este interfaz implementa un método decide que básicamente lo que hace es recibir un objeto Authentication representando al principal que accede a la petición, un objeto seguro (url o método) y una lista de aributos con metadatos de seguridad (la lista de roles para los que se les puede dar acceso). El siguiente diseño es el definido para el componente AccesDecisionManager: El diagrama representa el sistema de autorización de Spring Security. Este sistema está basado en un sistema de votos. Spring Security tiene tres implementaciones de AccessDecissionManager: AffirmativeBased, en el caso de recibir un único voto positivo, se le da acceso al recurso. Se permite controlar el comportamiento en el caso que todos los votos son de abstención. ConsensusBased, en este caso será necesario que haya más votos positivos que negativos para dar acceso al recurso protegido. También se puede controlar el comportamiento si todos los votos son abstención. UnanimousBased, en este caso será necesario que todos los votos sean positivos para dar acceso al recurso. Se permite controlar el comportamiento en el caso que todos los votos son de abstención. Los objetos AccessDecissionManager hacen uso de AccessDecissionVoter, actualmente Spring proporciona dos clases de este objeto: RoleVoter, comprueba cada rol que protege el recurso comprobándolo con el principal que realiza la petición. Si se tiene uno de los roles devolverá un AffirmativeBased AccessDecissionManger, así con uno bastará para dar acceso. AuthenticatedVoter, Este componente permite diferenciar entre acceso anónimo, completamente autenticado o autenticado mediante remember-me. Así podrá acceder a páginas que necesitan tener un comportamiento diferente para usuarios autenticados de los que no. Todos los componentes del módulo de autorización de Spring Security permiten ser extendidos para proveer mecanismos de autorización específicos o más profundos. Seguridad de la capa de servicio Spring Security permite securizar invocaciones a métodos, comúnmente llamado seguridad a nivel de capa de servicio. Esto permitirá que tengamos mecanismos de autorización de invocaciones de componentes de la capa de servicio aportando mayor seguridad. Spring otorga cuatro configuraciones para la seguridad en la capa de servicio, configuración a nivel global mediante namespace, mediante el componente MethdoSecurityInterceptor, basada en anotaciones o a nivel de bean. En Spring podemos observar cuatro maneras de securizar las ejecuciones de métodos dentro de Spring Security, Configuración de seguridad a nivel global usando namespace, a nivel de bean, usando el componente MethodSecurityInterceptor y basada en anotaciones. Configuración de seguridad a nivel global (namespace) Spring Security permite una configuración de seguridad a nivel global, esta opción es 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 ---TODO--- com.mycompany ---END TODO--- que acaben por service e independientemente del número de parámetros que tenga el método. Seguridad a nivel de bean Con el objeto MethodSecurityInterceptor Seguridad a nivel de anotación