Spring Security
Spring Security
BDI
Andrés Guzmán F.
Formación BDI TI
Bolsadeideas.com
Spring Security
¿Qué es Spring
Security?
Autenticación
Configuración
Base de Datos
Form y login
Logout
básico
Temas
¿Porqué
Spring Security?
Problemas del API de
Spring security
Seguridad Java EE
Spring Security es un
subproyecto del framework
Spring, que permite gestionar
completamente la seguridad
de nuestras aplicaciones Java,
y cuyas ventajas principales
son las siguientes:
¿Qué es Spring Security?
La configuración de la seguridad es portable de un servidor a otro, ya
que se encuentra dentro del WAR o el EAR de nuestras aplicaciones
Spring Security
Autorización
Autenticación
(control de acceso)
Características Spring Security
LDAP
OpenID
Kerberos
Soporte en Spring Authorization
• Autorización en
peticiones web HTTP
Tres áreas
(HTTP Requests)
en las que
• Autorización cuando los
se puede
métodos son invocados
aplicar
• Autorización cuando se
autorización
accede a objetos del
dominio (instancias)
Configuración
Spring Security
Configurar web.xml
Provee una forma estándar para configurar Spring Security en
Aplicaciones Web Java EE
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml,
/WEB-INF/spring/applicationContext-security.xml
</param-value>
</context-param>
Configuración Mínima de
Seguridad <http>
Todo lo mínimo necesario para habilitar la
seguridad web (HTTP Request) es
configurar lo siguiente en el archivo de
configuración de contexto de Spring
Security (applicationContext-
security.xml)
<!-- Todas las URLs quedarán seguras, requiere el ROLE_USER para el acceso -->
<http auto-config='true'>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
</http>
Elemento <intercept-url>
El elemento <intercept-url> define un patrón el cual debe
coincidir contra las URLs proveniente del request utilizando una
sintaxis de path.
<http>
<form-login />
<logout />
</http>
• Representan el manejo de un
formulario de login (form-login) y
cierre de sesión (logout)
respectivamente
• Cada uno de ellos tienen atributos que
pueden utilizarse para personalizar su
comportamiento e implementación
<authentication-manager> &
<authentication-provider>
Podemos tener más de un elemento <authentication-
provider>para definir diferentes tipos u origen de
autenticación, cada uno se consultará por turno
<authentication-manager>
<authentication-provider>
<user-service>
<user name="andres" password=“andres" authorities="ROLE_USER,
ROLE_ADMIN" />
<user name="john" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<authentication-manager> &
<authentication-provider>
Para agregar usuarios, podemos definir un set de información
de ejemplo directamente en el namespace del xml
<authentication-manager>
<authentication-provider>
<user-service>
<user name="andres" password="andres" authorities="ROLE_USER,
ROLE_ADMIN" />
<user name="john" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
La configuración de arriba define dos usuarios guardados en memoria (In
Memory), con sus contraseñas y sus roles dentro de la aplicación (las
cuales serán usadas para el control de acceso).
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="andres" password="231badb19b93e44f47da1bd64a8147f2"
authorities="ROLE_USER, ROLE_ADMIN" />
<user name="john" password="81dc9bdb52d04dc20036dbd8313ed055"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Password Encoding SHA
Similar al ejemplo MD5, el valor del password puede ser
codificado usando algoritmo hash SHA en <password-
encoder>
<authentication-manager>
<authentication-provider>
<password-encoder hash="sha"/>
<user-service>
<user name="andres"
password="883768b6dd2c42aea0031b24be8a2da40fef4b64"
authorities="ROLE_USER, ROLE_ADMIN" />
<user name="john"
password="7110eda4d09e062aa5e4a390b0a572ac0d2c0220"
authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Concepto
de Role
¿Qué es un Role?
Un rol es un grupo o tipo de usuario que se le otorgan
ciertos privilegios para llevar a cabo una o varias
acciones dentro de una aplicación
<http auto-config="true">
<intercept-url pattern="/login*"
access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login"/>
</http>
Acceso a usuarios anónimos
o invitados
<http auto-config="true">
<intercept-url pattern="/login*"
access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login"/>
</http>
Omitir el Security Filter Chain
También es posible para toda
petición (request) que coincidan con
cierto patrón puedan saltarse
completamente el filtro de
seguridad de spring, por ejemplo
recursos estáticos como imagenes,
css, javascript etc:
<http auto-config='true'>
<intercept-url pattern="/css/**" filters="none" />
<intercept-url pattern="/login.jsp*" filters="none" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page='/login.jsp'/>
</http>
Múltiples elementos <http>
La vista mi_pagina_despues_login.jsp: :
<body>
<h3>Esto es la primera página justo después del login de inicio de
sesión
Todo el mundo después de iniciar sesión, verá esta página.
</h3>
<p><a href="index.jsp">volver al index.jsp</a></p>
<p><a href="logout">Logout</a></p>
</body>
Configurar Página Post-Login
También podemos configurar otras opciones de modo que el
usuario siempre terminará en la página post-login
(independientemente si el inicio de sesión fue "on-demand"
(implícito) o el usuario lo hizo explícitamente) estableciendo el
atributo always-use-default-target a "true" .
<http auto-config="true">
<intercept-url pattern="/miapp/admin*"
access="hasRole('ROLE_SUPERVISOR')" />
<intercept-url pattern="/miapp*" access="hasRole('ROLE_USER')" />
<form-login login-page="/mi_pagina_login"
default-target-url="/mi_pagina_despues_login"
always-use-default-target='true'
authentication-failure-url="/mi_pagina_error_login" />
<logout logout-success-url="/mi_pagina_logout" />
</http>
Configurar Página Error Login
También es posible indicar la pagina de error
del login si falla la autenticación:
<http auto-config="true">
<intercept-url pattern="/miapp/admin*"
access="hasRole('ROLE_SUPERVISOR')" />
<intercept-url pattern="/miapp*"
access="hasRole('ROLE_USER')" />
<form-login login-page="/mi_pagina_login"
default-target-url="/mi_pagina_despues_login"
always-use-default-target='true'
authentication-failure-url="/mi_pagina_error_login" />
<logout logout-success-url="/mi_pagina_logout" />
</http>
Configurar Página Error Login
Luego se define un controlador genérico
parametrizable con la vista o se implementa
uno completamente, ejemplo parametrizable:
<view-controller path="/mi_pagina_error_login" view-
name="mi_pagina_error_login"/>
La vista mi_pagina_error_login.jsp:
<body>
<h2>Esta es mi_pagina_error_login.jsp. Indica que el login ha
fallado. </h2>
<a href="index.jsp">Ir a index.jsp</a></p>
</body>
Página de acceso denegado 403
También es posible indicar la pagina de acceso
prohibido cuando el usuario no tiene los
permisos necesarios:
<http auto-config="true">
<access-denied-handler error-page="/mi_pagina_403" />
<intercept-url pattern="/miapp/admin*"
access="hasRole('ROLE_SUPERVISOR')" />
<intercept-url pattern="/miapp*"
access="hasRole('ROLE_USER')" />
<form-login login-page="/mi_pagina_login"
default-target-url="/mi_pagina_despues_login"
always-use-default-target='true'
authentication-failure-url="/mi_pagina_error_login" />
<logout logout-success-url="/mi_pagina_logout" />
</http>
Ejemplo Formulario Login Personalizado
<form name='f' action="${pageContext.request.contextPath}/login"
method='post'>
<table>
<tr>
<td>Usuario:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
<td colspan='2'>
<input name="submit" type="submit" value="submit" />
</td>
</tr>
</table>
</form>
Basic Login
HTTP BASIC authentication
Se refiere a un tipo de autenticación
mediante cabeceras http, es decir HTTP
Authorization con un sistema de
autenticación básica y una codificación
username/password simbólico:
HTTP BASIC authentication
Si queremos usar autenticación básica (HTTP
BASIC authentication) en vez de formulario
de login, cambiamos a la siguiente
configuración:
<http auto-config='true'>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<http-basic />
</http>
Proveedor de
Autenticación
Base de Datos
Proveedores de Autenticación
En la práctica necesitaremos proveedores
más escalables para el manejo y registro de
usuarios y sus credenciales, algo más
robusto que agregar la información de
usuarios en el XML de contexto Spring:
• Ejemplos de proveedores más robustos
Base de datos
LDAP
• Podemos usar múltiples <authentication-
provider>, los cuales son consultados en
el orden en que se listan
Base de datos como
Proveedor de Autenticación
En el ejemplo de abajo, "securityDataSource" corresponde
al nombre del bean DataSource definido en XML
root/application context de spring, que apunta a la base
de datos que contiene el esquema estándar de tablas de
spring security (users, authorities, groups etc):
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="securityDataSource"/>
</authentication-provider>
</authentication-manager>
Base de datos como
Proveedor de Autenticación
Ejemplo similar al anterior pero con un esquema de tablas
que NO es estándar de Spring y usando consulta
personalizadas de autenticación (de forma explícita) para
consultar a los usuarios y roles desde la base de datos:
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="securityDataSource"
users-by-username-query=
"select username,password, enabled from users where username=?"
authorities-by-username-query=
"select username, role from user_roles where username =? " />
</authentication-provider>
</authentication-manager>
Base de datos como
Proveedor de Autenticación
Alternativamente, podemos configurar un
bean JdbcDaoImpl, una clase DAO que viene
como parte de Spring Security (listo para usar)
usando el atributo user-service-ref:
<authentication-manager>
<authentication-provider user-service-ref='userDetailsService'/>
</authentication-manager>
<bean id="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
Implementar interface
UserDetailsService
También podemos implementar nuestra propia clase
UserDetailsService. En el ejemplo de abajo, miUserService
corresponde al nombre de un bean (en root/application context) el
cuál puede ser una clase personalizada DAO/Repository (o Service),
propia de nosotros, que implementa la interfaz de
UserDetailsService, por ejemplo con Hibernate, pero también se
puede hacer con JPA, JDBC o cualquier otra tecnología de
persistencia.
<authentication-manager>
<authentication-provider user-service-ref='miUserService'>
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
<authentication-manager>
<authentication-provider ref='miProveedorAutenticacion'/>
</authentication-manager>
<bean id="miProveedorAutenticacion"
class="com.formacionbdi.security.
provider.MiAuthenticationProvider">
</bean>
Esquema de
Spring Security
Base de Datos
Hay varios esquemas de base de datos usado por el
framework, pero aquí pretendemos proporcionar un único
punto de referencia para todos ellos
Esquema Login
Esquema de tablas del Esquema ACL
persistente
usuario (Autorización)
(Remember-me)
<http>
<intercept-url pattern="/secure/**"
access="hasRole('ROLE_USER')"
requires-channel="https"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"
requires-channel="any"/>
...
</http>
Protocolo de Seguridad HTTPS
<http>
...
<session-management invalid-session-url="/sesion-invalida.htm" />
</http>
Detectar Timeout
Hay que tener en cuenta que si usamos el mecanismo para
detectar session timeouts, puede reportar falsamente un error
si el usuario cierra la sesión y luego se vuelve a conectar sin
cerrar el navegador
<http>
...
<session-management invalid-session-url="/sesion-invalida.htm" />
<logout delete-cookies="JSESSIONID" />
</http>
Seguridad
en las vistas
Seguridad en las vistas
Spring Security permite implementar condicionales como
elementos taglib (etiquetas) para comprobar el acceso.
<sec:authorize access="hasRole('ROLE_USUARIO')">
<a href="carro/agregar.htm?id=${producto.id}">
agregar al carro</a>
</sec:authorize>
La anotación
@Secured
Anotación @Secured
Nuestras clases pueden ser restringida con la
anotación @Secured tanto a nivel de clase como
a nivel de método
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
GRACIAS!