Olá, pessoal!
Veremos hoje um assunto que todos os
desenvolvedores, os arquitetos etc têm que se preocupar ao desenvolver
uma aplicação: a famosa segurança. Você, como
“profissional do software”, tem que saber quem vai ter
acesso a determinadas partes da sua aplicação e quais serão os limites de cada nível de acesso.
Como fazer isso, Camilo?
Alguns
programadores em JavaEE têm esta dúvida: como implementar
regra de acesso sem precisar fazer um hard-code?
Nenhum desenvolvedor que conheço vai querer fazer isso via code
por um simples motivo: as
regras de segurança podem mudar com bastante frequência.
Por exemplo, suponha que amanhã você precisa adicionar um novo nível de
administrador (sênior, pleno) e cada um com permissões diferentes.
Mas também pode acontecer de um novo grupo fazer parte da
administração, os “gerente de projetos”, aí lá vai você atualizar o code. Mas e se alguns dos citados deixarem de existir? Já viu o problema que
temos ao implementar regras de segurança dentro do seu servlet,
controller etc.
Geralmente quem está começando em JEE põe tudo que for
restrito dentro de WEB-INF, mas isso não é boa prática. As regras de
segurança referentes a acesso serão mais simples ou mais complexas, dependendo da regra de negócios da aplicação. Por
exemplo, já vi aplicações que têm vários tipos de
administradores, usuários, com acessos completamente diferentes,
porém no mesmo nível. Mas colocar em WEB-INF tudo isso não é
recomendado. Lembre-se de que quem tem acesso ao web-inf é somente o
container.
Vamos parar de conversa e ver isso prática. Let’s go…
- Realm é o rapaz que vai ajudar dar uma mãozinha nesse hard-work
-
Realm é um
depósito de informações de usuário que autentica e autoriza os
usuários.
Usando
realms você põe a responsabilidade no servidor Web, por obrigar a
implementar políticas de segurança. Isto significa que os
desenvolvedores não precisam escrever código para usar autenticação
e autorização (não que isso os impeçam de fazê-lo). Delegando
autenticação e autorização ao servidor, os desenvolvedores podem
escrever códigos de propósitos gerais, sem preocupação com as
regras de autorização de acesso – do livro Tomcat – Guia Rápido do Administrador.
Para o nosso exemplo, vamos usar um dos mais populares containers JEE, o
TomCat (versão 6). Se você estiver usando um container diferente,
terá que ler a documentação do fabricante e saber como
implementar, mas, na maioria das vezes, há poucas mudanças.
Artigos recomendados:
Requisitos
- Eclipse (usarei o Galileo)
- TomCat 6 (se tiver a 5.x.x sem problemas, pode usar)
Aqui vamos implementar sem usar dados vindo do BD. Então veja como
uma forma de praticar “Segurança”, até porque sem BD, você vai
precisar sempre ficar atualizando o arquivo tomcat-users.xml e
se você não usar criptografia, qualquer um pode abrir esse arquivo
e saber as senhas de cada usuário.
Desenvolvendo
Crie um dynamic web project no Eclipse. O meu chama RealmCamilo e, no decorrer do
post, informarei o que teremos em cada page .jsp.
Na página acessonegado.jsp insira o código a seguir:
<strong>E-mail/Senha inválido.</strong><a href="index.jsp" class="broken_link">Tente novamente </a> />
Na página index.jsp, deixe conforme abaixo:
<a href="admin" class="broken_link"> Acessar minha conta</a >
E na página index.jsp, dentro de /admin, deixe assim:
<body>
Esta é uma página de conteúdo restrito. :)
</body>
Até aqui nada de especial. Agora que começa a segurança.
Primeiro ponto é você deixar o tomcat parado e ir no caminho a
seguir (caso tenha instalado no modo default):
C:\Program Files\Apache Software Foundation\Tomcat 6.0\conf
<Realm className="org.apache.catalina.realm.MemoryRealm"/>
Salve e feche o arquivo
Agora vá no arquivo tomcat-users.xml no mesmo diretório do arquivo
server.xml.
Nesse arquivo criamos os usuários que terão acesso aplicação e
qual role ele pertence.
<tomcat-users>
<role rolename="manager" />
<role rolename="admin" />
<user username="camilo" password="123" roles="manager,admin" />
<user username="admin" password="" roles="manager,admin" />
<user username="lopes" password="lpjava" roles="manager"/>
</tomcat-users>
Não é muito difícil de ler, veja:
“lopes É-UM manager. Porém, admin e camilo são um manager e admin.”
O relacionamento aqui é one-to-many, nao se esqueça disso. Ou
seja, um usuário pode ter mais de um nível de acesso.
Lembre-se de que isso aí só são strings. O poder deles está quando
criamos as restrições no arquivo web.xml.
Abra o arquivo server.xml.
Precisamos dizer ao TomCat que vamos habilitar o Realm, a linha vem
comentada, para isso tire o comentário da linha a seguir:
<Realm className="org.apache.catalina.realm.MemoryRealm"/>
Salve e feche o arquivo.
Agora vá no arquivo tomcat-users.xml no mesmo diretório do arquivo server.xml.
Nesse arquivo criamos os usuários que terão acesso aplicação e qual role ele pertence.
Não é muito difícil de ler, veja:
“lopes É-UM manager. Porém, admin e camilo são um manager e admin.”
O relacionamento aqui é one-to-many, não se esqueça disso. Ou seja, um usuário pode ter mais de um nível de acesso.
Lembre-se de que isso aí só são strings. O poder deles está quando criamos as restrições no arquivo web.xml.
Criando as regras de acesso
Agora precisamos criar as regras de acesso, dizer o que um
“manager” pode acessar e o que um “admin”pode acessar.
Abra o arquivo web.xml da sua aplicação. Antes do primeiro código, você precisa saber disto:
- <security-constraint>:
Protege um recurso, ou seja, diz o que será protegido e quem pode
acessar. - <auth-constraint>: Especifica os roles que são permitidos acessar recursos
cobertos por esta limitação de segurança.
- <web-resource-collection>: Sub-elemento de <security-constraint> que diz o que será
registro. - <login-config>:
Ddiz qual o tipo de autenticação. Há quatros tipos: BASIC, DIGEST,
FORM, SSL.
Para
o nosso exemplo, usaremos o FORM. O BASIC usa a caixa de
autenticação do browser.
Insira
o código abaixo no seu arquivo web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Area restrita</web-resource-name>
<url-pattern>/admin/*</url-pattern> <!-- tudo dentro de admin sera restrito -->
</web-resource-collection>
<auth-constraint>
<!-- somente administrador tem acesso aos arquivos em admin -->
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Autenticação</realm-name>
<form-login-config>
<!-- de onde vem o resquet? da pagina login -->
<form-login-page>/login.jsp</form-login-page>
<!-- se falha vá para página acesso negado -->
<form-error-page>/acessonegado.jsp</form-error-page>
<!-- se der certo vá para a página solicitada -->
</form-login-config>
</login-config>
<security-role>
<role-name>manager</role-name>
</security-role>
<security-role>
<role-name>admin</role-name>
</security-role>
Atenção:
Tenha atenção com o código de <login-config>. Muitos confundem, achando que o login/senha estão OK. Vá para
a página que está em <form-login-page>, mas ali temos nenhuma condição IF.
O
segredo é: antes de ir para tela de login, você precisa tentar acessar o conteúdo restrito (na realidade, é isso o que
acontece, pense um pouquinho…), assim o servidor vai saber o que
fazer com quem acessar, caso o login/senha seja válido, ou seja,
enviar você para a página que foi solicitada (requested).
Se
você tentar ir direto para página de login, sem
acessar um conteúdo restrito,
como o servidor vai saber para onde encaminhá-lo, já que no action do form não
há nada que diz “vá para pagina XYZ”?
Veja
o código do form login.jsp:
<fieldset>
<legend>Login</legend>
<form action="j_security_check" method="post">
Usuario:<input type="text" size="30" name="j_username"/>
Senha:<input type="password" name="j_password"/>
<input type="submit" value="Entrar">
</form>
</fieldset>
O
atributo name, action deve ser com os nomes acima. Caso contrário,
nada funciona como esperado. E não esqueça que o método deve ser
post, pois é um FORM.
Eu
tenho o hábito de dizer: “primeiro
erre, para depois acertar”.
Ou seja, primeiro tente acessar, se não conseguir use seu
login/senha. O máximo que vai receber é dizer que você não tem
permissão para acessar.
Testando
Para testar, vamos
fazer um deploy da nossa app. Vamos usar um arquivo WAR.
Abaixo, veja como ficou
minha exportação:
Veja meus testes de
acesso:
Tentando com o
usuário camilo
Resultado:
Tentando com o
usuário lopes
Resultado:
Agora é com você, experimente testar
acessando o conteúdo restrito direto, tente colocar usuário
inexistente, ou usuário com roles diferentes ao acesso permitido.
Vou ficando por aqui, espero que tenham gostado. Claro que hoje temos várias formas de implementar a segurança em aplicações JEE, apresentamos aqui uma delas, temos frameworks como o Spring Security que ajuda na implementação, por exemplo.
Abraços,
see you! :).