Mostrando las entradas con la etiqueta spring security. Mostrar todas las entradas
Mostrando las entradas con la etiqueta spring security. Mostrar todas las entradas

martes, 10 de agosto de 2010

Spring Security Mediante Base de Datos

En el post anterior les mostré como implementar spring security de la manera más básica, ahora continuaremos pero esta vez ya no obtendremos los usuarios desde XML como en:














Ahora vamos a obtener los usuarios desde un archivo de propiedades, para eso el XML anterior se reduce a:










Ojo que el archivo de propiedades lo podemos obtener desde el classpath de la aplicación(como en el ejemplo anterior)
o desde un archivo externo a la aplicación como en:









De esta manera podemos modificar el archivo de propiedades sin desempaquetar el EAR o WAR de la aplicación


El archivo de propiedades que contiene a los usuarios es bien simple, le especificamos el usuario, password, los roles o perfiles y si está habilitado o no:


#usuario=password,rol1[,rolN][,enabled|disabled]
ccacique1=pass1,PERFIL_ADMINISTRADOR,disabled
ccacique2=pass2,PERFIL_SUPERVISOR,enabled
ccacique3=pass3,PERFIL_ADMINISTRADOR,PERFIL_SUPERVISOR,enabled


La gestión de usuarios mediante archivos(sea en XML o en properties) no es apropiado en un entorno de producción donde pueden interactuar cientos o miles de usuarios, por lo que spring security nos proporciona una manera de obtener dichos usuarios desde la base de datos:


Para implementar la gestión de usuarios mediante una base de datos con spring security debemos de hacer lo siguiente:


  1. Implementar un proveedor de usuarios.

  2. El proveedor de usuarios debe de implementar la interface org.springframework.security.core.userdetails.UserDetailsService

  3. La interface anterior obliga a definir el método public UserDetails loadUserByUsername(String username), por lo que debemos de implementarlo

  4. El método anterior retorna un objeto de la clase org.springframework.security.core.userdetails.UserDetails, esta clase define campos de autenticación de usuarios simple como nombre de usuario, password, si el usuario está bloqueado y los perfiles asociados a este usuario.

  5. Colocar la referencia al proveedor de usuarios en donde usuarioService es mi proveedor de usuarios



Veamos la implementación del gestor de usuarios:



package pe.com.slcsccy.pc.springsecurity.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import pe.com.slcsccy.pc.springsecurity.dao.UsuarioDAO;
import pe.com.slcsccy.pc.springsecurity.model.Usuario;

@Service("usuarioService")
public class UsuarioServiceImpl implements UserDetailsService{
@Autowired
private UsuarioDAO usuarioDAO;

@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
Usuario usuario = null;
List usuarios = usuarioDAO.buscarUsuarioPorCodigo(username);
if(usuarios.size()==0)throw new UsernameNotFoundException("Usuario no existe.");
else{
usuario = usuarios.get(0);
usuario.setPerfiles(usuarioDAO.buscarPerfilesDeUsuarioPorCodigo(username));
return usuario;
}
}
}


El proveedor de usuarios hace uso de un objeto de acceso a datos, que lo he implementado con spring jdbc:


package pe.com.slcsccy.pc.springsecurity.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.GrantedAuthority;

import pe.com.slcsccy.pc.springsecurity.model.Perfil;
import pe.com.slcsccy.pc.springsecurity.model.Usuario;

public class UsuarioDAOImpl implements UsuarioDAO {

private JdbcTemplate jdbcTemplate;

public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

@SuppressWarnings("unchecked")
@Override
public List buscarUsuarioPorCodigo(String codigo) {
return jdbcTemplate.query("select * from usuario where cod_usuario = ? ", new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Usuario usuario = new Usuario();
usuario.setUsername(rs.getString("cod_usuario"));
usuario.setPassword(rs.getString("des_password"));
usuario.setAccountNonExpired(rs.getString("in_cuenta_expirada").equals("N")?true:false);
usuario.setAccountNonLocked(rs.getString("in_cuenta_bloqueada").equals("N")?true:false);
usuario.setCredentialsNonExpired(rs.getString("in_credencial_expirada").equals("N")?true:false);
usuario.setEnabled(rs.getString("in_habilitado").equals("S")?true:false);
return usuario;
}
},codigo);
}

@SuppressWarnings("unchecked")
@Override
public List buscarPerfilesDeUsuarioPorCodigo(String codigo) {
return jdbcTemplate.query("select cod_perfil from usuario_perfil where cod_usuario = ? ", new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Perfil perfil = new Perfil();
perfil.setNombrePerfil(rs.getString("cod_perfil"));
return perfil;
}
},codigo);
}
}


El acceso a los datos se realiza mediante un modelo de dominio de usuarios y de perfiles siguiente:

Usuario.java


package pe.com.slcsccy.pc.springsecurity.model;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class Usuario implements UserDetails{

private static final long serialVersionUID = -4993799715730712001L;

private List perfiles;
private String username;
private String password;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;

public Collection getPerfiles() {
return perfiles;
}

@SuppressWarnings("unchecked")
public void setPerfiles(List perfiles) {
this.perfiles = (List) perfiles;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Collection getAuthorities() {
return perfiles;
}

}



Perfil.java


package pe.com.slcsccy.pc.springsecurity.model;
import org.springframework.security.core.GrantedAuthority;
public class Perfil implements GrantedAuthority{

private static final long serialVersionUID = 1L;
private String nombrePerfil;

public Perfil(){
}

public String getNombrePerfil() {
return nombrePerfil;
}

public void setNombrePerfil(String nombrePerfil) {
this.nombrePerfil = nombrePerfil;
}

@Override
public String getAuthority() {
return this.nombrePerfil;
}

}


El modelo de dominio y el objeto de acceso a datos colaboran entre sí para conectarse y dar soporte a los datos de una base de datos Oracle que tiene la siguiente estructura e información:


create user springsecurity identified by springsecurity account unlock;
grant resource,connect to springsecurity;

create table springsecurity.usuario(
cod_usuario varchar2(40) not null,
des_password varchar2(40) not null,
in_cuenta_expirada char(1) default 'N' not null ,
in_cuenta_bloqueada char(1) default 'N' not null ,
in_credencial_expirada char(1) default 'N' not null ,
in_habilitado char(1) default 'S' not null ,
primary key(cod_usuario)
);

create table springsecurity.perfil(
cod_perfil varchar2(40) not null,
des_perfil varchar2(40) not null,
primary key(cod_perfil)
);

create table springsecurity.usuario_perfil(
cod_usuario varchar2(40),
cod_perfil varchar2(40),
primary key(cod_usuario,cod_perfil),
foreign key(cod_usuario) references springsecurity.usuario(cod_usuario),
foreign key(cod_perfil) references springsecurity.perfil(cod_perfil)
);

insert into springsecurity.perfil values('PERFIL_ADMINISTRADOR','PERFIL DE ADMINISTRADOR');
insert into springsecurity.perfil values('PERFIL_SUPERVISOR','PERFIL DE SUPERVISOR');
insert into springsecurity.usuario(cod_usuario,des_password) values('ccacique1','pass1');
insert into springsecurity.usuario(cod_usuario,des_password) values('ccacique2','pass2');
insert into springsecurity.usuario(cod_usuario,des_password) values('ccacique3','pass3');
insert into springsecurity.usuario(cod_usuario,des_password) values('ccacique4','pass4');
insert into springsecurity.usuario_perfil(cod_usuario,cod_perfil) values('ccacique1','PERFIL_ADMINISTRADOR');
insert into springsecurity.usuario_perfil(cod_usuario,cod_perfil) values('ccacique2','PERFIL_SUPERVISOR');



Con la estructura anterior ya podemos gestionar nuestros usuarios con soporte de spring security.


El contenedor de beans de spring security quedaría de la siguiente manera:



xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">


access-decision-manager-ref="accessDecisionManager">







login-page="/login.jsp"
default-target-url="/public/mostrarFormulario.htm"
authentication-failure-url="/loginerror.jsp"/>





invalidate-session="true"
logout-url="/public/terminarSesion.htm"
logout-success-url="/logout.jsp" />













































El proyecto completo te lo puedes bajar desde AQUI

sábado, 7 de agosto de 2010

Spring Security Mediante XML

Hola que tal, ahora les voy a presentar una pequeña implementación de spring security, el caso de uso a implementar es el siguiente:

Permitir que la aplicación calculadora(formulario simple de ingreso de operandos y selección de operación) sea accedida mediante usuarios que previamente se han autenticado o que tambien sea accedida en forma anónima al seleccionar una lista de opciones.

1. Lo primero que tenemos que hacer es configurar un filtro en el descriptor de despliegue de nuestra aplicación web de la siguiente manera:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">



calculadora-controller
org.springframework.web.servlet.DispatcherServlet
1




calculadora-controller
*.htm





springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy




springSecurityFilterChain
/*




org.springframework.web.context.ContextLoaderListener




contextConfigLocation

/WEB-INF/calculadora-security.xml





index.jsp




403
/sinacceso.jsp






2. Ahora vamos a configurar los beans que conforman el controller de la aplicación, mediante anotaciones. El flujo de control de la aplicación es simple: define un archivo de inicio index.jsp que redirecciona hacia /public/iniciar.htm está ruta será interceptada por el filtro de spring security y como la URL es pública no necesitará de una autenticación, después llegará hacia el controller: @Controller public class CalculadoraController {...} que ha mapeado la URL solicitada y la redirigirá hacia la página jsp opciones.jsp. En la página de opciones es donde se prueba la seguridad implementanda mediante spring, en esta página listo 5 opciones de acceso(todas me conducen al formulario de la calculadora), la primera opción accesa al formulario en forma anónima, las 4 siguientes requieren una autenticación, si el usuario aún no se a autenticado es redirigido hacia login.jsp para que se autentique, si el usuario ingresa sus credenciales(usuario y passwords) y genera un error entonces es redirigido hacia loginerror.jsp, si el usuario se autentica satisfactoriamente pero no tiene permiso entonces generará un error 403(acceso denegado, el cual es definido en el descriptor de despliegue)



xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">





p:basename="mensajes"/>

p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>






3. Ahora lo más importante, la definición del contexto de seguridad mediante spring:



xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">


access-decision-manager-ref="accessDecisionManager">







login-page="/login.jsp"
default-target-url="/public/mostrarFormulario.htm"
authentication-failure-url="/loginerror.jsp"/>





invalidate-session="true"
logout-url="/public/terminarSesion.htm"
logout-success-url="/logout.jsp" />










































El proyecto completo te lo puedes bajar desde AQUI

miércoles, 29 de julio de 2009

¿Qué es Spring Security?

Spring Security proporciona servicios de seguridad para aplicaciones de software empresariales basados en J2EE, enfocado particularmente sobre proyectos construidos usando SpringFramework, si ya estas familiarizado con Spring(y particularmente con los principios de inyección de dependencias) será más rápido aprender Spring Security.

Como sabemos la seguridad comprende dos operaciones: La primera operación es conocida como "autenticación", por el cual se establece si un usuario(que quiere realizar una acción en nuestra aplicación) es quien dice ser, y la segunda operación es llamada "autorización" que se refiere al proceso de decidir si a un usuario le es permitido realizar una determinada acción en nuestra aplicación.

Para llegar al punto donde una acción de autorización es necesaria, la identidad del usuario ya ha sido establecida por el proceso de "autenticación", estos conceptos son comunes y no todos son especificos a Spring Security.

En el nivel de "autenticación" Spring Security soporta muchos modelos de autenticación, muchos de estos modelos de autenticación son proporcionados por terceros o son desarrollados por estandares importantes como el IETF(Internet Engineering tTask Force), adicionalmente, Spring Security proporciona su propio conjunto de caracteristicas de autenticación.

Especificamente, Spring Security actualmente soporta integración de autenticación con todas las siguientes tecnologías:

  1. HTTP BASIC authentication headers (an IEFT RFC-based standard).
  2. HTTP Digest authentication headers (an IEFT RFC-based standard).
  3. HTTP X.509 client certificate exchange (an IEFT RFC-based standard).
  4. LDAP (un enfoque muy comun para necesidades de autenticación multiplataforma, especificamente en entornos extensos).
  5. Form-based authentication (necesario para interfaces de usuario simples).
  6. OpenID authentication.
  7. Computer Associates Siteminder.
  8. JA-SIG Central Authentication Service.
  9. Transparent authentication context propagation for Remote Method Invocation (RMI) and HttpInvoker.
  10. Automatic "remember-me" authentication.
  11. Anonymous authentication.
  12. Run-as authentication.
  13. Java Authentication and Authorization Service (JAAS)
  14. Container integration with JBoss, Jetty, Resin and Tomcat (tambien podemos usar autenticación gestionada por el contenedor)
  15. Java Open Source Single Sign On (JOSSO) *
  16. OpenNMS Network Management Platform *
  17. AppFuse *
  18. AndroMDA *
  19. Mule ESB *
  20. Direct Web Request (DWR) *
  21. Grails *
  22. Tapestry *
  23. JTrac *
  24. Jasypt *
  25. Roller *
  26. Elastic Plath *
  27. Atlassian Crowd *
  28. Nuestros propios sistemas de autenticación.
(* Indica proporcionado por un tercero)


Muchos proveedores de software independientes adoptan Spring Security porque tiene modelos flexibles de autenticación, haciendolo les permite rápidamente integrar sus soluciones con cualquier necesidad de su cliente sin emprender un conjunto de ingenierias o requerir al cliente cambiar su entorno.

Si ninguno de los mecanismos de autenticación satisface tus necesidades, Spring Security es una plataforma abierta y además es bastante simple como para poder escribir nuestros propios mecanismos de autenticación, muchos usuarios corporativos de Spring Security necesitan integrarse con sistemas legados que no siguen ningún estandar particular de seguridad por lo que Spring Security se integra fácilmente a estos sistemas

A veces el simple proceso de autenticación no es suficiente. A veces necesitamos tambien diferenciar la seguridad basada en como el usuario interactua con nuestra aplicación, por ejemplo, podríamos querer asegurarnos que las solicitudes solo lleguen a través de https, esto para proteger passwords de terceros que puedan interceptarlo. O tambien podriamos querer asegurarnos que una persona es quien está realizando las solicitudes y no un "robot" o otro proceso automatizado.

Esto es especialmente util para proteger el proceso de recuperación de passwords de ataques de fuerza bruta, o simplemente para hacer más difícil a las personas duplicar el contenido clave de nuestra aplicación. Para ayudar a realizar estas metas, Spring Security soporta completamente "canales de seguridad" automáticos integrandose con JCaptcha para detección de usuarios humanos.

Independientemente de como la autenticación fué realizada, Spring Security proporciona un cunjunto amplio de capacidades de autorización. Existen tres áreas principales de interés respecto a la autorización, que son; autorización basado en solicitudes web, autorización basada en que métodos pueden ser invocados y autorización de acceso a instancias de objetos que pertenecen a un dominio individual, para entender mejor las diferencias considera las capacidades de autorización encontradas en la especificación Servlet del patrón de Seguridad Web, seguridad EJB gestionada por el contenedor y la seguridad de los sistemas de archivos respectivamente.