Ejemplo básico de autenticación contra BBDD usando Spring Security (parte II)

Continuo con la segunda parte del ejemplo comenzado ayer.

Una vez conseguida la auntenticación contra un usuario cargado en memoria por Acegi el siguiente paso sería preparar la infraestructura de base de datos contra la que se va a realizar la nueva comprobación de credenciales. Como mínimo la base de datos ha de almacenar, como es lógico, el nombre de usuario y la password de cada uno de los usuarios. Además, cada uno de ellos ha de tener un perfil asociado para en función de este y de las reglas del filtro se permita o no el acceso a determinados paths.

Desde la página oficial de Spring Security nos sugieren este modelo de BBDD (para la autenticacion basta con la tabla users y authorities):

El script de creación de la BBDD se puede encontrar en la página de Spring Security pero es una implementación para Hypersonic. Yo voy a usar MySQL así que para este ejemplo ejecutaré este otro script sacado del foro de Spring:

DROP TABLE IF EXISTS contacts;
DROP TABLE IF EXISTS authorities;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS acl_permission;
DROP TABLE IF EXISTS acl_object_identity;

CREATE TABLE users (
	username varchar(50) NOT NULL,
	password varchar(50) NOT NULL,
	enabled bool NOT NULL,
	
	constraint PK_Username primary key (username)
) ENGINE=InnoDB;


CREATE TABLE authorities (
	username varchar(50) NOT NULL,
	authority varchar(50) NOT NULL,
	
	constraint FK_Username foreign key (username) references users(username),
	constraint IX_AuthUsername unique key (username, authority)
) ENGINE=InnoDB;
        

CREATE TABLE acl_object_identity (
  	id int NOT NULL auto_increment,
  	object_identity varchar(250) NOT NULL,
  	parent_object int,
  	acl_class varchar(250) NOT NULL,
  	
  	index (parent_object),
  	
  	constraint PK_Id primary key (id),
	constraint FK_ParentObject foreign key (parent_object) references acl_object_identity(id)

) ENGINE=InnoDB;


CREATE TABLE acl_permission (
  	id int NOT NULL auto_increment,
  	acl_object_identity int NOT NULL,
  	recipient varchar(100) NOT NULL,
  	mask int NOT NULL,
  	
  	constraint PK_Id primary key (id),
	constraint FK_ACLIdentity foreign key (acl_object_identity) references acl_object_identity(id),
	constraint IX_URecipient unique key (acl_object_identity, recipient)

) ENGINE=InnoDB;

INSERT INTO users VALUES('pepe','pepe',1);

INSERT INTO authorities VALUES('pepe','ROLE_ADMINISTRADOR);

Creo la BBDD y ejecuto el script. Ahora hay que definir un datasource usando Spring. Para ello creo (por separar conceptos) un nuevo fichero de contexto que llamo applicationContext-acegi-security.xml y lo coloco en el raíz de la carpeta WEB-INF.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
        <property name="location"><value>classpath:/databaseMySQL.properties</value></property>    
    </bean>
    
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName"><value>${driver}</value></property>
		<property name="url"><value>${url}</value></property>
		<property name="username"><value>${username}</value></property>
		<property name="password"><value>${password}</value></property>
		<property name="defaultReadOnly"><value>${defaultReadOnly}</value></property>				
		<property name="maxActive"><value>${maxActive}</value></property>
		<property name="maxWait"><value>${maxWait}</value></property>
		<property name="validationQuery"><value>${validationQuery}</value></property>
	</bean>	

</beans>

Una vez creado se referencia añadiéndolo al parámetro de contexto contextConfigLocation en el web.xml que quedaría así:

<context-param>
		<param-name>contextConfigLocation</param-name>

		<param-value>
			/WEB-INF/applicationContext-acegi-security.xml /WEB-INF/applicationContext-acegi-datasource.xml
		</param-value>
	</context-param>

El jar de Commons BDCP se puede descargar href=”http://commons.apache.org/downloads/download_dbcp.cgi”>aquí. También hace falta el Commons Pool. Por supuesto también es necesario añadir el driver JDBC de MySQL al directorio de librerias.

También hay que crear el fichero .properties del que obtiene los parámetros: databaseMySQL.properties.

driver=com.mysql.jdbc.Driver
username=*****
password=*****
url=jdbc:mysql://localhost:3306/pruebas
initialSize=5
maxActive=5
maxWait=500
maxIdle=3
minIdle=1
validationQuery=SELECT 'ok' from dual
testOnBorrow=true
defaultReadOnly=false

El siguiente paso es añadir el siguiente fragmento de código al fichero applicationContext-acegi-security.xml. En el se hace referencia al datasource creado previamente y se pasan dos parámetros clave para la autenticación:

  • usersByUsernameQuery: SQL para obtener los datos del usuario. Lo que espera obtener Acegi es el username la password y si el usuario es enabled o no (los as)
  • authoritiesByUsernameQuery:SQL para obtener el ROL del usuario obtenido de la query del parámetro usersByUsernameQuery
<bean id="authenticationDao"
	      class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
		<property name="dataSource">
			<ref bean="dataSource"/>
		</property>
		
	<property name="usersByUsernameQuery">
			<value>select USERNAME as username, PASSWORD as password, ENABLED as enabled FROM users WHERE username =? </value>
			</property>
		<property name="authoritiesByUsernameQuery">
		<value>select USERNAME as username, authority as rolename FROM authorities WHERE username =? </value>
		</property>
	</bean>

Y ya está. Ya se puede probar. Tan sólo quedan un par de detalles por zanjar: la encriptación de la password.

Añadir la propiedad passwordEncoder a el bean daoAuthenticationProvider:

    	<property name="passwordEncoder">
      		<ref bean="passwordEncoder" />
    	</property>

y el correspondiente bean, en este caso utilizado Md5 como algoritmo de encriptación:

<bean id="passwordEncoder"
   		class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

Aquí se puede encontrar el javadoc del paquete encoding.

—- Actualización: (18 Agosto de 2008)

La información del usuario logueado se guarda en el atributo de sesión ACEGI_SECURITY_CONTEXT. A partir de este atributo se puede obtener el login del usuario. Yo, lo que hago normalmente en una aplicación real, es sustituir lo que en el ejemplo he llamado EstoyDentro.do por un action, que a partir del login validado por Acegi, consulte el resto en BBDD (nombre, apellido, etc) y luego lo meta en sesión. Posteriormente hago un forward a donde corresponda.

Este es un snippet de como obtener el login:

SecurityContext contexto = 
(SecurityContext)request.getSession().getAttribute("ACEGI_SECURITY_CONTEXT");

String login = ((org.acegisecurity.userdetails.User)
							(context.getAuthentication().getPrincipal())).getUsername();

Y esto es todo amigos… próximamente en Hermosodía:

  • Ejemplo de TestNG
  • Histórico de BBDD

14 Responses to “Ejemplo básico de autenticación contra BBDD usando Spring Security (parte II)”


  1. 1 Vk agosto 18, 2008 a las 14:38

    Hola figura!

    Muy bueno el artículo!

    ¿Sabes cómo se puede recuperar, una vez logueado, la información del usuario?

    Por ejemplo:

    Recuperar el nombre del usuario (u otro campo que recupere de la base de datos con la query de usuarios.

    Gracias. Un saludo

  2. 2 LeChuckNorris agosto 18, 2008 a las 22:21

    @Vk: Espero que te haya sido útil. He actualizado la entrada con la respuesta a tu pregunta.

  3. 3 juan agosto 29, 2008 a las 14:36

    Hola, vas a hacer uno con una autenticación contra LDAP usando Spring Security???

  4. 4 juan septiembre 17, 2008 a las 13:06

    Podias contestar aunque sea para decir que NO lo vas a hacer

  5. 5 LeChuckNorris septiembre 17, 2008 a las 14:38

    @Juan: Siento no haberte respondido antes. Leí tu comentario pero no tuve tiempo en ese momento de responderte y se me ha pasado. Estos días ando un poco liado… estoy ultimando un proyecto y en paralelo me están metiendo caña con el arranque de otro que, para variar va con retraso. Normalmente escribo los tutoriales a medida que voy desarrollando o dando algún curso de formación y así mato dos pájaros de un tiro. La tercera parte sería lo que comentas… autenticarse contra un LDAP y posiblemente debería haber una cuarta de autenticación mediante un certificado digital… pero al menos hasta dentro de un mes no podré ponerme con ello. Supongo que ya será tarde para ti, pero ya te digo que ahora me es imposible.

    Un saludo.

  6. 6 durdy noviembre 14, 2008 a las 15:38

    Me interesaría muchisimo que publicases ese articulo de Spring Security para certificados digitales por favor cuando puedas. Sigo bastante tu blog me parece muy bien documentado y de mucho conocimiento.
    Gracias.

  7. 7 jotadeveloper noviembre 20, 2008 a las 07:11

    Bueno, en respuesta a Juan, desde mi blog, interesado en LDAP con Spring Security 2.0.

    http://blog.jotadeveloper.com/2008/11/17/configuracion-spring-security-204-para-ldap/

    pd: quiero una de Spring Security 2.0 con DAO.. alguien tiene algo ??

    Saludos.

  8. 8 Fernando enero 26, 2009 a las 20:58

    Hola, por favor estoy tratando de realizar lo de este curso pero tengo un problema me sigue autentificando con el dao de memoria no me coje los usuarios que puse en la base de datos alguien puede ayudarme

  9. 9 Edwin enero 26, 2009 a las 22:46

    Saludos, tengo ya todo realizado pero necesito el parametro de authorities es decir el role que desempeña, para poder distinguir si es administrador u otro rol puesto.

  10. 10 Victor Ruiz marzo 18, 2009 a las 14:26

    Hola,

    MUY BUENO el artículo, lo he seguido paso a paso y me ha funcionado a la perfección. Ahora ya tengo autenticación basado en una fuente de datos SQL.

    El motivo de este post no es el de elogiar únicamente, sino el de pedir en la medida de lo posible una referencia a un posible artículo complementario a este que realize la autorización basada en datos almacenados en base de datos…

    Gracias!

  11. 11 Mauricio Jovel abril 8, 2009 a las 07:22

    Hola a todos:

    Antes que nada muy buen ejemplo el que nos has dado y a sido de gran ayuda, pero fijate que para recuperar el usuario, la forma en como tu lo haces no me funciono, buscando entre otros blog y foros encontre está solución la cual comparto con ustedes por si tienen el mismo problema.

    Authentication contexto= SecurityContextHolder.getContext().getAuthentication();
    String login = ((User)(contexto.getPrincipal())).getUsername();

  12. 12 Manuel Flores diciembre 8, 2009 a las 16:12

    Disculpe podria subir el codigo de su aplicacion en un archivo war o algo por el estilo? Es que estamos desarrollando este tutorial en el colegio pero no logramos hacer que corra.
    De antemano gracias.


  1. 1 Ejemplo básico de autenticación contra BBDD usando Spring Security (parte I) « Hermoso día… Trackback en agosto 15, 2008 a las 08:09
  2. 2 Today on the presidential campaign trail (AP) · Trackback en agosto 15, 2008 a las 20:12

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s




Add to Technorati Favorites
Clicky Web Analytics Clicky

Flickr Photos

Aljibe

luz

C1

C1

Más fotos

A %d blogueros les gusta esto: