Você está na página 1de 9

Home > Traduções > Apache Shiro Parte 1 – básico

Apache Shiro Parte 1 – básico


April 7th, 2011 gilberto_ca Leave a comment Go to comments

Este post é uma tradução livre do artigo “ Apache Shiro Part 1 – Basics “, publicado por Meri em
27 de março 2011

Apache Shiro, inicialmente chamado JSecurity, é um framework de segurança desenvolvido em


java. Foi aceito e tornou-se um projeto Apache de nível superior em 2010. Tem como objetivo
ser poderoso e fácil de usar.

O projeto está em constante desenvolvimento e com listas de e-mails ativas para usuários e
desenvolvedores. Áreas mais importantes estão documentadas em sua página web. No
entanto, existem algumas lacunas na documentação. Não é possível aprender a usar o
máximo dos recursos do Shiro somente com a documentação. Felizmente, o código é bem
documentado e onde o testei, ela foi de fácil leitura.

Principais recursos do projeto Shiro são:

autenticação,

autorização,

criptografia,

gerenciamento de sessão.

Neste artigo tentaremos demonstrar vários recursos do Shiro. Vamos começar com uma
simples aplicação sem segurança e então adicionaremos recursos de segurança. Todo código
está disponível no projeto SimpleShiroSecuredApplication hospedado no Github.

Aplicação sem Segurança

O código da aplicação sem segurança está localizado no ramo(branch) unsecured_application.


A aplicação representa um sistema interno para uma companhia fictícia. A companhia tem
quatro departamentos:

administradores(administrators),

reparadores(repairmen),

cientistas(scientists),

vendedores(sales).

Cada departamento tem sua própria página. Cada página contém botões que serão usados por
usuários em sua atividade. Quando o usuário pressiona o botão, o trabalho é realizado. Por
exemplo, qualquer reparador pode acessar a página reparadores(repairmen) e pressionar o
botão “Reparar Refrigerador(Repair Refrigerator)”. O botão repara refrigerador e mostra
mensagem de sucesso.

Cada usuário tem sua própria página de gerenciamento de conta. Esta página de
gerenciamento contém informações privadas do usuário. Como a aplicação sem segurança não
tem usuários ainda, a página de gerenciamento de conta não faz nada. Adicionalmente, há
uma página que contém todas funções da aplicação. Tudo que alguém pode fazer é possível
ser feito nesta página.

Qualquer pessoa pode fazer qualquer coisa e ver todas as páginas. A aplicação exemplo é
executada na classe de teste RunWaitTest. Não é uma boa prática usar teste de unidade desta
forma, mas isso não é importante agora. Se você executar a classe a aplicação estará
disponível no endereço (url) http://localhost:9180/simpleshirosecuredapplication/.

Adicionando Autenticação

Primeiro, temos que verificar a identidade do usuário. A mais fácil e padronizada forma de
autenticação é feita por senha e nome usuário. Usuário preenche o seu nome de usuário e
senha e o sistema verifica se os valores fornecidos combinam com alguma conta de usuário.

Para aplicações mais simples, é suficiente armazenar nome e senha de usuários em arquivos
de texto puro. Em um cenário mais realista, o nome e senha são armazenados em um
mecanismo de persistente or a verificação é feita por outro sistema como ldap ou active
directory. Shiro suporta todos os métodos de autenticação mencionados. Se os recursos de
autenticação pré-existentes não são suficientes, é possível estender o framework com sua
própria implementação de verificação.

Neste capítulo, iremos adicionar autenticação baseada em nome de usuário e senha na


aplicação. Nome de usuário e senha serão armazenados no arquivo de inicialização do Shiro, o
qual é texto e estático.

Novos requisitos:
É possível a entrada e saída de usuários(log in/out). A aplicação será acessível somente para
usuários registrados. Usuário com autenticação sem erros é redirecionado para sua própria
página de gerenciamento de conta. Todas as páginas e funções da aplicação serão acessíveis
para qualquer usuário autenticado.
Passos necessários:

adicionar Apache Shiro,

criar página de autenticação(log in),

configurar usuários e senhas,

criar página de saída(log out).

Adicionar Apache Shiro

Shiro é integrado à aplicação web através de filtros servlet. Um filtro intercepta requisições e
respostas antes do servlet e executa todas as tarefas necessárias (como a identificação do
usuário atualmente autenticado, anexar o usuário ao thread corrente, …). Filtros Shiro
pré-definidos fornecem recursos de segurança básicos, como:

força a autenticação do usuário(log in),

força ssl,

verificação dos direitos de acesso à página.

Se você quiser aprender mais sobre filtros Shiro pré-definidos, um bom lugar para começar é a
enumeração DefaultFilter. Ela lista todos os filtros Shiro pré-definidos disponíveis. Se estes não
forem suficientes para suas necessidades, você pode criar um personalizado.

Usaremos o filtro altamente configurável IniShiroFilter. Ele lê a configuração Shiro a partir do


arquivo ini e inicializa o framework de segurança. Ele não executa qualquer verificação de
segurança. Verificação de segurança, autenticação de usuário, verificação de protocolo, etc. são
todos transferidos(delegados) tanto para o filtro Shiro pré-definido quanto para o filtro
personalizado(outra implementação). O filtro IniShiroFilter apenas os inicializa.

A configuração ini é descrita na documentação e no javadoc. O arquivo de configuração ini tem


quatro seções:

Seção [main] contém a inicialização do Shiro. Filtros e objetos personalizados são


configurados aqui.

Seção [users] define usuários, senhas e perfis de usuário(roles).

Seção [roles] associa perfis(roles) com permissões.

Seção [urls] especifica direitos de acesso às páginas da aplicação (urls). É feito ligando
filtro tanto pré-definido quanto personalizado às urls

Adicione Apache Shiro como dependência ao arquivo pom.xml:


<properties>
<shiro.version>1.1.0</shiro.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
</dependencies>

Crie o arquivo Shiro.ini e o coloque no classpath. Configure o arquivo web.xml para chamar o
filtro IniShiroFilter antes de cada requisição:
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
<init-param>
<param-name>configPath</param-name>
<param-value>classpath:Shiro.ini</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Criar P ágina de Autenticação(Log in)

A página de autenticação é uma simples página html contendo um botão submissão, nome de
usuário e senha. A funcionalidade de autenticação é tratada pelo filtro Shiro authc pré-definido.
O filtro autch permite acesso à página (url) somente a usuários autenticados. Se o usuário não
está autenticado, o filtro o redirecionará para a página de autenticação (log in).

Crie a página login.jsp:

<form name="loginform" action="" method="post">


<table align="left" border="0" cellspacing="0" cellpadding="3">
<tr>
<td>Username:</td>
<td><input type="text" name="user" maxlength="30"></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="pass" maxlength="30"></td>
</tr>
<tr>
<td colspan="2" align="left"><input type="checkbox" name="remember"><font size="2">Remember Me</font>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" name="submit" value="Login"></td>
</tr>
</table>
</form>

Habilite o filtro authc para todas as páginas da aplicação:

[main]
# specify login page
authc.loginUrl = /simpleshirosecuredapplication/account/login.jsp

# name of request parameter with username; if not present filter assumes 'username'
authc.usernameParam = user
# name of request parameter with password; if not present filter assumes 'password'
authc.passwordParam = pass
# does the user wish to be remembered?; if not present filter assumes 'rememberMe'
authc.rememberMeParam = remember

# redirect after successful login


authc.successUrl = /simpleshirosecuredapplication/account/personalaccountpage.jsp

[urls]
# enable authc filter for all application pages
/simpleshirosecuredapplication/**=authc

Atualilzação: Shiro automaticamente executa a equiparação(comparação) de caminho(path


matching) relativa ao contexto. Como a aplicação SimpleShiroSecuredApplication não tem o
caminho do contexto definido, caminhos completos no arquivo Shiro.ini são necessários. No
entanto, se o contexto da aplicação fosse definido para /simpleshirosecuredapplication, então
os caminhos poderiam ser relativos, por exemplo, /**=authc ou /account
/personalaccountpage.jsp.

Como não é seguro enviar nome de usuário e senha pela rede, devemos forçar autenticações
com o protocolo ssl. O filtro ssl faz exatamente isso. Ele tem um parâmetro opcional: número
da porta ssl. Se o parâmetro porta(port) for omitido, ele usa a porta ssl pré-definida 443.

Antes de configurar o protocolo ssl no Shiro, precisamos habilitá-lo no servidor web. Como fazer
isso, depende do servidor web. Iremos demonstrar como habilitá-lo no Jetty. Primeiro, crie um
keystore com o certificado auto assinado:

keytool -genkey -keyalg RSA -alias jetty -keystore keystore -storepass secret -validity 360 -keysize 2048

Responda todas questões e no final pressione ENTER, assim o keystore senha e a chave senha
serão o mesmo.

Segundo, adicione o keystore ao projeto e configure o servidor Jetty para usar o protocolo ssl. O
código java está disponível na classe AbstractContainerTest.

Agora é possível configurar o filtro ssl no arquivo Shiro.ini:

[urls]
# force ssl for login page
/simpleshirosecuredapplication/account/login.jsp=ssl[8443],authc
# enable authc filter for the all application pages; as Shiro reads urls from up to down, must be last
/simpleshirosecuredapplication/**=authc

Configurar Usuários e Senhas

A aplicação SimpleShiroSecuredApplication estará agora disponível somente para usuários


autenticados. Assim, é necessário adicionar alguns usuários de forma que algumas pessoas
tenham acesso à aplicação.
A configuração é feita na seção [users] do arquivo Shiro.ini. O formato das entradas da seção é:

username = password, roleName1, roleName2, ..., roleNameN

A seguinte seção cria sete usuários, todos com a mesma senha ‘heslo’:
[users]
administrator=heslo,Administrator
friendlyrepairmen=heslo,repairmen
unfriendlyrepairmen=heslo,repairmen
mathematician=heslo,scientist
physicien=heslo,scientist
productsales=heslo,sales
servicessales=heslo,sales

Agora é possível ser autenticado e ter acesso à aplicação. No entanto, as senhas estão, ainda,
em texto puro. É melhor armazenar e comparar somente o hashing da senha.

Objetos responsáveis por autenticação são chamados de realms. Por padrão, Shiro usa o
IniRealm com comparador de senha plugável para comparar senhas. Iremos substituir as
senhas no ini por suas correspondentes hasheadas com SHA-256 e configurar o IniRealm para
usar este comparador de senhas.

Gerar o hash SHA-256 da senha:

import org.apache.shiro.crypto.hash.Sha256Hash;

public static void main(String[] args) {


Sha256Hash sha256Hash = new Sha256Hash("heslo");
System.out.println(sha256Hash.toHex());
}

Configurar o Shiro para comparar senha hasheada ao invés da própria senha:

[main]
# define matcher matching hashes instead of passwords
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName=SHA-256

# enable matcher in iniRealm (object responsible for authentication)


iniRealm.credentialsMatcher = $sha256Matcher

Substituir as senhas dos usuários por senhas hasheadas:


[users]
administrator=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, Administrator
friendlyrepairmen=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, repairmen
unfriendlyrepairmen=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, repairmen
mathematician=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, scientist
physicien=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, scientist
productsales=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, sales
servicessales=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005, sales

Nota: é possível especificar SALT no arquivo de configuração ini.

Criar P ágina de Saída(Log out)

Qualque aplicação que tenha recursos de autenticação deveria também ter o recurso de saída.
Terminar uma sessão corrente com Shiro é fácil, use o comando:
//acquire currently logged user and log him out
SecurityUtils.getSubject().logout();

A página de saída(Log out) então fica assim:


<%@ page import="org.apache.shiro.SecurityUtils" %>
<% SecurityUtils.getSubject().logout();%>
You have succesfully logged out.

Adicionar Autorização

Concluiremos esta primeira parte adicionando autorização à aplicação. Começamos limitando


o acesso às páginas aos usuários. Nenhum usuário deveria ser capaz de ver páginas de outros
departamentos. Fornecendo assim, somente segurança parcial ao projeto, pois o usuário ainda
é capaz de usar a página com “todas as funções da aplicação” ou editar o endereço (url) no
navegador para realizar qualquer ação. Nós a chamaremos de autorização em nível de página.

Então, limitaremos a habilidade dos usuários para realizar ações próprias. Mesmo que abra a
página com “todas as funções da aplicação” ou edite o endereço (url) no navegador, ele poderá
realizar somente funções específicas de seu departamento. Nós a chamaremos de autorização
em nível de função.

Novos requisitos: o usuário não é capaz de ver páginas de departamentos que não pertence. O
usuário é capaz de realizar somente funções de seu departamento. Uma exceção a essa regra
é o administrador, que pode realizar funções administrativas e de reparação.

P ágina de Autorização

Autorização em nível de página é feita com filtro de perfis(roles).


Parâmetro parte do filtro pode conter qualquer número de perfis. Usuário autenticado pode
acessar a página somente se ele tem todas os perfis fornecidos.

Como de costume, o filtro de perfis(roles) é configurado no arquivo Shiro.ini:

[urls]
# force ssl for login page
/simpleshirosecuredapplication/account/login.jsp=ssl[8443],authc

# only users with some roles are allowed to use role-specific pages
/simpleshirosecuredapplication/repairmen/**=authc, roles[repairman]
/simpleshirosecuredapplication/sales/**=authc, roles[sales]
/simpleshirosecuredapplication/scientists/**=authc, roles[scientist]
/simpleshirosecuredapplication/adminarea/**=authc, roles[Administrator]

# enable authc filter for the all application pages; as Shiro reads urls from up to down, must be last
/simpleshirosecuredapplication/**=authc

Teste se a segurança funciona: entre como um usuário de vendas, clique home, clique no link
‘repairmen page’. Você verá um erro feio.

Nós terminamos a página de autorização e substituimos o erro redirecionando-o para uma


página de erro. Os filtros pré-definidos do Shiro possuem a propriedade unauthorizedUrl. Em
caso de acesso não autorizado, o filtro redirecionará o usuário para um endereço (url)
específico.

[main]
# redirect to an error page if user does not have access rights
roles.unauthorizedUrl = /simpleshirosecuredapplication/account/accessdenied.jsp

accessdenied.jsp:
<body>
Sorry, you do not have access rights to that area.
</body>

Autorização de Funções

Todas as páginas departamentais estão protegidas agora. No entanto, qualquer usuário pode
ainda realizar qualquer função na página com “todas as funções da aplicação”. Além disso,
qualquer usuário autenticado pode editar endereço (url) e assim fazer qualquer ação. Por
exemplo, se você entrar como vendedor e colocar
https://localhost:8443/simpleshirosecuredapplication
/masterservlet?action=MANAGE_REPAIRMEN na url, a aplicação irá realizar a função gerenciar
reparadores também (e então irá dispará a exceção: null point, mas a violação de segurança já
foi feita).
Atribuimos uma úncia permissão para cada função. Elas estão divididas em grupos:

todas as permissões estão no grupo “functions”,

todas as permissões administrativas estão no grupo “manage”,

todas as permissões reparação estão no grupo “repair”,

todas as permissões venda estão no grupo “sale”,

todas as permissões ciência estão no grupo “science”.

Shiro suporta permissões de múltiplos níveis representadas como strings. Níveis são separados
com o símbolo ‘:’. p.e. “functions:manage:repairmen” tem três níveis: “functions”, “manage” e
“repairman”. Permissões de múltiplos níveis permitem facilmente o agrupamento de
permissões. Por exemplo, o grupo science pertence ao grupo functions e contém três
permissões:
functions:science:research,

functions:science:writearticle,

functions:science:preparetalk.

A classe Ações verifica as permissões do usuário autenticado(log in) antes de fazer seu
trabalho:
public String doIt() {
String neededPermission = getNeededPermission();
// acquire logged user and check permission
if (SecurityUtils.getSubject().isPermitted(neededPermission))
return "Function " + getName() + " run succesfully.";

throw new UnauthorizedException("Logged user does not have " + neededPermission + " permission");
}

NOTA: Outro modo de se alcançar o mesmo objetivo é através de anotações.

O servlet PerformFunctionAndGoBackServlet captura exceções de autorização e as converte em


mensagem de erro:

private String performAction(String actionName) {


try {
Actions action = findAction(actionName);
String result = action == null ? null : action.doIt();
log.debug("Performed function with result: " + result);
return result;
} catch (ShiroException ex) {
log.debug("Function failed with " + ex.getMessage() + " message.");
return "Error: " + ex.getMessage();
}
}

Finalmente, precisamos configurar as permissões para os perfis no arquivo Shiro.ini. Shiro


suporta curingas para permissões de múltiplo nível. Assim, não temos que especificar cada
permissão departamental em separado:

[roles]
# members of departments should be able to perform all departmental functions
sales=functions:sale:*
scientist=functions:science:*
repairman=functions:repair:*

# administrators are able to do all management functions and repair functions


Administrator=functions:manage:*,functions:repair:*

Você pode agora acessar a página “todas as funções da aplicação” e testar as funções.
Se um usuário autenticado não tiver a permissão requerida, uma mensagem de erro aparecerá
no topo da página. Além disso, se você fizer a autenticação (log in) como vendedor e tentar
hackear
https://localhost:8443/simpleshirosecuredapplication
/masterservlet?action=MANAGE_REPAIRMEN, você verá uma mensagem de erro no console (em
vez de uma mensagem de sucesso).

Fim

A aplicação final está disponível no ramo(branch) ‘static_authentication_and_authorization’


hospedado no Github.

Na segunda parte iremos criar um realm personalizado e mover usuários, senhas, perfis(roles)
e permissões do arquivo ini para um banco de dados.

Categories: Traduções Tags: Apache Shiro, Application Server, Autenticação, Autorização, Java,
maven, Proteção, Recursos de Segurança, traduções
Comments (2) Trackbacks (0) Leave a comment Trackback
Name (required)

E-Mail (will not be published) (required)

Website
Subscribe to comments feed

Top WordPress
Copyright © 2007-2011 Vivendo e Aprendendo …
Theme by NeoEase. Valid XHTML 1.1 and CSS 3.