Recentemente ministrei um curso sobre Segurança em aplicações
JavaEE, onde grande parte do treinamento é a utilização e
a configuração do JAAS (Java Authentication and Authorization Service)
abordando Basic e Form Authentication usando os realms:
File, JDBC e LDAP.
Aproveitando o embalo do treinamento e principalmente pela empolgação
dos alunos da turma quando viram quão simples e fácil é usar o JAAS,
vou mostrar a configuração de autenticação e autorização em uma
aplicação JavaEE usando Basic Authentication e JDBC Realm.
O JAAS (Java Authentication and Authorization Service) é a
API padrão do Java para controle de acesso e autorização em aplicações
JavaEE. Com JAAS é possível autenticar e validar usuários e
certificados, bem como controlar a possibilidade de acesso e/ou
utilização de recursos na aplicação (arquivos, diretórios, URLs,
conteúdo, etc). Resumidamente, o JAAS cuida de:
- Autenticação: deve verificar se um usuário é ele
mesmo através de validação de senhas e/ou certificados. - Autorização: com base em um usuário identificado,
as regras e os controles de permissão e acesso serão aplicadas na
aplicação/produto e seus recursos.
O exemplo a seguir foi feito usando o Eclipse, Glassfish_v2 e MySQL, e
não há nenhum segredo obscuro, simplesmente criaremos um Dynamic
Web Project e usaremos o console do Glassfish para criar o realm.
A infra-estrutura (servidor e banco de dados)
O ponto chave para a configuração do JDBC Realm é o banco de
dados (tabelas de usuário e grupos). Criaremos o schema com o
SQL a seguir. Basicamente são apenas duas tabelas: usertable e grouptable.
A configuração do schema no realm será feita
adiante e este exemplo está simples desta forma apenas para ficar o mais
claro possível na configuração do realm. Certamente no seu
caso você já terá suas tabelas de usuários e grupos e, para usá-los, basta
fazer a configuração do realm de acordo com a sua realidade,
alterando os valores das propriedades de configuração.
CREATE DATABASE learn_jaas;
USE learn_jaas;
CREATE TABLE usertable(userid VARCHAR(10) PRIMARY KEY, password VARCHAR(32) NOT NULL);
CREATE TABLE grouptable(userid VARCHAR(10), groupid VARCHAR(20) NOT NULL, PRIMARY KEY (userid, groupid));
ALTER TABLE grouptable ADD CONSTRAINT FK_USERID FOREIGN KEY(userid) REFERENCES usertable(userid);
COMMIT;
E agora vamos inserir alguns usuários e grupos para os testes,
conforme o SQL abaixo. Os usuários serão: user, guest e
admin e os grupos serão: users, e admins.
Reparem que os grupos estão no plural, enquanto os usuários estão no
singular. Este é um importante detalhe, a seguir, na configuração das roles
usaremos os grupos para aplicar as regras e não os usuários.
INSERT INTO usertable VALUES ('user', 'user');
INSERT INTO grouptable VALUES ('user', 'users');
INSERT INTO usertable VALUES ('guest', 'guest');
INSERT INTO grouptable VALUES ('guest', 'users');
INSERT INTO usertable VALUES ('admin', 'admin');
INSERT INTO grouptable VALUES ('admin', 'admins');
Com o banco de dados pronto, ainda precisamos de um passo antes do realm,
precisaremos criar agora o Connection Pool e o DataSource
para este banco de dados. O JNDI Name deste DataSource
será usado na criação do realm, portanto, este passo é
essencial para o funcionamento do exemplo. Entretanto, como o foco aqui
não é a criação do DataSource, darei apenas o JNDI Name
conforme usei no exemplo: learn-jaas-jdbc.
Agora só precisamos criar o realm, o nome usado para ele
será learn-jaas-realm. No console do glassfish vamos
em: Configuration >> Securiy >> Realm >> New.
As propriedades deverão ser preenchidas de acordo com a imagem e a
tabela abaixo (se o seu schema for diferente é só ajustar os
valores):
Propriedade | Valor |
jaas-context | jdbcRealm |
datasource-jndi | learn-jaas-jdbc |
user-table | usertable |
user-name-column | userid |
password-column | password |
group-table | grouptable |
group-name-column | groupid |
digest-algorithm | none |
A aplicação
Com a infra-estrutura necessária criada e funcionando, partiremos
para a aplicação. Este será um ponto bem simples, a aplicação não terá
nada além de 4 páginas JSP, web.xml e sun-web.xml.
No Eclipse, criaremos um Dynamic Web Project usando o
glassfish como servidor (JavaEE 5). As páginas citadas anteriormente
ficarão dispostas conforme o projeto abaixo:
Em cada página index.jsp dos diretórios admin, public
e users há um dizer assim: “Welcome Admin!”; “Welcome
Guest!”; “Welcome User!”; respectivamente. E em /index.jsp
há apenas os links para as demais páginas. Estes diretórios serão
protegidos posteriormente.
O próximo passo consiste na criação das roles em nossa
aplicação. Este costuma ser o ponto onde os iniciantes se confundem
muito, por isso houve aquela distinção entre os nomes dos usuários e os
grupos anteriormente. A criação das roles é livre, podemos
criá-las como bem entendermos, o único ponto de atenção aqui é que a
role é associada ao grupo, ou seja, uma role
será aplicada para todos os usuários de um determinado grupo.
Então, em WEB-INF/sun-web.xml criaremos as roles
associadas com os seus respectivos grupos:
<security-role-mapping>
<role-name>user-role</role-name>
<group-name>admins</group-name>
<group-name>users</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>admin-role</role-name>
<group-name>admins</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>guest-role</role-name>
<group-name>admins</group-name>
<group-name>users</group-name>
<group-name>guests</group-name>
</security-role-mapping>
As roles foram criadas com o sufixo -role apenas
para ficar bem claro que são roles e não usuários ou grupos.
Vejam que as roles estão associadas aos grupos e não aos
usuários.
Este é um momento onde aplicaremos as regras hierárquicas e
organizacionais da empresa, repare que o grupo admins aparece
em todas as roles, afinal de contas, não queremos barrar ao
administrador do sistema o acesso às páginas públicas ou de usuários,
certo?
Próximo passo: Configuração do web.xml! A configuração da
autenticação em si não passa de 4 linhas de xml, informaremos o tipo
(método) de autenticação (pode ser none, basic, form
e digest/certificate) e qual o nome do realm
associado:
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>learn-jaas-realm</realm-name>
</login-config>
O que precisaremos agora é, com base nas roles, criar as
regras de acesso na aplicação. Elas podem ser feitas de várias formas e
como podemos usar URL Pattern para definir onde a regra será
aplicada, faremos isso por diretórios, combinando os diretórios com as roles
(admin, user e guest):
<security-constraint>
<web-resource-collection>
<web-resource-name>paginas admnistrativas</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin-role</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>paginas para usuários</web-resource-name>
<url-pattern>/users/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user-role</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>paginas para visitantes</web-resource-name>
<url-pattern>/public/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>guest-role</role-name>
</auth-constraint>
</security-constraint>
Repare que o código ficou grande, mas é muito repetitivo. Os pontos
de atenção são o elemento url-pattern, onde é gerada a regra
para onde as restrições serão aplicadas e, principalmente, o elemento role-name,
onde definimos qual a role está associada com aquela regra.
Mais uma vez repare que a regra de acesso é associada à role,
já a role, por sua vez, está associada com um grupo, que, por sua
vez, está associado com um usuário.
Agora é só fazer o deploy e executar o projeto. Lembre-se das senhas
(ou consulte no banco de dados) e faça o teste de acesso em cada página.
Para facilitar disponibilizei o projeto para download, basta clicar
aqui (por algum motivo alheio a minha compreensão o wordpress
não deixou o nome do arquivo igual ao original, então, basta colocar um
ponto antes do ‘tar’, deve ficar project-to-learn-jass.tar.gz).