Security

O componente security fornece a estrutura necessária para integrar com sistemas de segurança e permitir controle de acesso através de credenciais.

API Base

Foco de uma atenção cada vez maior nos últimos anos, segurança é um aspecto muito importante e que deve ser cuidadosamente planejada para cobrir o máximo possível nossos sistemas. De uma forma simplista, podemos dividir a segurança da aplicação em duas partes:

  • Garantia de identidade: o sistema precisa ter certeza de que o usuário que está tentando acessá-lo é quem ela diz ser, existem diversos mecanismos para esta verificação, o mais clássico de todos é através da tupla [login, senha], mas existem outros métodos, como token, por exemplo... Nossos sistemas podem implementar esta etapa de segurança, mas é mais comum permitir que sistemas especializados nisto o façam, pois além de separar responsabilidades, as falhas, provavelmente, serão cobertas com mais agilidade. São exemplos aplicações que utilizam LDAP ou JOSSO
  • Controle de permissões: uma vez logados, os usuários geralmente possuem permissões para ações específicas de seu papel no sistema, assim é comum criarmos usuários que têm poderes de administradores, enquanto outros podem apenas autorizar operações, por exemplo. Este tipo de controle não é específico do domínio do sistema, mas este precisa informar quem pode acessar ou não.

O componente security-api serve para abstrair e padronizar a implementação destes dois tipos de controle, de modo que a aplicação saiba o que está sendo feito, mas desconheça completamente como está sendo feito. A imagem abaixo ilustra esta ideia:

../../_images/Security_review.png

Um dos principais motivos da existência desta API é permitir a flexibilidade exigida pelas aplicações na hora de integrar com sistemas externos dos nossos clientes. Por isto a interface SecurityManager é utilizada como base para criação de novos componentes, responsável pela verificação das informações recebidas pelo usuário, seu principal método é o login, abaixo veremos que existem integrações com sistemas LDAP e JOSSO implementando-a.

SecurityService

A base do módulo de segurança é o SecurityService, ele trabalha em conjunto com a estrutura de autorização do Java para saber se um usuário está logado e quais permissões ele possui.

Fica a critério do desenvolvedor solicitar informações ao serviço para verificar as credenciais do usuário e agir de acordo. De uma forma geral, se não houver autenticação, o usuário não poderá navegar pelas telas, caso não exista um usuário (logo, um Subject) associado à thread atual, considera-se que o usuário é o Sistema, que possui superpoderes para realizar diversas ações, como algumas tarefas de processamento em batch.

Implementando Credenciais

Uma Credencial é a forma de dar Permissão para uma determinada ação, os dois conceitos estão intimamente ligados. Enquanto uma Permissão define para o sistema o que pode ser feito, uma Credencial define quem pode fazer. Credenciais podem ser concedidas a usuários de duas formas:

  • Credenciais: credenciais que garantem permissão para alguma coisa a um ou mais usuários
  • Meta-Credenciais: conjunto de credenciais atrelado a um ou mais usuários
../../_images/Metacredential.png

Credenciais mais comuns derivam dos tipos de Permissão implementados, por exemplo, Ação, URL, Tarefa etc...

Permissões

Existem diversos tipos de credenciais, cada uma dando permissão a algo completamente distinto. Permissões, no componente security, são objetos que definem se o usuário possui ou não acesso a uma determinada ação, utilizando strings para tal.

Diversos tipos podem ser criados, bastando implementar a interface Permission. São exemplos de tipos de permissão:

  • Ação: quais ações podem ser executadas
  • Autorização: a quais entidades um usuário pode autorizar
  • Tarefa: quais tarefas podem ser iniciadas
  • URL: define quais páginas o usuário pode acessar
  • Grupo: grupos gerais de permissão
../../_images/Userpermission.png

Esta imagem ilustra a forma de interação das partes envolvidas, um usuário solicita qualquer coisa para o sistema que precise de alguma verificação de identidade ou credencial (login no sistema, acesso a uma página protegida etc...), o sistema utiliza o SecurityService para solicitar ao SecurityManager responsável pelo ambiente informações de permissão relacionadas com o que foi solicitado (credenciais e meta-credenciais), retorno define se a ação deve ser bloqueada ou permitida.

Integrando com framework web

Através do HttpApplicationSecurityManager, fornece uma interface básica para autenticação e controle de acesso Web para os usuários. Este módulo utiliza a entidade User para armazenar e verificar as informações fornecidas, isto significa que a aplicação armazena as informações do usuário, algo que não é comum em nossas aplicações mas que pode ser necessário.

Integrando com outros frameworks

Além do SecurityManager implementado no web, também temos outros dois que servem como ponte de comunicação, que delegam a responsabilidade de verificar identidade a sistemas terceiros, são eles:

  • LDAPSecurityManager: integra com sistemas LDAP
  • JOSSOSecurityManager: integra com sistemas JOSSO

Existem outras implementações específicas para sistemas proprietários, mas que, por questões de licença não foram disponibilizadas no [[Jmine]] Tec.

Configuração LDAP

Para utilizar o LdapSecurityManager em sua aplicação basta definir a dependência para o jmine-tec-security-ldap e configurar os beans do spring da seguinte maneira:

<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="url" value="<url para seu servidor de ldap>"/>
    <property name="userDn" value="<usuário para autenticação>"/>
    <property name="password" value="<senha para autenticação>"/>
    <property name="anonymousReadOnly" value="<True or False>"/>
    <property name="pooled" value="true"/>
</bean>

<bean id="ldapConnector" class="jmine.tec.security.ldap.connector.LdapConnector">
    <property name="userBaseDN" value="<Dominio base do usuario>"/> <!-- dc=jmine, dc=com, dc=br-->
    <property name="groupBaseDN" value="<Dominio base do grupo de usuários>"/>
    <property name="userFilter" value="<Query utilizada para buscar usuários>"/>
    <property name="groupFilter" value="<Query utilizada para buscar grupos>"/>
    <property name="groupNameAttribute" value="<nome do atributo em que o usuário se encontra no grupo>"/> <!--cn-->
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
    <constructor-arg ref="contextSource"/>
</bean>

<bean id="securityManager" class="jmine.tec.security.ldap.LdapSecurityManager">
    <property name="transactionalController" ref="persistenceController"/>
    <property name="securityService" ref="securityService"/>
    <property name="ldapTemplate" ref="ldapTemplate"/>
    <property name="connector" ref="ldapConnector"/>
    <property name="loginHandler" ref="loginHandler"/>
</bean>

<bean id="loginHandler" class="jmine.tec.security.ldap.LdapLoginHandler">
    <constructor-arg index="0" ref="ldapTemplate"/>
    <constructor-arg index="1" ref="ldapConnector"/>
    <constructor-arg index="2" ref="persistenceController"/>
    <constructor-arg index="3" ref="credentialDAO"/>
    <constructor-arg index="4" ref="userFilterHandler"/>
    <constructor-arg index="5" ref="groupFilterHandler"/>
</bean>

<bean id="userFilterHandler" class="jmine.tec.security.ldap.filter.UserUsernameFilterHandler"/>

<bean id="groupFilterHandler" class="jmine.tec.security.ldap.filter.UserDNFilterHandler">
    <constructor-arg ref="ldapTemplate"/>
</bean>

Aqui, o domínio e query para usuários serve para validar se o usuário forneceu as credenciais corretas, se a informação fornecida estiver ok, o domínio e query de de grupos será utilizado para obter as permissões de acesso do usuário. A propriedade groupNameAttribute serve para mapear um atributo dos grupos do usuário útil para a aplicação.

Caso a busca no grupo utilize como parâmetro de busca o username e não o userDN, basta substituir o bean “groupFilterHandler para”:

<bean id="groupFilterHandler" class="jmine.tec.security.ldap.filter.GroupUsernameFilterHandler"/>

LDAP queries

Como mostrado acima é preciso alguns beans para o ldap funcionar de maneira adequada, dois desses beans são responsáveis pela criação correta das queries de consulta ao LDAP, esses beans são:

  • userFilterHandler
  • groupFilterHandler

Ao utilizar o bean jmine.tec.security.ldap.filter.UserDNFilterHandler, torna-se possível utilizar queries de consulta de grupo que tenham disponiveis os placeholders “#{username}” e “#{userDN}”, por exemplo as queries:

  • (&(objectClass=group)(member=#{userDN}))
  • (&(objectClass=group)(member=#{username}))