Back-End

6 abr, 2010

Autenticação e Autorização: JAAS com JDBC Realm

Publicidade

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).