Traduções

Por que Modelagem de Domínio?

0

Rebecca Wirfs-Brock. Why Domain Modeling?
[online] Disponível na Internet via WWW. URL: http://wirfs-brock.com/blog/2013/02/27/why-domain-modeling/. Arquivo capturado em 27 de fevereiro de 2013

Uma barreira ao considerar arquiteturas ricas em modelo de domínio é a ideia errônea do valor ou propósito de um modelo de domínio. Para alguns, criar um modelo de domínio parere retroceder à aqueles dias iniciais onde projeto e modelagem eram percebidas como atividades discretas, longas e muitas vezes improdutivas.

Quando a tecnologia objeto era jovem, vários autores fizeram uma forte distinção entre análise orientada a objeto, projeto orientado a objeto e programação. Ostensivamente, durante análise orientada a objeto você analisou uma tarefa com intuito de automatizá-la e desenvolveu um modelo conceitual (de objeto) daquele domínio. Você produziu um conjunto de descrições de tarefa e um modelo de objetos que incluiu representações de conceitos do domínio e mostrou como estes objetos interagiram para concluir algum trabalho. Mas você não conseguiu implementar diretamente estes objetos. Durante o projeto orientado a objeto você refinou esse modelo da análise de forma a considerar a implementação e restrições tecnológicas. Somente então, ao terminar o projeto, escreveria seu programa. A implicação era que qualquer modelo que você produzisse durante a análise ou projeto necessitaria ampla manipulação e refinamento antes de poder escrever seu programa.

Mas mesmo naqueles dias iniciais, muitos de nós borrou as linhas entre análise, projeto e programação orientada a objeto. Na prática, como trabalhávamos era frequentemente bem diferente do sugerido pela literatura popular daquele tempo. Podíamos analisar o problema, rapidamente esboçar algumas ideias de projeto e então implementá-las. Podíamos usar cartões CRC para modelar nossos objetos (os quais descartaríamos). Não havia lacunas distintas entre análise do problema e projeto e implementação da solução. Algumas vezes diferentes pessoas faziam análise enquanto outras o projeto e programação; mas muitas vezes um desenvolvedor faria todas essas atividades. Algumas vezes, criávamos representações permanentes de alguns modelos (além de nosso código). Isso dependia da situação e da necessidade.

Esses dias, raramente vejo alguém produzir análise de objeto ou modelos de projeto. Na verdade, projeto e modelagem tornaram-se algo sem sabor (ou de má reputação). Um bom projeto de objeto é considerado muito difícil por programadores “médios”, e não há tempo fora da codificação para pensar sobre o domínio e propor alguns modelos.

Os modelos de objeto mais comuns que vejo, são criados para um dos seguintes propósitos: pequenos modelos conceituais construídos para ganhar entendimento de uma funcionalidade significante; ou esboços de projeto informal com o intuito de fornecer uma visão rápida para recém-chegados ou pessoas que não leem código que necessitam “saber mais” do software. A falta de modelagem (a menos que você considere código e testes modelos – Eu não!) é predominante se ou não a equipe segue práticas ágeis. Os modelos mais comuns que vejo são modelos ER detalhados que são mais especificações de implementação do que modelos. Eles não deixam nenhum detalhe dificultando a busca de partes importantes.

Entender e descrever um domínio e criar qualquer modelo dele de algum forma, fica fora de muitas atividades de desenvolvimento.
Mas se seu software é complexo, sofre mudanças repentinas, estratégico e você não está fazendo nenhuma modelagem de domínio, você pode estar perdendo alguma coisa realmente importante. Se seu software é complexo o bastante, você pode notavelmente se beneficiar da modelagem de domínio e certamente realizar algumas atividades do Projeto Dirigido por Domínio(Domain-Driven Design).
Por exemplo, a “Estratégia de Projeto” do Projeto Dirigido por Domínio é um esforço consciente para criar um entendimento comum entre visionários do negócio, especialistas do domínio e desenvolvedores. Discussões de domínio iniciais de alto nível leva ao entendimento do que é central ao problema(o núcleo do domínio) e ao relacionamento entre todas as partes(subdomínios) que se interagem. Ganhar tal consenso te ajuda a manter o foco em melhores práticas de projeto e estruturar (ou restruturar) seu software habilitando-o a crescer e evoluir sustentavelmente.
Mas não para por aí. Se você compra a ideia de modelagem de domínio, você também se compromete a desenvolver um profundo compartilhamento do entendimento do domínio do problema ao lado do seu código. Sua missão não é somente entregar operações funcionais, mas incorporar conhecimento do domínio em sua solução. Seu código terá objetos que representam conceitos do domínio. Você será mais minucioso ao nomear classes e métodos, assim refletindo exatamente a linguagem do domínio. Você terá discussões progressivas com especialistas de domínio e em conjunto discutir e refinar seu entendimento do domínio. Ao longo do caminho você pode rascunhar e revisar modelos de domínio. Se esforçará para identificar, preservar, fortalecer e tornar explícito as conexões entre o problema do negócio e seu código. Quando refatorar seu projeto ao ganhar mais entendimento, você não esquecerá de refletir o domínio em seu código. Seu modelo de domínio vive e evolui junto com o código.
Como consequência, não há aquela grande desconexão entre o que você codifica e o que o negócio diz. E essa pode ser uma poderosa força para uma colaboração mais próxima entre desenvolvedores e especialistas do domínio.

Java Concorrent na Prática

Java Concorrente na Prática – crítica

4

Para um livro já consagrado, uma boa tradução seria o mínimo. Mas lamento relatar que o profissional escolhido para tal tarefa deixou muito a desejar. Quem fez a revisão editorial do livro – se é que o fez – , também, não realizou um bom trabalho. É nítido, a partir do primeiro capítulo, o descaso com o leitor. Um exemplo explícito disto é você ver em várias partes do livro a operação de copiar e colar, ou melhor de substituição de texto: o tradutor ou editor, substituiu a sigla GUI por Grafical User Interface onde pode, assim, onde houvesse seGUIR, conseGUIR, etc. encontramos conseGUI(Grafical User Interface). Legal né!

Bom, vou parar por aqui. Não vou nem mencionar a coerência textual, caso contrário a editora teria que me ressarcir por essa “obra”.


Apache Shiro Parte 1 – básico

2

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


ATUALIZAÇÃO: duas novas seções adicionadas – tratamento de erros e hashing de senhas.

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></td>
        </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

Atualizaçã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, nenhuma mensagem de erro razoável é mostrada se o usuário comete um erro. Além disso, as senhas são armazenadas em arquivo texto.

Tratamento de Erro

Se o usuário comete um erro ao fazer a autenticação (log in), o Shiro o redireciona de volta para a página de login. A página parece exatamente a mesma de antes, o que pode confundir o usuário.

Novo requerimento:
Mostrar mensagem de erro após cada tentativa de autenticação(log in) sem êxito.

Toda vez que ocorrer um erro de autenticação, uma exceção é lançada. Por definição, o filtro de autenticação captura a exceção e armazena nome da classe (exceção) em um parâmentro da requisição (request). Como desejamos personalizar os dados enviados à página, teremos que estender o filtro pré-definido FormAuthenticationFilter e sobrescrever o método setFailureAttribute:

@Override
protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {
  String message = ae.getMessage();
  request.setAttribute(getFailureKeyAttribute(), message);
}

Substitua o filtro pré-definido FormAuthenticationFilter por VerboseFormAuthenticationFilter e o configure para usar o atributo de requisição (request) ‘simpleShiroApplicationLoginFailure’ para armazenar a informação do erro:

[main]
# replace form authentication filter with verbose filter
authc = org.meri.simpleshirosecuredapplication.servlet.VerboseFormAuthenticationFilter
# request parameter with login error information; if not present filter assumes 'shiroLoginFailure'
authc.failureKeyAttribute=simpleShiroApplicationLoginFailure

Mostrar o erro na página login.jsp:

<%
  String errorDescription = (String) request.getAttribute("simpleShiroApplicationLoginFailure");
  if (errorDescription!=null) {
%>
Login attempt was unsuccessful: <%=errorDescription%>
<%
  }
%>

Cuidado: uma aplicação real não deve apresentar muitas informações de erro de autenticação. Uma mensagem como “tentativa de logon sem sucesso.”, com nenhuma informação adicional é geralmente suficiente.

Hashing de Senhas

Na versão atual da aplicação, todas 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 trasnformada(hashing) 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 trasnformadas(hashing):

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

Nota: não é 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.

Go to Top