Tomcat Realm: Controle de acesso gerenciado pelo Container Web

Vou aproveitar o post do Urubatan ensinando como fazer um login com JSF para explicar como delegar, para o container web, o serviço de autenticação e autorização.

Neste exemplo explicarei como configurar uma aplicação web para ser autenticada pelo Tomcat, que será o Container Web usado no texto. Caso você use o Jetty, dê uma olhada em como fazer um Realm no Jetty.

Ah?! Como assim, o que é um Realm?
<conceito>
Realm: é uma base de dados que contém a informação de usuário, senha e as roles deste usuário no sistema
</conceito>

Não sabe o que é role?
<conceito>
Role: Lembra da parte de modelagem de sistema? Mais precisamente, lembra da definição dos casos de uso? Lembram que para executar um UC é necessário informar o ator que o executa? Ótimo. Cada um desses atores é uma role, ou melhor, um papel que um usuário precisa ter para executar o UC.
</conceito>

Para começar, vou demonstrar a configuração de um Realm do Tomcat. O Realm que eu estou usando prevê que os dados estão em um banco de dados relacional, neste caso o PostgreSQL. Para isso é necessário a criação das tabelas no postgre.
————————————————————————————————————-
tabela_usuario
——————
coluna_login texto ficará o nome do usuário
coluna_senha texto ficará a senha do usuário

tabela_roles
——————
coluna_nome_role texto ficará o nome da role
coluna_login texto ficará o nome do usuário com acesso a role
————————————————————————————————————-
Não precisa de uma tabela de roles, porque as roles são fixas, lembra? Elas representam os atores do caso de uso, certo?
Eu sei (cof) que, às vezes, (cof, cof) não dá tempo de fazer casos de uso(cof, cof, cof). Então pega o caderno, onde você escreveu a analise do sistema, e vê quem é que pode executar esta funcionalidade. Simples, não?

Neste caso, o ream Esta configuração deve ficar em um arquivo chamado context.xml na pasta META-INF, que fica na raiz do seu WAR:

/META-INF/context.xml -------------------------------------------------------------------------

<?xml version=”1.0″ encoding=”utf-8″?>
<Context displayName=”reteste” reloadable=”true”>
<Resource name=”jdbc/stripessec”
auth=”Container”
type=”javax.sql.DataSource”
maxActive=”10″
maxIdle=”3″
username=”nome_de_usuario_do_banco”
password=”senha_do_usuario_do_banco”
driverClassName=”org.postgresql.Driver”
url=”jdbc:postgresql://localhost:5432/database_criado_no_postgre”/>

<Realm className=”org.apache.catalina.realm.DataSourceRealm” debug=”99″
dataSourceName=”jdbc/stripessec” localDataSource=”true”
userTable=”tabela_usuario”
userNameCol=”coluna_login”
userCredCol=”coluna_senha”
userRoleTable=”table_permissao”
roleNameCol=”coluna_nome_permissao” />

</Context>
---------------------------------------------------------------------------------------------

No exempo eu criei um DataSource, para um database no banco PostgreSQL, que também servirá para o resto da aplicação. E criei um Realm JDBC. Que, basicamente é falar o quais as tabelas e quais as colunas que representa os usuários e as permissões dele.

Depois do context.xml criado, escrevo, no web.xml, as informações necessárias para a aplicação usar o Realm e o DataSource:

/WEB-INF/web.xml --------------------------------------------------------------------------

<?xml version=”1.0″ encoding=”UTF-8″?>

<web-app xmlns=”http://java.sun.com/xml/ns/j2ee&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&#8221;
version=”2.4″>

<!– ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ –>
<!– Configuração do DataSource. –>
<!– ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ –>
<resource-ref>
<description>Web Database</description>
<res-ref-name>jdbc/stripessec</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

<!– ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ –>
<!– Configuração da autenticação e autorização. –>
<!– ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ –>

<security-constraint>
<display-name>Área Restrita</display-name>
<web-resource-collection>
<web-resource-name>Arquivos protegidos por login</web-resource-name>
<url-pattern>/jsp/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>systemuser</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>StripesSecRealm</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>systemuser</role-name>
</security-role>

</web-app>

---------------------------------------------------------------------------------------------

Estou disponibilizando o DataSource para o resto da aplicação e declarando o Realm, com configurado para proibir o acesso, para usuário não autenticados, aos arquivos dentro da pasta jsp, que por sua vez está na raiz do WAR. Aqui é um bom lugar para colocar uma URL comum as Actions do seu framework MVC, desta forma o acesso a elas também será proibido.

Estas são as páginas de login e de erro, respectivamente, que ficarão na raiz do meu WAR:

/login.jsp -----------------------------------------------------------------------------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="pt-br">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>.:: Autenticação ::.</title>

</head>
<body>
<form method="POST" action="<%= response.encodeURL("j_security_check") %>" >
<fieldset title="Informe login e senha">
<legend>Login</legend>

<label for="j_username">Login:</label>
<input type="text" name="j_username" class="textBox"/><br/>

<label for="j_password">Senha:</label>
<input type="password" name="j_password" class="textBox"/><br/>

</fieldset>
<p align=”center”>
<input type=”submit” value=”Log In”/>
</p>
</form>
</body>
</html>
---------------------------------------------------------------------------------------------

Notem a falta total de TagLibs. Se não fosse a preocupação em garantir que vai funcionar, independente do contexto em que será feito o deploy, poderia ser um arquivo HTML.


/error.jsp ------------------------------------------------------------------------------------

<html
<head>
<title>Erro ao tentar autenticar usuário</title>
</head>
<body>

<p>

Usuário ou senha inválidos.<br/>

Verifique o nome de usuário e a senha e <a href="<%= response.encodeURL("login.jsp") %>">tente novamente</a>.

</p>

</body>
</html>

---------------------------------------------------------------------------------------------

Outra vantagem é que mesmo que seja tentado acessar a url diretamente, o container irá redirecionar para a página de login.

Após a autenticação, o container se encarrega de abrir a URL solicitada inicialmente. Este comportamento é perfeito para permitir seus usuários a colocar as partes do sistema que ele mais utiliza em seus favoritos(a.k.a. bookmarks).


Esta é a página protegida pelo Realm. :
/jsp/home.jsp -------------------------------------------------------------------------------
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<h1>Página protegida pelo Realm.</h1>
</body>
</html>

---------------------------------------------------------------------------------------------
Para acessar esta página, o usuário precisa da permissão "
systemuser”, isto é, no banco de dados, na tabela de associação entre o usuário e as roles tem que ter o login dele e o systemuser como role.

Para essa autenticação, a única dependência é o driver JDBC para o PostgreSQL, neste caso, na pasta $TOMCAT_HOME/common/lib.

  1. Alguma sugestão de melhoria nas explicações? Ficou alguma dúvida?
  2. Poderiam contribuir com formas de burlar esta autenticação? Se elas existirem?
  3. Alguma outra sugestão para o texto?

Atualmente eu tenho usado a autenticação apenas em meus freelances, uma vez que no trabalho a aplicação é desktop. Mais um motivo para eu preferir aplicações web… 😀

P.S.: Caso dê alguma caca neste post, dá um desconto, porque é o primeiro que eu publico usando o Google Docs 🙂

Anúncios

56 opiniões sobre “Tomcat Realm: Controle de acesso gerenciado pelo Container Web

  1. Posso ter me perdido no texto (que diga-se de passagem está muito bom…), mas como vc associa uma role a uma pagina jsp?

    Tipo, no exemplo acima a página “home.jsp” está associada a role “systemuser”, até aí tudo blz… pq esta role é padrão. Mas como associar a página “cadastrodeqqcoisa.jsp” à role “systemadmin”?

  2. Mumak: Obrigado pelo elogio. Quanto a sua pergunta…

    No caso que eu mostro no texto, eu estou protegendo todos os arquivos dentro da pasta jsp que fica na raiz da aplicação. Isso é configurado usando a tag :
    […]/jsp/*[…]

    E exigindo, para acessar esses arquivos, a role “systemuser”. Defino isso usando a tag :
    […]systemuser[…]

    Poderia ser qualquer nome aqui. Eu coloquei “systemuser” por ser o mais genérico.

    Assim, se você quiser restringir ainda mais, poderia ter:
    […]/cadastrodeqqcoisa.jsp[…]
    […]systemadmin[…]

    Assim, para acessar a página “cadastrodeqqcoisa.jsp”, localizada na raiz do WAR, será necessário a role systemadmin.

    Espero ter ajudado. Qualquer dúvida é só comentar 🙂

    [],
    AC

  3. Muito bacana esse esquema de autenticação usando JDBC.

    Gostaria de aproveitar para perguntar uma coisa: como posso saber na minha aplicação qual usuário se autenticou? No caso, pra eu poder carregar um perfil do usuário que será usado pela minha aplicação e, até mesmo, para poder mostrar os links disponíveis para cada usuário (isso é muito importante na aplicação que estou começando a desenvolver).

    • Olá AC, achei muito interessante o seu tutorial, mas estou com um problema na implementação do context.xml. Na verdade, eu já tenho um projeto web iniciado com banco em postgres, e essa sua sujestão caiu como uma luva.

      O problema logo de cara, é na criação do context.xml. aparece um erro na linha 1 assim:
      the value following “version” in the XML declaration must be a quoted string.

      O que pode ser isso?? é alguma configuração do Tomcat?? Se puder me ajudar, agradeço, pois estou iniciando em java e é muito dificil encontrar soluçoes sobre esses tipos de dúvidas nos fóruns. Sei que esse assunto é antigo no seu blog, mas agradeço se puder ajudar.

      Valeu.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s