* Visite o ALJUG - http://aljug.blogspot.com - Noticias sobre a comunidade java alagoana e do mundo * Visite o blog Mundo Gamificado www.mundogamificado.com.br - E vamos mudar o mundo! *

sexta-feira, 13 de novembro de 2009

Segurança de login em J2EE com Ajax

Artigo escrito por

Segurança em Java na plataforma web é baseada na separação dos conteúdos em dois contextos - protected e public. Mas há muitos casos (em minha experiência, na maioria dos casos) quando você oferece o mesmo conteúdo (por exemplo, uma página da web), mas com informações diferentes para tipos de usuários diferentes. Existe conteúdos para os usuários não-autenticados (os não registrados) aqueles que você esconde algumas informações confidenciais , e para usuários autenticado (registrados) os que podem optar por esconder alguns dados em função da sua autorização (função do usuário).


O formulário de segurança baseada em J2EE automaticamente protege a parte "seguro" da aplicação web. Que na realidade significa o contêiner J2EE que solicita automaticamente as credenciais do usuário quando o mesmo tenta acessar o contexto protegido. Contexto, aqui, significa uma pasta no servidor (algo como "seguro"), que é acessível por um caminho URL (algo como 'http://server.com/secure').
Mas, se você tiver apenas uma página ou duas (ou uma dúzia) que tornam-se diferente dependendo do tipo de usuário? Neste caso, você não tem nada que possa ser considerado um contexto seguro, porque você não pode separar-se fisicamente de conteúdo em duas partes, a menos que você deseja copiar todas as suas páginas para uma pasta "segura".


A dura verdade é que a única maneira de autenticar o contêiner J2EE (logs-in) é se um usuário estiver interceptando o acesso do usuário ao contexto protegido. Você simplesmente não pode manualmente pedir ao contêiner J2EE para registrar seus usuários, e apresentar um formulário para inserir suas credenciais. Esta situação é um problema de longa duração para todos os desenvolvedores J2EE.

Sob o capô, o formulário de segurança baseado em J2EE tem três entidades: primeiro é o login (página onde o usuário insere seu login e senha), e é quando o usuário tenta acessar o conteúdo protegido. Segundo é a página de erro ,aparece quando login e/ou senha digitada está incorreto, e os / j_security_check URL que está incorporado em qualquer contêiner J2EE. O último é capaz de receber login e senha a partir da página de login, validando-os e, após uma validação bem sucedida é redirecionado para a página que foi originalmente solicitado, ou, em caso de falha de validação, é redireciona o usuário para a página de erro,para dar-lhe outra tentativa.

A parte complicada é que / j_security_check URL não pode ser usado manualmente. Você não pode simplesmente enviar usuário e senha para ele, contêiner J2EE requer que essa URL seja chamado automaticamente. Não seria maravilhoso se fosse possível fazer uma chamada AJAX e passar login e senha para / j_security_check?


A solução que eu vi para essas situações sem separação física entre conteúdos protected e public é baseado em um <iframe>.

Então, vamos supor que temos um formulário configurado baseado em uma aplicação web segura , no web.xml, que parece algo como:



<security-constraint>
... <web-resource-collection>
..... <web-resource-name>secured</web-resource-name>
........<url-pattern>/secure/*</url-pattern>
.........<http-method>POST</http-method>
.........<http-method>GET</http-method>
......</web-resource-collection>
...<auth-constraint>
....<role-name>admin</role-name>
...</auth-constraint>
</security-constraint>
<security-role>
..<role-name>admin</role-name>
</security-role>


Nós necessitaremos de duas páginas - login.jsp e parentReload.jsp. O primeiro vai para o login-config do J2EE no config do web.xml, para que apareça se for feita uma solicitação para um contexto seguro:


<login-config>
..<auth-method>FORM</auth-method>
...<form-login-config>
....<form-login-page>/login.jsp</form-login-page>
....<form-error-page>/login.jsp?invalid=true</form-error-page>
...</form-login-config>
</login-config>


O login.jsp deve está algo como:


<%@page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<body>
<%
.....if (request.getParameter("invalid")!=null) {
%>
Incorrect login/password, try again:
<%
}
%>
<form action="j_security_check" method="post">
........user name: <input type="text" name="j_username"/><br/>
........password: <input type="password" name="j_password"/><br>
.......<input type="submit">
</form>
</body>
</html>


O parentReload.jsp vai para a pasta /secure tornando-se, provavelmente, o seu único habitante. O conteúdo JSP é bem simples, você pode adivinhar o que ele faz?


<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
....<script type="text/javascript">
.........parent.location.reload();
....</script>
</head>


Ele recarrega a pagina principal.

Agora, em cada página referencia de forma diferente para tipos de usuários, diferentes você pode colocar esse código no topo da página:


<%
final java.security.Principal userPrincipal = request.getUserPrincipal();
if(userPrincipal==null) {
%>
<iframe src="secure/parentReload.jsp" frameborder="0"></iframe>
<%
}
%>


Esta é a forma como ele funciona, você ainda não adivinhou? É o seguinte , o usuário atual não está autenticado ainda, um iframe é processado na página.Esse iframe, src 'secure/ParentReload.jsp está localizado na área protegida, assim, ao invés de exibir o contêiner J2EE original parentReload.jsp o contêiner intercepta o pedido e processa a página login.jsp dentro do frame, que resulta em um pequeno Widget contendo usuário e senha no topo da página, que deixa a página arrumada. Depois que o usuário decide fazer o login, o formulário de login é apresentada no iframe sem recarregamento da página principal. Se as credenciais do usuário foram válidos o contêiner J2EE transmite o parentReload.jsp no iframe. Uma vez proferida dentro do iframe ele fará com que a janela pai (a página principal) seja recarregada. Após recarregá-lo já não tente processar o iframe mais, e você está livre para processar o conteúdo protegido.

Este foi testado e funcionou muito bem no Tomcat, e deve funcionar com qualquer container J2EE.


Quem quiser ter acesso ao artigo original clique aqui

Até mais.

Nenhum comentário: