Olá pessoal, tudo bem?
Em outro post eu mostrei como fazer uma validação via Servlet e Filter. Vamos fazer de um modo diferente hoje, vamos validar usuário utilizando JSF e JAAS.
A validação de usuário via JAAS faz com que o próprio servidor valide o usuário e sua senha juntamente a qual perfil de acesso ele tem. Sem a necessidade de a todo o momento estar (programaticamente) defendendo nossa aplicação. Deixemos o JBoss fazer isso por nós.
A seguir todos os links sobre web que já postei aqui no Blog: JSF: Converter e Bean Auto Complete, JSF – Hello World, Auto Complete, Autenticação de Usuários (Filter/Servlet), Tratando Exceções em uma Aplicação Web, Criando um WebServer.
Nós iremos utilizar JSF, Postgres, Eclipse e o JBoss 6:
O JBoss Tools é apenas para adiantar a parte JSF e poder utilizar o JBoss 6 por dentro do Eclipse. Você poderá criar todo o código passado aqui, e depois colocar apenas o war dentro da pasta do JBoss e executá-lo por fora do Eclipse. E mais acima tem um link para o post de como fazer de como fazer uma aplicação JSF.
Não irei mostrar como instalar o Postgres, pois irá fugir do tema do post, mas você poderá utilizar qualquer banco como MySQL, SqlServer, Oracle e assim vai.
Para instalar o JBoss Server descompacte o arquivo e pronto.
Descompacte o Eclipse e instale o JBoss Tools. É uma ferramenta muito boa quando se trabalha com JBoss e JSF.
Para instalar o JBoss Tools vá ao menu Help >Install New Software digite o endereço http://download.jboss.org/jbosstools/updates/stable/helios/na barra “Work with” e aperte a tecla “enter”.

Para ficar mais fácil, selecionei essas duas opções:

Depois avance e finalize a instalação.
E para instalar o servidor é fácil, botão direito na aba “Servers” > New > Server
Selecione JBoss 6 > Next

Selecione o path onde está seu JBoss descompactado.

E agora clique em Finish.
Vamos criar um novo projeto JSF (File > New > Project). Estou utilizando já um modelo pronto fornecido pelo JBoss Tools. Caso você queria criar um projeto JSF do zero, basta olhar mais acima onde eu postei outros links sobre a parte web.

Configure sua aplicação, eu a estou chamando de LoginJSF, selecione JSF 2.0 e depois clique em Finish.

O Eclipse irá perguntar se você quer mudar o modo de visualização web, eu marquei que não. Você pode marcar o sim depois e ver como que fica.

Ele irá criar uma aplicação onde já tem uma navegação básica. Note que ele já adicionou seu projeto dentro do servidor, caso não o tenha adicionado clique com o botão direito em cima do projeto >Run As > Run on Server. E selecione o JBoss.


Rode o servidor e acesse o seguinte link: http://localhost:8080/LoginJSF/

Pare o JBoss pois vamos criar três pastas:
- Uma pública
- Uma com acesso apenas para admin
- Uma com acesso parar admin e user
Abaixo, como ficará nossa estrutura de arquivos e os arquivos listados.

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<h:head>
I am public! [=
</h:head>
<h:body>
Everyone can see me. \o/
</h:body>
</html>
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<h:head>
Yes master admin! Welcome!
</h:head>
<h:body>
Let us run this business!
</h:body>
</html>
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<h:head>
Welcome mister user!
</h:head>
<h:body>
<br/>
Please, do not create any bugs, ok?! >=)
</h:body>
</html>
Agora vamos criar as configurações que interessam. Primeiramente, vamos alterar o “web.xml” para que ele proteja as nossas páginas:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
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_3_0.xsd">
<display-name>LoginJSF</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>*.jsf</url-pattern>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- Protected Areas -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Only admins</web-resource-name>
<url-pattern>/pages/protected/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Users and admins</web-resource-name>
<url-pattern>/pages/protected/user/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
<role-name>USER</role-name>
</auth-constraint>
</security-constraint>
<!-- Validation By Form -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/pages/public/login.xhtml</form-login-page>
<form-error-page>/pages/public/loginError.xhtml</form-error-page>
</form-login-config>
</login-config>
<!-- Allowed Roles -->
<security-role>
<role-name>ADMIN</role-name>
</security-role>
<security-role>
<role-name>USER</role-name>
</security-role>
<!-- Filter to get the user name and work with it -->
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.filters.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/pages/protected/*</url-pattern>
</filter-mapping>
</web-app>
Nós iremos precisar de uma página para login juntamente com uma página para erro. Observe que essas páginas estão descritas no “web.xml”.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
JSF 2 Login
</h:head>
<h:body>
<p>Login to access secure pages:</p>
<form method="post" action="j_security_check">
<h:panelGrid columns="2">
<h:outputLabel for="j_username" value="Username" />
<input type="text" id="j_username" name="j_username" />
<h:outputLabel for="j_password" value="Password" />
<input type="password" id="j_password" name="j_password" />
<input type="submit" name="submit" value="Login" />
</h:panelGrid>
<br />
</form>
</h:body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
JSF 2 Login
</h:head>
<h:body>
<p>Ops! Check your user and password</p>
</h:body>
</html>
Vamos criar um Filtro java que irá capturar o nome do login que foi digitado onde você poderá utilizar o login para buscar no banco de dados o usuário e colocá-lo na sessão.

package com.filters;
import java.io.IOException;
import javax.servlet.*;
import org.jboss.security.SecurityAssociation;
public class LoginFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,
ServletException {
String userName = SecurityAssociation.getPrincipal().getName();
System.out.println("Yeeey! Get me here and find me in the database: " + userName);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
Vamos criar agora nossas tabelas no banco de dados?
Estou utilizando um exemplo mais simples possível, duas tabelas apenas e cada uma com o mínimo de campos necessários.
Crie um database chamado LoginJSF e em seguida execute o script abaixo:
CREATE TABLE "users"
(
"name" character varying(50),
pass character varying(50)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "users" OWNER TO postgres;
CREATE TABLE user_roles
(
user_name character varying(50),
role_name character varying
)
WITH (
OIDS=FALSE
);
ALTER TABLE user_roles OWNER TO postgres;
Vamos inserir dois usuários, um com perfil de USER e outro com perfil de ADMIN:
INSERT INTO users("name", pass) VALUES ('user', 'user');
INSERT INTO users("name", pass) VALUES ('admin', 'admin');
INSERT INTO user_roles(user_name, role_name) VALUES ('user', 'USER');
INSERT INTO user_roles(user_name, role_name) VALUES ('admin', 'ADMIN');
Estamos quase lá, seja um pouquinho mais paciente! [=
Agora precisamos configurar o arquivo “login-config.xml” do próprio JBoss. Ele fica no diretório /JBOSS_QUE_VC_DESCOMPACTOU/server/default/conf/ . Adicione as seguintes linhas nele junto com as outras tags declaradas como “application-policy”:
<!-- Others application-policy -->
<!-- ..................... -->
<!-- Security Profile Of our Software-->
<application-policy name="LoginJSFRealm">
<authentication>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName">java:/LoginJSFRealmDS</module-option>
<module-option name="principalsQuery">select pass from users where name=?</module-option>
<module-option name="rolesQuery">select role_name, 'Roles' from user_roles where user_name = ?</module-option>
</login-module>
</authentication>
</application-policy>
Acabamos de informar o JBoss que iremos utilizar o Realm:LoginJSFRealm e precisamos informar ao JBoss agora que nossa aplicação irá utilizar esse Realm. Vamos criar um arquivo chamado “jboss-web.xml” dentro da pasta WEB-INF com o seguinte código:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<!-- Links with JBoss the Realm to use -->
<security-domain>java:/jaas/LoginJSFRealm</security-domain>
</jboss-web>
No arquivo “login-config.xhml” informamos ao JBoss para utilizar o seguinte datasource LoginJSFRealmDS. Através desse datasource ele irá se conectar ao banco de dados. Crie um arquivo chamado “LoginJSFRealm-ds.xml”dentro da pasta /JBOSS_QUE_VC_DESCOMPACTOU/server/ default/deploy/:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>LoginJSFRealmDS</jndi-name>
<connection-url>jdbc:postgresql://localhost:5432/LoginJSF</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>postgres</user-name>
<password>YOUR_PASSWORD</password>
<!-- sql to call when connection is created. Can be anything, select 1 is valid for PostgreSQL <new-connection-sql>select 1</new-connection-sql> -->
<!-- sql to call on an existing pooled connection when it is obtained from pool. Can be anything, select 1 is valid for PostgreSQL <check-valid-connection-sql>select
1</check-valid-connection-sql> -->
<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>PostgreSQL 7.2</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
E por último, copie o Driver JDBC 4 do Postgres que você fez o download para o diretório /JBOSS_QUE_VC_DESCOMPACTOU/server/ default/lib/.
Vamos agora rodar nossa aplicação e fazer o teste final? \o/
Acesse ao diretório publico primeiro: http://localhost:8080/LoginJSF/pages/public/public.html

Vamos ao diretório que apenas Admin pode acessar: http://localhost:8080/LoginJSF/pages/protected/admin/admin.html

Digite a senha e o usuário correto e pronto. Você irá logar.

E se um usuário tentasse acessar o link do admin? Faça o teste e veja o que acontece:

Tente o mesmo com o USER acessando a URL: http://localhost:8080/LoginJSF/pages/protected/user/user.html
Bem, por último e não menos importante, note no console quem apareceu por lá:

Através do filtro você irá conseguir fazer a consulta no seu banco de dados utilizando o usuário digitado e colocá-lo na sessão.
Importante 1: Você só irá passar pelo filtro após o login com sucesso feito pelo usuário. O trabalho de validar se o usuário digitou a senha correta fica por conta do JBoss! ;)
Importante 2: Caso você digite a senha correta e ele te envie para a tela de erro confira novamente os dados do JBoss como datasource,se o nome do datasource declarado no login-config é igual ao nome declarado dentro do arquivo de final “–ds.xml”, se as configurações descritas no datasource estão ok como senha, database, url de conexão.
Importante 3: Só após terminar o post percebi que eu dei o nome às páginas como html e não xhtml (user.html, admin.html, public.html). Você pode alterar e acessar novamente vendo o JSF entrar em ação (não se esqueça de acertar trocando o link e colocando xhtml no final!). Foi mals! =/
Espero que o post possa ter lhe ajudado.
Qualquer dúvida, pergunta ou sugestão basta falar.
Até a próxima pessoal! \o_