Arquivo

Archive for the ‘Segurança’ Category

O Problema da Galeria de Arte

Figura 1 – Visibilidade de uma câmera em uma galeria de arte [1]

A Geometria Computacional [2] é um ramo da Matemática que busca soluções computacionais para problemas geométricos. Galeria de Arte é um problema derivado da Geometria Computacional proposto originalmente por Victor Klee em 1973 [1] que oferece uma resposta matemática para a pergunta: qual é a quantidade mínima de câmeras de vigilância necessárias para monitorar inteiramente uma Galeria de Arte? Essa é a forma mais comum de formular esse problema, mas ele se aplica a qualquer cenário em que exista um ambiente delimitado por paredes e que precisa ser monitorado – seja por câmeras de segurança, vigias armados com posição fixa, unidades ED-209, etc – de forma que não sobrem quaisquer partes do ambiente sem monitoramento.

Figura 2 – Onde as câmeras devem ser posicionadas?

Para tornar as coisas um pouco mais simples, vamos trabalhar em duas dimensões (2D) assumindo que a planta baixa da galeria de arte é um polígono simples: uma forma geométrica delimitada por seguimentos de linhas retas que não cruzam umas as outras – não tem paredes internas – e que não contém “buracos” (polígonos dentro de um polígono maior ou o possível resultado da intersecção interna de pelo menos três linhas). Sendo uma câmera um ponto, um conjunto de câmeras cobre o polígono se todo ponto do polígono é monitorado por alguma câmera [1]. Se fossem vigilantes e não câmeras, assumiríamos que eles ficam fixos nos vértices (ponto de encontro de dois segmentos laterais).

Isso normalmente é válido nas galerias de arte, pois as obras de arte ficam nas paredes (arestas ou seguimentos de reta do polígono) e teoricamente uma câmera deveria filmar a máxima extensão de uma parede e a máxima quantidade de paredes possível, o que só se consegue posicionando as câmeras nos vértices. As obras raras não se enquadram nessa regra, pois devido ao seus valores às vezes inestimáveis, como no caso da Mona Lisa, é necessária vigilância exclusiva independente de quanto isso custe.

Figura 3 – Mona Lisa – obra insubstituível

Matematicamente, dado um conjunto de câmeras C, uma câmera cn vigia um polígono P se existe um segmento de reta que liga a câmera ao ponto p e tanto o segmento de reta quanto o ponto p são internos ao polígono:

C{c1, c2, c3, …, cn} → p ∀ p ∈ C | cp ∈ P

Como a planta baixa da galeria é um polígono, o problema consiste em colocar pontos nesse polígono e à partir deles traçar linhas para as paredes opostas sem sair do polígono, que pode ser convexo (aquele em que dois pontos quaisquer, quando unidos, nunca passam pelo lado de fora do polígono) ou não convexo. Um polígono convexo precisa apenas de uma câmera, pois sua simetria permite que de um dos vértices se possa enxergar todos os outros vértices:

Figura 4 – Octógono – um polígono convexo regular (todos os lados e ângulos têm a mesma medida) de oito lados

Para que o problema se apresente de forma mais genérica, vamos trabalhar com polígonos não convexos, como o da figura abaixo, pois são mais comuns de encontrar do que os convexos:

Figura 5 – Um polígono não convexo

O Teorema de Chvátal diz que para todo polígono de n vértices, n/3 câmeras são sempre suficientes e ocasionalmente necessárias. Para o Pente de Chvátal, n/3 câmeras são necessárias. Como o pente abaixo tem 15 vértices, 5 câmeras são necessárias para monitorar sua área interna:

Figura 6 – Pente de Chvátal com 15 vértices

Além do Teorema de Chvátal, os teoremas abaixo serão utilizados no exemplo que apresentaremos a seguir:

  • Todo polígono possui pelo menos um vértice estritamente convexo.
  • Teorema de Jordan: toda curva plana fechada simples divide o plano em duas regiões: o interior e o exterior da curva.
  • Teorema de Meister: Todo polígono com n ≥ 4 vértices possui uma diagonal.
  • Teorema da Triangularização: Todo polígono n vértices pode ser particionado em triângulos pela adição de (zero ou mais) diagonais.
  • Toda triangularização de um polígono P de n vértices usa n − 3 diagonais e consiste de n − 2 triângulos.

Demonstração

Para fazer uma demonstração, vou utilizar o exemplo do canal Derivando e a didática do prof. Eduardo Sáenz de Cabezón, PhD em Matemática e também professor de Matemática Discreta e Álgebra pela Universidad de La Rioja, na Espanha.

O exemplo do prof. Eduardo faz triangularização por adição de diagonais para dividir o polígono internamente em n triângulos – essa é a Prova de Suficiência de Fisk. O problema seria um pouco mais complexo se o prof. tentasse remover as “orelhas” com triangularização por remoção de orelhas [1], o que é possível pelo teorema de Meister, mas vamos ficar no caso mais simples – adição de diagonais -, que vale para qualquer polígono com mais de 3 lados, pois o triângulo (3 lados) é o único polígono que não possui diagonais (N<4) e uma câmera colocada em qualquer um dos vértices pode monitorar todo o perímetro interno, uma vez que ele respeita a regra das n/3 câmeras – como ele tem 3 lados, uma câmera é suficiente e no caso necessária.

Nossa demonstração partirá de um polígono não convexo com 10 lados e 10 vértices:

Vamos triangular esse polígono, pois sabemos que todo polígono com mais de três lados pode ser triangulado pela adição de diagonais. Necessariamente, encontraremos 8 triângulos, pois para triangular um polígono de 10 lados, precisamos de (10-2) triângulos:

Agora, vamos construir um grafo dual colocando um vértice em cada face de cada triângulo e unindo todos esses vértices. Esse grafo serve apenas para verificar se os triângulos inscritos no polígono podem ser 3-colorados. Só haverá 3-coloração se o grafo for do tipo árvore e não cíclico:

Por último, vamos aplicar a 3-coloração aos triângulos inscritos. O processo consiste em escolher três cores diferentes e pintar cada vértice com uma cor sem que dois vértices adjacentes tenham a mesma cor:

Enfim, onde serão instaladas as câmeras? Vamos fazer algumas considerações. O Teorema de Chvátal afirma que (n/3) câmeras são suficientes e ocasionalmente necessárias para cobrir a área interna do polígono. No nosso caso, 3 câmeras (10/3) são suficientes, mas ainda não sabemos se as 3 são necessárias.

As câmeras serão posicionadas em todos os vértices de mesma cor. Podemos instalar 4 câmeras nos vértices vermelhos, 4 câmeras nos vértices azuis ou apenas 2 câmeras nos vértices verdes. 2 é o mínimo de câmeras que precisamos para monitorar toda a área interna do polígono. Sendo assim, precisamos de apenas 2 câmeras e essas serão instaladas nos vértices verdes:

Essa é uma prova de que sempre podemos economizar recursos utilizando matemática. Dificilmente conseguiríamos um resultado melhor no chute, como provei em outro artigo.

Referências

1. [https://www.ime.usp.br/~cpq/main/arquivos/teoremadagaleriadearteetriangularizacaodepoligonos.pdf]
2. [http://webserver2.tecgraf.puc-rio.br/ftp_pub/lfm/CIV2802-GeometriaComputacional.pdf]
3. [https://brilliant.org/wiki/guarding-a-museum/]
4. [https://plus.maths.org/content/art-gallery-problem]
5. [https://www.youtube.com/watch?v=nEFYpwofbbk]
6. [http://sweet.ua.pt/leslie/GeoCom/Slides/GC_0708_6_Galeria_Arte.pdf]
7. [http://www.ic.unicamp.br/~rezende/ensino/mo619/ArtGallery-PJR-Handout.pdf]
8. [http://www.inf.ufrgs.br/~comba/cmp189-files/class03.pdf]
9. [https://www.inf.ufrgs.br/~prestes/Courses/Graph%20Theory/GrafosA10.pdf]
10. [https://www.ime.usp.br/~cris/aulas/09_2_331/slides/aula3.pdf]

Anúncios

Como Habilitar o Ehcache no Shiro

O Shiro oferece um mecanismo de cache para diminuir o tempo de respostas das operações de segurança, mas as implementações disponibilizadas podem ser utilizadas para propósitos fora do escopo do framework de segurança.

Figura 1 – Arquitetura do Shiro

Várias implementações do CacheManager estão disponíveis. Nesse artigo, mostraremos como habilitar o EhCacheManager, o que permite utilizar o Ehcache. Antes de continuar, sugiro que você veja o artigo de introdução ao Shiro que escrevi e um outro artigo sobre a integração do Ehcache ao Spring, onde faço algumas considerações sobre o cache em si.

Comecemos pela configuração das dependências do Maven:

   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
   </dependency>
   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.3.1</version>
    </dependency>  
    <dependency>
      <groupId>javax.cache</groupId>
      <artifactId>cache-api</artifactId>
      <version>1.0.0</version>
    </dependency>

Em seguida, vamos configurar o arquivo shiro.ini

[main]
[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

Uma vez definido um CacheManager, o Shiro o entrega para as classes que implementam a interface CacheManagerAware. Nosso AppRealm é um SimpleAccountRealm. Sendo assim, já estamos implementando aquela interface.

Referências

1. [https://shiro.apache.org/caching.html]
2. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/Cache.html]
3. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/ehcache/EhCacheManager.html]
4. [http://www.ehcache.org/]

Criando sua Própria Tag Library do Shiro

Se você precisa de mais granularidade na checagem de permissões em uma página web, como por exemplo determinar se um botão deve ou não ser exibido, o Shiro oferece uma API que te permite fazer sua implementação nos métodos do seu controller/managed bean – não faça scriplets! No exemplo do botão, você poderia condicionar sua exibição assim:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui">
   <body>
      <p:commandLink action="#{appMB.executar()}" 
          rendered="#{appMB.podeExecutar()}">Executar</p:commandLink>
   </body>
</html>

A implementação do método podeExecutar() utiliza a API do Shiro para verificar se o usuário tem determinada permissão:

public boolean podeExecutar() throws IOException {
   Subject subject = SecurityUtils.getSubject();
   return subject.isPermitted("PERMISSAO_EXECUCAO");
}

O problema é que você tende a reescrever esse mesmo código ou um muito parecido em cada managed bean que precisar de autorização. Felizmente, o Shiro possui uma tag library útil para quem trabalha com arquivos JSP, mas se você trabalha com JSF, não há nada pronto para utilizar. Porém, é possível criar sua própria biblioteca reutilizável à partir daquele código de checagem que você inseriu no managed bean. Vamos definir a assinatura de uma tag chamada “hasPermissao” que receba como parâmetro uma permissao:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
   version="2.2"
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
   http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
   <namespace>http://app.com.br/security</namespace>
   <tag>
      <description><![CDATA[Verifica a permissao do usuario]]></description>
      <tag-name>hasPermissao</tag-name>
      <component>
         <component-type>permitido</component-type>
      </component>
      <attribute>
         <description><![CDATA[Permissao a ser verificada.]]></description>
         <name>permissao</name>
         <required>true</required>
         <type>java.lang.String</type>
      </attribute>
   </tag>
</facelet-taglib>

Uma vez criada a biblioteca, ela deve ser cadastrada no web.xml:

<context-param>
   <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
   <param-value>/WEB-INF/app.taglib.xml</param-value>
</context-param>

Em seguida, vamos criar uma classe que extende UIComponentBase e é anotada como @FacesComponent. Essa implementação “esconde” todos os componentes visuais delimitados pela tag caso o usuário não esteja autorizado:

@FacesComponent(createTag = true, 
   namespace = "http://app.com.br/security", 
   tagName = "hasPermissao", 
   value = "hasPermissao")
public class PermissaoTag extends UIComponentBase {

   @Override
   public String getFamily() {
      return "app";
   }

   @Override
   public void encodeBegin(FacesContext context)
      throws IOException {
      String permissao = (String)getAttributes().get("permissao");
      Subject subject = SecurityUtils.getSubject();
      if (!subject.isPermitted(permissao)) {
         getChildren().stream().forEach(
            s -> s.setRendered(false));
      }
   }
}

Por último, importe a tag em seu arquivo xhtml e utilize no trecho de código sujeito à autorização:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui"
   xmlns:app="http://app.com.br/security">
   <body>
     <app:hasPermissao permissao="PERMISSAO_EXECUCAO">
       <p:commandLink action="#{appMB.executar()}">Executar</p:commandLink>
     </app:hasPermissao>
   </body>
</html>

Referências

1. [https://www.mkyong.com/jsf2/custom-tags-in-jsf-2-0/]
2. [https://shiro.apache.org/web.html#Web-taglibrary]
3. [https://shiro.apache.org/java-authorization-guide.html#programmatic-authorization]

Como Integrar o Apache Shiro a uma Aplicação JSF

O Shiro é um framework de segurança da Apache escrito em Java que permite a criação de soluções para autenticação, autorização, criptografia, gerenciamento de sessão e ainda fornece várias implementações de cache. Ele é simples de configurar e tem vários pontos de extensão que nos permitem intervir sobre seu funcionamento – são características de um framework bem projetado -, mas as configurações padrão já são suficientes para uma aplicação de pequeno porte.

Figura 1 – Arquitetura do Shiro

Nesse artigo, vou mostrar um exemplo de como integrar o Shiro a uma aplicação JSF. Nosso modelo será composto por uma enum chamada Permissao, uma enum Perfil para agrupar as permissões, e a entidade Usuario, que possui um Perfil:

public enum Permissao {
   CRIAR_PEDIDO, 
   LISTAR_PEDIDOS;
}

public enum Perfil {
   ADMINISTRADOR(Permissao.CRIAR_PEDIDO, Permissao.LISTAR_PEDIDOS);
   private List<Permissao> permissoes;
   private Perfil(Permissao... permissoes) {
      this.permissoes = Arrays.stream(permissoes).
         collect(Collectors.toList());
   }
}

@Entity
@Table(name = "TBL_USUARIO")
@TypeDefs(value = {@TypeDef(name = "TIPO_PERFIL" ...)})
public class Usuario {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_USUARIO")
   private Long id;
   @Column(name = "NM_USUARIO")
   private String nome;
   @Column(name = "COD_PERFIL")
   @Type(type = "TIPO_PERFIL")
   private Perfil perfil;
}

Há várias formas de configurar o Shiro. Vou mostrar como configurá-lo à partir do arquivo de configuração shiro.ini. Precisamos incluir duas dependências no arquivo pom.xml – isso é o básico para o Shiro ser integrado a uma aplicação web:

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.3.2</version>
</dependency>
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.3.2</version>
</dependency>

Em seguida, vamos configurar o arquivo shiro.ini, que deve ficar no classpath – eu costumo colocar em /src/main/resources. As seções desse arquivo agrupam propriedades que determinam o comportamento do Shiro. Basicamente, informamos qual é o Realm utilizado (será explicado mais adiante), qual é a página de autenticação para a qual o Shiro redirecionará o usuário não autenticado, para onde o usuário será redirecionado após o logout e também permite que informemos que há páginas privadas que só podem ser acessadas por usuários que tenham determinadas permissões. No nosso exemplo, a página “criarpedido.xhtml” só pode ser acessada por usuários que contenham a permissão “CRIAR_PEDIDO”.

[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
authc.loginUrl = /publico/index.xhtml
logout.redirectUrl = /publico/index.xhtml

[users]

[roles]
ADMINISTRADOR = *

[urls]
/privado/criarpedido.xhtml =  authc, perms["CRIAR_PEDIDO"]

No arquivo web.xml, configuraremos os filtros e listeners do Shiro e também informaremos quais são as páginas que responderão pelos códigos de erro HTTP.

<filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>

<listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener
</listener-class>
</listener>
	
<error-page>
   <error-code>401</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>403</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>404</error-code>
   <location>/publico/paginanaoencontrada.xhtml</location>
</error-page>

<error-page>
   <error-code>500</error-code>
   <location>/publico/erro.xhtml</location>
</error-page>

Essa é toda a configuração básica que qualquer aplicação web precisa para ser integrada ao Shiro. De agora em diante, começaremos a implementação do nosso mecanismo de autenticação e autorização. Só então você verá como é simples trabalhar com o Shiro. Uma peça importante do mecanismo de autenticação é o AuthenticationToken, que é a classe que mantém as credenciais do usuário. Você pode escolher uma das implementações dessa interface disponíveis, mas vamos criar uma implementação dela que recebe o ID do usuário:

public class IdAuthenticationToken implements AuthenticationToken {
   private Integer userId;

   public IdAuthenticationToken(Integer userId) {
      this.userId= userId;
   }

   @Override
   public Object getPrincipal() {
      return this.id;
   }

   @Override
   public Object getCredentials() {
      return this.id;
   }
}

Você precisará informar ao Shiro que um usuário está se autenticando. Você pode fazer isso à partir de um servlet, campos de input em um formulário de uma tela que é tratada por um ManagedBean, etc. Eu fiz através de um servlet porque antes que o usuário se autenticasse na minha aplicação era feita client authentication contra um Apache Server para validar o certificado digital. Modifiquei um pouco o código para indicar que as credenciais do usuário estão vindo pela request, que no meu caso era um post realizado pela aplicação que rodava em um JBoss debaixo daquele Apache. A credencial é apenas o atributo “userId”, que foi fornecido pela aplicação que validou o certificado digital.

@WebServlet(displayName = "AutenticacaoServlet", 
   name = "AutenticacaoServlet", urlPatterns = "/autenticar")
public class AutenticacaoServlet extends HttpServlet {

protected void doPost(HttpServletRequest request, 
      HttpServletResponse response)
     throws ServletException, IOException {
   Integer userId = (Integer) request.getAttribute("userId");
   Subject subject = SecurityUtils.getSubject();
   subject.login(new IdAuthenticationToken(token, userId));
   subject.checkPermission("CRIAR_PEDIDO");

   response.sendRedirect(request.getContextPath() + 
      "/private/criarpedido.xhtml?faces-redirect=true";

O Realm é um componente que interpreta os artefatos de segurança da aplicação – como usuários, regras e permissões – para o Shiro. Sendo o Realm a fonte de dados para autorização, podemos dizer, grosso modo, que ele é o DAO, ou melhor, um repository, que serve um modelo de autorização e autenticação.

Figura 2 – Sequência Simples de Autenticação

public class AppRealm extends SimpleAccountRealm {

   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(
       AuthenticationToken token) throws AuthenticationException {
      IdAuthenticationToken authToken = (IdAuthenticationToken) token;
      Optional<Usuario> usuario = usuarioDao.buscar(token.getUserId());
      return new SimpleAuthenticationInfo(
         usuario.get(), usuario.get().getId(), getName());
   }

   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {
      Set<String> roles = new HashSet<>();
      Set<String> permissions = new HashSet<>();

      Usuario usuario = (Usuario) SecurityUtils.getSubject().getPrincipal();
      Perfil perfil = usuario.getPerfil();

      roles.add(perfil.name());

      perfil.getPermissoes().forEach(a -> {
         permissions.add(a.nome());
      });

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
      info.setRoles(roles);
      info.setStringPermissions(permissions);
      return info;
   }

   @Override
   public String getName() {
      return getClass().getName();
   }

   @Override
   public boolean supports(AuthenticationToken token) {
      return IdAuthenticationToken.class.equals(token.getClass());
   }
}

Utilizamos a implementação SimpleAccountRealm, que é suficiente para o que nos propusemos a fazer. Se você quiser que o Shiro fique automaticamente consultando o banco de dados para carregar as permissões, basta utilizar um JdbcRealm e adicionar a consulta que o Shiro deve utilizar no arquivo shiro.ini.

Nesse momento, já temos um mecanismo que gerencia as credenciais do usuário e autoriza o acesso às páginas informadas na configuração inicial. Se você precisar fazer checagens de permissão ou verificar se o usuário está autenticado programaticamente, você deve acessar o Subject através do SecurityUtils ou utilizar as anotações do Shiro nos métodos das suas classes que devem ser autorizados.

Recomendações para Migração de Aplicações JSF “Puras”

Se você tem uma implementação de PhaseListener que de alguma forma toma decisões com base na URL acessada em sua aplicação JSF, remova-a. Na verdade, você deveria remover filtros, servlets e quaisquer outras implementações interessadas em autorização. Quem cuidará disso é o Shiro – mais especificamente a sua implementação de Realm.

É comum que aplicações JSF tenham uma ExceptionHandlerFactory para interceptar e tratar exceções nas páginas. Isso também não será necessário, pois o Shiro contém a ShiroException e suas variantes. Você também pode definir páginas específicas para tratar os códigos de erro HTTP mapeadas no seu arquivo web.xml.

Referências

1. [http://shiro.apache.org/reference.html]
2. [https://shiro.apache.org/java-authorization-guide.html]
3. [https://shiro.apache.org/authorization.html]
4. [https://shiro.apache.org/architecture.html]
5. [https://shiro.apache.org/configuration.html]
6. [http://galluzzo.com.br/?p=698]
7. [https://dzone.com/articles/java-security-framework-apache]
8. [http://czetsuya-tech.blogspot.com/2012/10/how-to-integrate-apache-shiro-with.html]
9. [http://www.javastutorial.com/2016/03/how-to-use-apache-shiroauthentication.html]

Como Gerar o Checksum de um Arquivo

Como expliquei no artigo Criptografia de Senha em Java, uma função de hash gera uma cadeia de caracteres de tamanho fixo a partir de uma sequência de qualquer tamanho; é uma equação matemática que a partir de um texto cria um código chamado message digest (resumo de mensagem), que é o resultado retornado por uma função de hash. Este pode ser comparado a uma impressão digital, pois cada documento possui um valor único de resumo e até mesmo uma pequena alteração no documento, como a inserção de um espaço em branco, resulta em um resumo completamente diferente.

Naquele artigo, mostrei como criptografar um texto utilizando o SHA-256, que é a variante mais utilizada do SHA-2. O código abaixo utiliza outros algoritmos (ou funções hash) para gerar o message digest do conteúdo de um arquivo qualquer. Quando esse resultado é utilizado para checar se um arquivo é genuíno e isento de erros, ele passa a ser chamado de hash sum ou mais popularmente de checksum:

public static void main(String[] args) throws Exception {
   byte[] fileBytes = Files.readAllBytes(Paths.get("/path/my_file.war"));
   Arrays.asList("MD5", "SHA-1", "SHA-256", "SHA-512").forEach((alg) -> {
      try {
         MessageDigest algoritmo = MessageDigest.getInstance(alg);
         byte digestMessage[] = algoritmo.digest(fileBytes);
         System.out.println(alg);
         System.out.println(new HexBinaryAdapter().marshal(digestMessage));
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
      }
   });
}

Utilizei o HexBinaryAdapter do Java, mas você poderia utilizar o Hex.encodeHexString(…) do Apache Commons ou ainda poderia converter os bytes para a versão hexadecimal manualmente byte-a-byte, assim:

(...)
StringBuilder hexPassword = new StringBuilder();
for (byte aByte : digestMessage) {
   hexPassword.append(String.format("%02X", 0xFF & aByte));
}
System.out.println(hexPassword.toString());

Alternativas

Se você só precisa do checksum e estiver utilizando Windows, você poderia baixar o FCIV da Microsoft, que pelo menos é um utilitário de linha de comando, ou o Hash Calculator, que mostra os checksums de forma gráfica. O FCIV é bem simples de utilizar:

C:\>fciv -SHA1 {ARQUIVO}

Referências

1. [http://howtodoinjava.com/core-java/io/how-to-read-file-content-into-byte-array-in-java/]
2. [http://www.adam-bien.com/roller/abien/entry/java_8_reading_a_file]
3. [http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest]
4. [http://www.devmedia.com.br/como-funciona-a-criptografia-hash-em-java/31139]
5. [https://www.lifewire.com/what-does-checksum-mean-2625825]

Uma Breve História das Moedas Virtuais

A história do dinheiro revela um desafio central: como desenvolver um sistema que possa efetivamente facilitar o intercâmbio de bens e serviços ao mesmo tempo que gera prosperidade e impede que as instituições que o administram abusem da confiança decorrente dessa função? No terceiro episódio da série O Futuro das Instituições Financeiras, Jim Kittridge apresentou uma Breve História das Moedas Virtuais. Curiosamente, essa história começa no século XIX. Antes de tratarmos das moedas virtuais, precisamos entender o que é uma moeda real e o que a faz ter um valor real.

A Moeda Fiduciária

Você já pensou quanto realmente vale uma cédula de Real em sua carteira? O valor real daquele pedaço de papel não é o que está estampado, mas sim o contrato que ele representa. Para que qualquer moeda se torne viável, é necessário que ela conquiste a confiança da comunidade: as pessoas devem concordar que o dinheiro pode ser trocado por bens e serviços. No caso das criptomoedas, a confiança deve ser independente de agentes governamentais ou financeiros.

Como podemos confiar no valor intrínseco da moeda? Um caminho é atrelá-la à um produto valioso, escasso e durável como o ouro – isso é chamado de lastro. Estando atrelada (lastreada), a moeda não fica tão suscetível à inflação. O valor de um bem está atrelado a diversos fatores, dentre eles a importância deste para o mercado e o quanto as pessoas estão dispostas a pagar pela mercadoria. Isso tudo se encontra dentro de uma sistemática ligada à oferta e a demanda.

De 1944 a 1971 o valor do dólar era fixado em US$ 35.00 por 31,1034768 gramas de ouro de acordo com o sistema de Bretton Woods. O sistema acabou em 1971, quando o presidente Richard Nixon cancelou a conversibilidade do dólar em ouro, deixando o câmbio flutuante e acabando com qualquer lastro do papel-moeda.

Moeda real ou fiduciária (fiat money) é qualquer título emitido por um governo central ou instituição financeira que seja não-conversível, ou seja, que não seja lastreado a nenhum metal (ouro, prata) e não tenha nenhum valor intrínseco [2]. Seu valor advém da confiança (fidúcia, do latim fidere, confiar) que as pessoas têm em quem emitiu o título. A moeda fiduciária pode ser uma ordem de pagamento (cheques, por exemplo), títulos de crédito, notas promissórias, ou qualquer documento que você poderia aceitar como pagamento, confiando que, depois, o tal documento seria aceito como pagamento de outro produto ou serviço por outra pessoa ou empresa.

fiatmoney

Figura 1 – Moedas fiduciárias (fiat money)

Por exemplo, você aceita um cheque de R$ 500,00 pois sabe que tem fundos e que poderá utilizá-lo para pagar outra coisa. Não importa que seja apenas um pedaço de papel sem valor próprio, você confia que essa nota será aceita por qualquer pessoa, instituição ou comércio do Brasil como uma forma de pagamento. O Real é uma moeda de curso forçado, ou seja, uma pessoa não pode se negar a aceitá-lo como método de pagamento. O governo garante assim o valor da moeda como meio de troca e consegue criar dinheiro sem precisar de um ativo – como ouro – para servir de lastro [2].

As Primeiras Moedas Ditas Virtuais: Quem Iria Imaginar?

O Bitcoin não foi a primeira moeda virtual. Na verdade, não está nem próximo de ser a primeira. Além disso, as primeiras moedas virtuais tinham, contraintuitivamente, existência física. Você precisa voltar até 1896 para encontrar a primeira, que era chamada Selo S&H e foi lançada pela empresa Sperry and Hutchins. Os selos S&H eram vendidos em postos de gasolina e em supermercados que os davam como bonificação aos compradores que podiam então resgatar mercadorias específicas em um catálogo da S&H. Nos anos 60, a empresa tinha emitido 3 vezes mais selos que o serviço postal dos EUA. Na década de 70, a S&H alterou seu curso de um modelo de negócios baseado em selos e começou a entrar em declínio. Isso ocorreu porque a competição de grandes corporações cortou o intermediário, que era a própria S&H.

4fd2fa5b73f4cc14622ef6804c4ed8e5

Figura 2 – Selos S&H

A próxima moeda virtual a causar entusiasmo teve início em 1981 quando a American Air Lines lançou o American Advantage (AAdvantage), que foi o primeiro programa de milhagens aéreas. Hoje, toda companhia aérea e até mesmo empresas de aluguel de carros e a maior parte dos hotéis (EUA) oferecem alguma versão do programa de milhagem. Em 2005, a revista The Economist estimou que o valor total das milhas não resgatadas valia mais que todas as cédulas de dólar em circulação. As milhas aéreas são vendidas a preços razoáveis por milha e podem ser gastas em um número crescente de estabelecimentos e em uma infinidade de serviços – até mesmo para pagar por funerais! Ao longo dos últimos dez anos, as companhias aéreas fizeram mais dinheiro vendendo essa moeda virtual para companhias de cartões de crédito e hotéis do que realmente fizeram pelos vôos em si.

Uma outra moeda que tem crescido rapidamente, embora pouco usual, está na África. Uma vez que poucas pessoas na África dispõem de uma conta bancária e as moedas locais têm imensas volatilidades, as pessoas estão se voltando para seus celulares, que têm uma significativa penetração de mercado e estão usando minutos pré-pagos como moeda. Isso se tornou um negócio de bilhões de dólares por ano. A maior parte dos comércios e dos logistas aceitam minutos pré-pagos de boa vontade. Existem até mesmo empresas como a Ezetop, em Dublin na Irlanda, para ajudar os clientes a comprarem e venderem minutos e enviá-los para qualquer lugar do mundo. Minutos podem ser enviados internacionalmente via Internet ou mensagens SMS e são aceitos em mais de 450 mil estabelecimentos em mais de 20 países.

Pensando assim, de forma tão abrangente, muitas coisas podem ser consideradas moedas virtuais desde que todos concordem com o valor atribuído à coisa que se tornou moeda: escambo, comércio de vale refeição e vale transporte (muito comum na década de 90 quando eram emitidos em papel), latas de leve-leite (comum na cidade de São Paulo também na década de 90) e até sanduíches de presunto no caso do Chaves.

Agora Sim, as Moedas Virtuais do Jeito que Você Imagina

Uma moeda virtual não é emitida por nenhum governo. Ela é emitida por qualquer entidade onde um conjunto de usuários concorde sobre qual valor ela tem. Pode-se concluir que as moedas virtuais não tem “valor real”, mas que valor uma moeda fiduciária emitida pelo governo oferece que está além de um valor combinado por todos os usuários? Em muitos aspectos, todo o dinheiro fiduciário somente se distingue do dinheiro virtual porque nós, usuários, concordamos em um valor relativamente estável.

O Bitcoin não é sequer a primeira moeda online. Esse título pertence à empresa E-gold, que foi fundada em 1996. E-gold era uma moeda virtual lastreada por ouro real, algo com o qual nem mesmo as moedas fiduciária podem contar hoje em dia. Era o mesmo que negociar a propriedade do ouro de forma anônima. Em seu pico em 2008, o E-gold tinha mais de 5 milhões de contas. Contudo, sistemas de segurança fracos contribuíram para seu desaparecimento em 2009. Beenz, Flooz e Qcoins eram moedas online que surgiram depois do E-gold, mas tiveram os mesmos problemas de segurança. No caso do Qcoins (China), houve problemas com o governo que causaram sua vida curta.

No final de 2008, duas novas moedas de alto potencial foram lançadas. Bitcoin e Facebook Credits. Ambas apresentaram propostas para resolver os problemas de segurança das tentativas anteriores, mas de maneiras totalmente distintas. O Facebook Credits enfrentou uma morte prematura em 2012, não por causa de segurança ou fraude, mas porque só podia ser gasto dentro do Facebook, que na época era bem menor do que é hoje.

facebook-credits

Figura 3 – Facebook Credits

Em outubro de 2008, sob o pseudônimo de Satoshi Nakamoto, Craig Wright lançou um artigo técnico na Internet [6] em que ele propôs uma versão puramente ponto-a-ponto do dinheiro eletrônico e que garantia a segurança através de sofisticada técnica de encriptação baseada em um modelo matemático. Assim nasceu o Bitcoin, uma criptomoeda segura e um sistema de pagamento online baseado em protocolo de código aberto que é independente de qualquer autoridade central.

images

Figura 4 – Bitcoin

No âmbito da moeda virtual Bitcoin, um blockchain é a estrutura de dados que representa uma entrada de contabilidade financeira ou um registro de uma transação. Cada transação (bloco) é digitalmente assinada com o objetivo de garantir sua autenticidade e garantir que ninguém a adultere de forma que o próprio registro e as transações existentes dentro dele sejam considerados de alta integridade [10] – esses são alguns dos pilares da segurança da informação. Essa idéia foi, provavelmente, inspirada no conceito de autoridades certificadoras utilizado no mundo dos certificados digitais. Essa segurança nas transações dificultava muito a cópia do dinheiro. O conceito de bloco é a fundação que alicersa o Bitcoin e é conhecida como Blockchain.

1-newfxaocasu-zm9glkmejw

Figura 5 – Blockchain

Em janeiro de 2009, o primeiro bloco, de codinome Gênesis, foi lançado e permitiu que a mineração inicial de Bitcoins surgisse.

A Mineração de Bitcoins

O processo pelo qual os bitcoins entram no mercado é mais parecido com o que ocorre com o ouro que, por sinal, também pode ser usado como moeda: tanto o ouro quanto os bitcoins são obtidos por mineração (do inglês, mining) [7]. Para minerar bitcoins é necessário um computador rodando um programa Bitcoin Miner (Minerador de Bitcoin) que esteja ligado em rede a um conjunto de outros computadores pertencentes a proprietários diversos ou organizações. Esse software gera os valores na conta de um usuário à partir de limites ajustados constantemente pela rede [7]. Esta rede tem nós dedicados à mineração e nós de instituições que negociam com a moeda virtual e que utilizam o mesmo software usado para mineração. Essa rede é descentralizada – não há um nó centralizador do processo. Ela é uma rede ponto-a-ponto, o que garante a não existência de uma autoridade ou algum tipo de governança que controle o processo de emissão e o valor da cotação.

Em intervalos controlados pelo software que administra o sistema e que está distribuído por todos os nós, é emitido um hash (sequência de bits gerada pelo algoritmo de criptografia) contendo um determinado valor criptografado. Tratei brevemente da função hash nesse artigo, mas lá o foco era como fazer isso programaticamente. A dificuldade em quebrar este hash – encontrar a chave que o gerou por criptografia – é ajustável. Ao ser lançado um novo hash, todos os nós dedicados à mineração se põem imediatamente a tentar decifrá-lo (quebrá-lo). Matematicamente, quebrar um hash significa encontrar os números primos que o geraram, o que é impossível de se fazer manualmente e demorariam décadas para fazer de forma automatizada com o poder computacional que temos. Porém, se alguém descobrir a solução da hipótese de Rieman, que é um dos problemas de Hilbert que ainda não foram solucionados, o mundo dos bitcoins entrará em ruínas. Quebrar o hash gerado é o desafio imposto aos mineradores de bitcoins.

O primeiro minerador que conseguir decifrar o hash recebe como recompensa um determinado número de bitcoins. Tão logo isto ocorra, aquele nó anuncia à toda a rede que quebrou o código e que aqueles bitcoins relacionados ao hash lhe pertencem. Assim que esta transação estiver registrada em todos os nós da rede, o que ocorre relativamento rápido, aquele feliz minerador pode fazer uso de seus bitcoins. A geração aleatória de hashes garante a escasses de moedas, o que inibe a ação de especuladores e a “inflação virtual”. A idéia da escasses nos remete aos tempos das moedas fiduciárias lastreadas por metais como o ouro.

cradle_psf

Figura 6 – Um paciente minerador

Referências

1. [https://www.youtube.com/watch?v=iHYjsOFkHn0]
2. [http://www.mundodosbancos.com/moeda-fiduciaria/]
3. [http://www.investopedia.com/terms/f/fiatmoney.asp?lgl=no-infinite]
4. [http://www.dummies.com/personal-finance/investing/how-the-fiat-system-works/]
5. [http://www.techtudo.com.br/artigos/noticia/2014/01/bitcoin-o-que-e.html]
6. [http://www.techtudo.com.br/noticias/noticia/2016/05/quem-e-satoshi-nakamoto-identidade-do-criador-do-bitcoin-e-revelada.html]
7. [http://www.techtudo.com.br/artigos/noticia/2014/01/bitcoin-a-mineracao-de-moedas.html]
8. [http://www.techtudo.com.br/tudo-sobre/bitcoin.html]
9. [http://computerworld.com.br/blockchain-o-que-e-e-como-funciona]
10. [https://letstalkbitcoin.com/blog/post/goodbye-mike-and-some-thoughts-about-bitcoin]
11. [https://dzone.com/articles/java-and-the-blockchain]

Implementação de Autorização com Token Utilizando RESTEasy

Gosto bastante de desenvolver orientado a aspectos. A especificação JAX-RS possibilita implementar um mecanismo de autorização simples para seu web service REST. Um mecanismo de segurança simples ainda é melhor do que não ter segurança e a segurança deve ser definida como parte da arquitetura e não como uma funcionalidade.

Nesse exemplo, vamos mostrar como implementar um mecanismo de autorização baseado em token que é verificado em um interceptador do RESTEasy. Você poderia utilizar um ContainerRequestFilter ao invés do interceptor, mas você teria que utilizar a annotation @NameBinding em conjunto com a sua annotation para só então poder utilizá-la para anotar seu filtro.

1. Crie um enum que será utilizado para parametrizar sua anotação.

public enum Role {
   AUTHENTICATION_REQUIRED;
}

2. Crie uma anotação que utiliza a enum definida anteriormente para criar uma política de segurança. Essa anotação e aquela enum serão verificadas no interceptador. Você poderia utilizar outros métodos para identificar os recursos onde a política se aplicará, mas a combinação de enum e anotação é simples e elegante.

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface SecurityPolicy {
   Role[] value() default {};
}

3. Implemente um interceptador que verifica a anotação criada e a presença do atributo “TOKEN” no header da request. Note que além da anotação que criamos anteriormente (SecurityPolicy), estamos testando as anotações padrão PermitAll e DenyAll que poderiam estar anotando o recurso e são mais abrangentes que a nossa. Se tudo é permitido ou se tudo é negado, não faz sentido fazer uma verificação mais granular.

@Provider
@ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor {
   @Override
   public ServerResponse preProcess(HttpRequest request, 
        ResourceMethod methodInvoked) 
      throws Failure, WebApplicationException {
      Method method = methodInvoked.getMethod();
      if (method.isAnnotationPresent(PermitAll.class)) {
         return null;
      }
      if (method.isAnnotationPresent(DenyAll.class)) {
         return new ServerResponse("Não pode acessar esse recurso",
         Status.UNAUTHORIZED.getStatusCode(), 
         new Headers<Object>());
      }
      if (method.isAnnotationPresent(SecurityPolicy.class)) {
         SecurityPolicy rolesAnnotation = 
           method.getAnnotation(SecurityPolicy.class);
         List<Role> roles = Arrays.asList(rolesAnnotation.value());
         if (roles.contains(Role.AUTHENTICATION_REQUIRED)) {
            HttpHeaders headers = request.getHttpHeaders();
            List<String> authorization = 
              headers.getRequestHeader("TOKEN");
            if(authorization != null && !authorization.isEmpty())
            {
               String token = authorization.get(0); 
               boolean autorizado = /*regras de autorizacao*/;
               if(autorizado){
                  // Deve-se retornar nulo para que o 
                  // processamento da request continue normalmente
                  return null;
               }
            }
            return new ServerResponse("Usuário não autorizado", 
              Status.FORBIDDEN.getStatusCode(),
              new Headers<Object>());
         }
      }
      // Deve-se retornar nulo para que o 
      // processamento da request continue normalmente
      return null;
   }
}

4. Crie um recurso e anote o método que exige a aplicação da política de segurança

@Path("/usuario")
public class UsuarioResource {
 
  @EJB
   private UsuarioService service;

   @GET
   @SecurityPolicy(Role.AUTHENTICATION_REQUIRED)
   @Path("/buscar")
   @Produces(MediaType.APPLICATION_JSON)
   public Response buscar(@PathParam("id") String id) {
      try {
         Usuario usuario = service.buscar(id);
         ResponseUsuario respUsuario = new ResponseUsuario();
         respUsuario.setNome(usuario.getNome());
         return Response.status(Response.Status.OK).
            entity(respUsuario).
            header("Content-type", "application/json; charset=utf-8").
            build();
      } catch (ServicoException e) {
          return Response.status(Response.Status.FORBIDDEN).
            entity("Nao foi possivel localizar o usuario.").
            header("Content-type", "application/json; charset=utf-8").
            build();
      }
      return Response.status(Response.Status.UNAUTHORIZED).
        entity("Usuário não autorizado.").
        header("Content-type", "application/json; charset=utf-8").
        build();
   }
}

Você poderia utilizar algum navegador para testar o funcionamento do seu web service, mas prefiro utilizar o SOAPUI. Se você tiver alguma problema relacionado a certificado do Java, dê uma olhada nesse artigo.

token

Figura 1 – Interface do SOAPUI

Note o parâmetro “TOKEN” que passamos no cabeçalho da request. O ideal é que o valor seja obtido do próprio web service, talvez acessando o banco de dados, e que este tenha um tempo de expiração que faça sentido para o negócio e para alguma política de segurança da informação de nível operacional.

Referências

1. [http://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
2. [https://www.infoq.com/br/news/2012/10/autenticacao-rest
3. [http://blog.rivendel.com.br/2013/06/07/seguranca-em-apis-rest-parte-1/
4. [http://www.slideshare.net/stormpath
5. [http://www.developerscrappad.com/1814/java/java-ee/rest-jax-rs/java-ee-7-jax-rs-2-0-simple-rest-api-authentication-authorization-with-custom-http-header/
6. [http://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
7. [https://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/
8. [http://howtodoinjava.com/resteasy/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/
9. [http://howtodoinjava.com/resteasy/jax-rs-2-0-resteasy-3-0-2-final-security-tutorial/[