Recentemente ministrei um curso sobre Segurança em aplicações JavaEE, onde, grande parte do treinamento é a utilização e 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 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.

schema

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.

1
2
3
4
5
6
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.

1
2
3
4
5
6
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):

glassfish-new-jdbc-realm

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:

project_jaas

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    <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:

1
2
3
4
    <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):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    <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, baste colocar um ponto antes do ‘tar’, deve ficar project-to-learn-jass.tar.gz)