Banco de Dados

6 mai, 2010

Segurança com Spring Security 3.0 utilizando banco de dados

Publicidade

Este artigo é o segundo, de uma série, que falaremos sobre segurança
em aplicações Java, continuando com o Spring Security. Dúvidas e
críticas são bem-vindas.

Aplicações comerciais sempre necessitam de acesso ao banco de dados. Então, por que seria diferente criar uma segurança sem estar com as
informações contidas no banco de dados?

No artigo
anterior
tivemos uma introdução de como usar o Spring Security
utilizando as configurações somente no XML. Neste artigo veremos como
criar a segurança utilizando o Spring Security e o banco de dados.

Preparando o banco de dados do exemplo

O banco de dados utilizado será o MySQL.
Você pode baixar a versão 5.1, utilizada no artigo, aqui.

Abra o terminal do MySQL com seu usuário e senha ROOT (aquela que
você configurou na instalação).

Crie o banco de dados e a tabela executando os seguintes comandos:

create database security;

use security;

CREATE TABLE users

(

username VARCHAR(15) NOT NULL,

password VARCHAR(40),

authority VARCHAR(15),

PRIMARY KEY (username)

);

Insira um usuário assim:

INSERT INTO users  VALUES('edson','integrator','ROLE_ADMIN');

Podemos baixar o MySQL
clicando aqui
, além da versão atual do driver JDBC, chamado de Connector/J
5.1
. Baixe os arquivos, instale o MySQL, caso não o tenha em sua
máquina e descompacte o arquivo JAR, do qual iremos
precisar, que será:

mysql-connector-java-5.1.10-bin.jar

O projeto

Pegue o projeto criado no artigo
anterior
, adicione a biblioteca JDBC do MySQL e também a biblioteca
JAR do Spring Framework:

org.springframework.jdbc-3.0.0.RELEASE.jar

O arquivo de configurações do Spring

No arquivo de configurações do Spring, altere como
mostrado na Listagem 1 a seguir:

Listagem 1 O arquivo
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http auto-config="true" >
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=invalido"/>
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT username, password, 'true' as enable FROM users WHERE username=?"
authorities-by-username-query="SELECT username, authority FROM users WHERE username=?"
/>
</authentication-provider>
</authentication-manager>
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<beans:property name="url" value="jdbc:mysql://localhost:3306/security" />
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="username" value="root" />
<beans:property name="password" value="integrator" />
</beans:bean>
</beans:beans>

A mudança feita no arquivo applicationContext.xml,
visto na Listagem 1, com relação ao artigo
anterior
, está na forma como vamos acessar o usuário,
senha e seu role. Alteramos o antigo elemento <user-service
/>
por <jdbc-user-service />.

Em <jdbc-user-service />,
temos TRÊS atributos importantes: users-by-username-query
e authorities-by-username-query e data-source-ref.
O primeiro atributo possui uma query que deve buscar três informações: username,
password e um valor booleano chamado enable.
A tabela criada no banco de dados, vista na Figura 1,
possui três campos (username, password e
authority
), mas não possui enable. Portanto, a
query deve simular este campo, informando que todos os cadastrados na
tabela estão habilitados:

SELECT username,
password, ‘true’ as enable FROM users WHERE username=?

Observe também que há uma condição WHERE na
cláusula SQL, para que o usuário seja filtrado no login e para que o
Spring Security se encarregue do resto, analisando se o usuário
transmitido e sua senha são similares ao existente no banco de dados.

Além de verificar se o usuário existe, o Spring
Security precisa saber se ele possui autorização para acessar
determinado local. O role, no caso, foi adicionado no terceiro campo da
tabela users, chamado de authority. O atributo authorities-by-username-query,
portanto, recebe uma query onde existe o usuário e seu role, sempre
filtrando pelo usuário:

SELECT username,
authority FROM users WHERE username=?

Atenção:
A query utilizada para o spring security precisa retornar os seguintes
nomes de colunas: username, password, enable
e authority.

No atributo data-source-ref
indicamos o data source necessário para se conectar ao banco de dados.

A conexão é feita pelo elemento <beans/>
no qual a classe utilizada é a org.springframework.jdbc.datasource.DriverManagerDataSource,
responsável por fazer a conexão com o banco de dados.

Logout, acesso negado e criptografia da senha

Depois de concluído o acesso à área restrita, temos
que efetuar o logout quando não interessa mais estar naquela área.

Também precisamos definir o que será apresentado
aos usuários que não possuem acesso a uma determinada área.

  • Logout

Para fazer o logout de uma área restrita,
utilizamos o padrão para fazer isso, que é: /j_spring_security_logout.
Sua utilização será no arquivo /admin/index.jsp,
como por exemplo a adição de um link, como na Listagem 2.

Listagem 2 Adição do link para
efetuar logout da área restrita

<html>
...
<body>
<h2>Parabéns, você está logado!</h2>
<hr />
Faça logout <a href="../j_spring_security_logout">clicando aqui</a>.
</body>
</html>
  • Página com a mensagem de acesso negado

Caso tenhamos um usuário cadastrado válido, que não
possui permissão de acesso a uma determinada área, vemos uma página
padrão, como de costume, exibida pelo servidor.

Figura 3
Acesso negado a um usuário que não tem permissão a esta área

Para modificar essa página, podemos criar uma que será exibida em seu lugar, informando o usuário da falta de
permissão de acesso.

Sua configuração depois será no elemento <http
/>
, do arquivo applicationContext.xml, com
o atributo access-denied-page. Abaixo vemos a página negado.jsp
como sendo a responsável por exibir uma mensagem personalizada, caso o
usuário entre em uma área não permitida.

<http auto-config="true" access-denied-page="/negado.jsp">
...
</http>
  • Criptografia de senha

O padrão para as senhas é de texto plano, como já
sabem. Entretanto, o Spring Security permite ler informações
criptografadas. Digamos que, na tabela de usuários,
tenhamos as senhas criptografadas em MD5. Teríamos que informar isso nas
configurações do Spring Security da seguinte forma:

<authentication-manager>
<authentication-provider>
<password-encoder hash="md5" />

</authentication-provider>
</authentication-manager>

Nota:
No MySQL podemos adicionar uma string em MD5 simplesmente utilizando a
função de mesmo nome:

INSERT INTO users VALUES(‘usuario’,
MD5(‘senha’),’ROLE_’)

Até a próxima!