Back-End

28 abr, 2010

Segurança passo a passo com Spring Security 3.0

Publicidade

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

Segurança de dados através do Spring Security

A segurança de áreas restritas em aplicações Web escritas em Java não
é uma tarefa das mais triviais. Sabendo que não era simples criar áreas de segurança, em 2003 surgiu o
Acegi Security System for Spring, um framework extremamente
configurável  e complexo. Comum na época, suas configurações eram
baseadas em XML e demorava um tempo para que o desenvolvedor o dominasse
completamente. O projeto Acegi evoluiu e, em 2007, foi incorporado aos projetos do
Spring Framework, sendo renomeado para Spring Security. A versão 2.0 foi lançada em 2008 e, em 2010, a versão 3.0, a que iremos
utilizar neste artigo.

Download do Framework

Para trabalhar com o Spring Security, você deve fazer o download aqui.
No momento em que este artigo é escrito, a versão utilizada é a Spring
Security 3.0.2.

Baixe a versão spring-security-3.0.2.RELEASE.zip. Ao
baixar, descompacte o arquivo extraindo todos os JARs existentes no
diretório lib.

Também será preciso baixar o Spring Framework. No momento em que este
artigo é escrito, a versão utilizada é a Spring Framework
3.0.2
.

Como o Spring Security trabalha

Da mesma forma que faríamos se estivéssemos utilizando JAAS, o Spring
Security trabalha a segurança através de declarações baseadas em papéis
(roles). Seja em XML ou Anotações, o Spring Security  não necessita
chamar método algum para realizar uma autenticação ou uma autorização.

Através dos roles definidos, podemos informar ao aplicativo em
questão, ao qual está sendo assegurada uma área, quais recursos podem
ser acessados ou restringidos a uma determinada pessoa que acessou a
área restrita.

Preparando o ambiente de trabalho

Para este artigo, iremos utilizar a IDE da Spring Source, divisão da VMware, criada sobre a plataforma Eclipse, chamada
de SpringSource Tools Suite.

Para baixar o SpringSource Tools Suite, clique
aqui
, preencha o formulário e faça o Download. Como a ferramenta
possui uma opção de instalador, use-a como facilitador se desejar. Na
própria página onde baixar o arquivo, haverá a explicação da instalação
em cada plataforma, em Installation Instructions.

Criando um projeto

No SpringSource Tools Suite, clique no menu File>New>Dynamic
Web Project
. Na caixa de diálogo New Dynamic Web
Project
, digite ProjSpringSecurity (ou o nome
que desejar) em Project name.

O SpringSource Tools Suite possui embutido um servidor de aplicações
Java Web baseado no Apache Tomcat 6, só que com algumas modificações.
Entretanto, vamos utilizar o Tomcat, que pode ser adicionado como mostro
neste
artigo
.

Confirme a criação do projeto no botão Finish.

Adicionando as bibliotecas ao Projeto

Com o botão direito do mouse sobre o projeto, na view Project
Explorer
, vá até Properties. Na caixa de
diálogo das propriedades do projeto, vá até Java EE Module
Dependencies
. Clique em Add External JARs e
adicione os seguintes arquivos:

  1. org.springframework.aop-3.0.2.RELEASE.jar
  2. org.springframework.asm-3.0.2.RELEASE.jar
  3. org.springframework.beans-3.0.2.RELEASE.jar
  4. org.springframework.context-3.0.2.RELEASE.jar
  5. org.springframework.core-3.0.2.RELEASE.jar
  6. org.springframework.expression-3.0.2.RELEASE.jar
  7. org.springframework.transaction-3.0.2.RELEASE.jar
  8. org.springframework.web-3.0.2.RELEASE.jar
  9. spring-security-config-3.0.2.RELEASE.jar
  10. spring-security-core-3.0.2.RELEASE.jar
  11. spring-security-taglibs-3.0.2.RELEASE.jar
  12. spring-security-web-3.0.2.RELEASE.jar
  13. commons-logging-1.1.1.jar

Note que o 13º item é um JAR que não pertence à família do Spring
Framework. Você pode baixar o arquivo compactado, contendo a biblioteca commons-logging-1.1.1.jar,
clicando aqui.

Uma aplicação simples com Spring Security

Para exemplificar como funciona o Spring Security, vamos criar uma
aplicação simples com apenas uma área segura. Essa área segura será
representada dentro de um diretório, chamado admin.

Teremos duas páginas index.jsp: uma na raiz do
aplicativo e outra dentro do diretório admin, como
mostra a figura abaixo:

As páginas do Projeto

As páginas JSP

A página index.jsp, existente dentro do diretório admin,
exibe apenas uma mensagem simples, com apenas HTML. O conteúdo é mostrado na Listagem 1.

Página index.jsp exibida após logar na área admin

Listagem 1 O conteúdo HTML da página /admin/index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Usuário Logado</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<h2>Parabéns, você está logado!</h2>
</body>
</html>

A página index.jsp encontrada na raiz exibe apenas
um link, que o leva até a área administrativa. Sua aparência é idêntica à figura abaixo. O conteúdo da página index.jsp, encontrada na raiz da
aplicação, é mostrado na Listagem 2.


Página index.jsp exibida quando acessada a aplicação

Listagem 2 O conteúdo HTML da página /index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Página Inicial</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<h2>Uma aplicação simples com Spring Security</h2>
<hr />
<a href="admin">Clique aqui para acessar a área administrativa</a>
</body>
</html>

Configurando o web.xml

Para o Spring Security, assim como o Spring, precisamos
configurar o web.xml. O Spring Security utiliza um filtro HTTP para
interceptar as URLs acessadas e verificar as permissões de acesso. A Listagem 3 exibe a configuração do arquivo web.xml.

Listagem 3 O arquivo web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>ProjSpringSecurity</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

Para configurar o Spring Security, utilizamos o filtro org.springframework.web.filter.DelegatingFilterProxy,
devidamente configurado na Listagem 3. O filtro está
sendo aplicado em todo o aplicativo, podendo ser visto no elemento <url-pattern
/>
.

Atenção: Um detalhe importante que precisa ser
notado é o nome do filtro, colocado no elemento <filter-name/>.
Não o altere, pois o Spring já espera pelo nome springSecurityFilterChain.

Configurando o applicationContext.xml

O Spring Security será configurado no arquivo applicationContext.xml.
Esse arquivo deverá ser criado dentro do diretório WEB-INF,
com o conteúdo mostrado na Listagem 4.

Listagem 4 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&nbsp;
http://www.springframework.org/schema/beans/spring-beans.xsd&nbsp;
http://www.springframework.org/schema/security&nbsp;
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http auto-config="true">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="edson" password="integrator" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>

No Spring Security as configurações de autenticação e autorização
estão sendo feitas no arquivo de contexto padrão do Spring (applicationContext.xml).
Para que esse arquivo seja lido, adicionamos no web.xml
o elemento <listener />, contendo o listener org.springframework.web.context.ContextLoaderListener.

O listener do Spring faz com que as configurações sejam carregadas na
inicialização da aplicação Web.

Ao ser carregado pelo listener, o arquivo da Listagem 4
declara os usuários e suas regras de acesso ao aplicativo.

O controle de acesso é feito pelo elemento <http />
do applicationContext.xml. Esse controle é definido no
sub-elemento <intercept-url />. O atributo pattern,
de <intercept-url /> informa, através de uma
expressão, em qual local o filtro deve agir, bem como define a sua regra
de acesso, através do atributo access.

Para que possamos definir que qualquer elemento dentro do diretório admin
fique acessível somente para os usuários do role ROLE_ADMIN,
adicionamos uma expressão comum no Apache Ant.

Caso tenhamos mais de um sub-elemento <intercept-url />,
teremos sua interpretação sendo feita por ordem de definição, sendo
que a primeira que atender a regra será chamada. Na prática, isso
significa que, se houver /admin/relatorios/** e /admin/**,
o primeiro caso deverá ser lido primeiro, portanto será o primeiro a
ser adicionado na ordem em  applicationContext.xml.

O atributo auto-config, com o valor true,
indica a configuração automática da aplicação para utilizar um
formulário de login. O JSP do formulário é gerado automaticamente pelo
Spring Security nesse caso. A figura a seguir exibe o
formulário gerado pelo Spring Security.


Formulário de login gerado automaticamente pelo Spring Security

Com o atributo <authentication-manager>,
gerenciamos os usuários e seus respectivos roles que darão permissão ao
diretório especificado anteriormente, em <intercept-url
/>
, pelo filtro.

Para facilitar a compreensão do exemplo, adicionamos apenas um
usuário, através de <user/>, informando o nome de
usuário, a senha e o seu papel de acesso. Ao logar no aplicativo, o Spring analisará qual role é permitido no
diretório e quem possui tal permissão.

Personalizando o formulário de acesso a área restrita

É interessante ter uma geração automática de formulário no Spring
Security, ajuda a testar a codificação, com certeza. Mas não é agradável
ao aplicativo como um todo, pois sempre precisamos criar o formulário
com as características gerais desenvolvidas no layout das páginas.

Criando a página personalizada de login

Para isso, o Spring Security nos fornece a personalização do
formulário. A Listagem 5 exibe o conteúdo da página /login.jsp
que ficará na raiz do seu aplicativo, junto com index.jsp.

Listagem 5 A página login.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Área Restrita</title>
</head>
<body>
<h2>Área Restrita</h2>
<hr />
<%
if(request.getParameter("error") != null){
if (request.getParameter("error").equals("invalido")){
%>
<p>
<span style="color:red">
Usuário ou Senha inválidos
</span>
</p>
<%
} //fim do if equals
}//fim do if null
%>
<form action="j_spring_security_check" method="post">
Usuário: <input value="${not empty login_error ? SPRING_SECURITY_LAST_USERNAME : ''}" />
<br />
Senha: <input><br />
<input type="submit" value="Efetuar Login"><br />
<a href="index.jsp">Retornar para a Página Inicial</a>
</form>
</body>
</html>

Para que o formulário funcione com o Spring Security, as regras mais
básicas são:

  • O atributo action deve apontar para j_spring_security_check;
  • O atributo name da caixa de entrada de  texto, do
    nome de usuário, deve ser j_username;
  • O atributo name da caixa de entrada de senha deve
    ser j_ password.

Esses princípios básicos farão com que seu formulário funcione com o
Spring Security. Entretanto, precisamos mostrar uma mensagem de erro,
caso o usuário não tenha colocado as informações necessárias ou as
mesmas não sejam compatíveis com o registrado no sistema para permitir a
entrada na área restrita.

É exatamente o papel do if(request.getParameter(“error”) e do
if (request.getParameter(“error”).equals(“invalido”)),
na página login.jsp, personalizado, com um parâmetro
que iremos transmitir, através do Spring Security, caso ocorra um erro
na permissão.

A página personalizada pode ser vista abaixo:


Formulário de acesso a área restrita personalizado

Alterando o arquivo applicationContext.xml

Por fim, mas não menos importante, precisamos alterar o arquivo applicationContext.xml
para que o Spring Security passe a trabalhar com a página de login
personalizada que criamos. A seguir você tem o trecho, contendo o
elemento <form-login/>, que deve ser inserido por
entre o elemento <http />:

<form-login login-page=“/login.jsp”
authentication-failure-url=“/login.jsp?error=invalido”/>

O elemento <form-login/> é de simples compreensão, pois temos
atributos que descrevem bem sua função:

login-page: A página personalizada com o formulário de substituição
do padrão existente no framework

authentication-failure-url: URL de retorno caso
ocorra um erro. Note que adicionamos,  após “?” , error=invalido.
Isso demonstra, claramente, que não é uma regra fixa o que pode ser
transmitido, caso ocorra um erro, na entrada de uma determinada área
restrita.


Resultado final do projeto com todos os arquivos criados

Embora tenhamos conhecido alguns elementos de utilização do
Spring Security, restou colocar o acesso ao banco de dados para fazer
uma autenticação verdadeira, como ocorre em sistemas. Em um outro artigo veremos como fazer para trabalhar com Spring
Security e o acesso ao banco de dados, com um exemplo completo, passo a
passo.

Até o próximo artigo, pessoALL.