Esfinge Guardian - Framework para Controle de Acesso


Visão geral



O Esfinge Guardian é um framework de autorização altamente extensível, plenamente capaz para uso no desenvolvimento de qualquer aplicação de negócio. Seus benefícios incluem a completa separação do código de negócios do código de autorização. Esta é uma característica importante porque o grau de dissociação é um determinante forte na qualidade da solução final. A mistura desses dois interesses torna a aplicação difícil de manter e normalmente implica em um custo mais elevado.
Uma característica do Esfinge Guardian é que ele fornece ao desenvolvedor de aplicativos ferramentas para atacar os problemas de desenvolvimento tradicionais, de uma forma simples. Duas decisões de design são responsáveis ​​pela simplicidade desse framework: o uso de anotações de domínio capazes de abstrair a implementação de políticas complexas de autorização, aproximando a terminologia com domínio do negócio; e o fato de que o Esfinge Guardian é um framework baseado em metadados, totalmente capaz de adaptar o seu algoritmo interno com base nos metadados associados às operações que precisam ser protegidas.
O framework Esfinge Guardian contém implementações de componentes para alguns dos modelos clássicos de controle de acesso: RBAC, ABAC, e MAC. Essas implementações representam um número expressivo de cenários de autorização, eliminando a necessidade de um conhecimento profundo sobre os modelos de controle de acesso. No entanto, o framework permite facilmente a extensão para novos modelos de autorização que podem ser plugados, funcionando da mesma forma que os já existentes.

Configuração


Como regra geral, é necessária a edição dos arquivos JAR do Esfinge Guardian com as seguintes dependências

  • aopalliance-1.0.jar
  • asm-3.3.1.jar
  • aspectjrt-1.6.2.jar
  • aspectjweaver-1.6.2.jar
  • cglib-2.2.2.jar
  • commons-logging-1.1.1.jar
  • el-api-2.2.jar
  • javassist-3.6.0.GA.jar
  • jboss-el.jar
  • jboss-el-api_2.2_spec-1.0.1.Final.jar
  • org.hamcrest.core_1.1.0.v20090501071000.jar
  • scannotation-1.0.2.jar
  • spring-aop-3.0.5.RELEASE.jar
  • spring-asm-3.0.5.RELEASE.jarspring-beans-3.0.5.RELEASE.jar
  • spring-context-3.0.5.RELEASE.jar
  • spring-core-3.0.5.RELEASE.jar
  • spring-expression-3.0.5.RELEASE.jar

Arquitetura


A arquitetura do Esfinge Guardian é descrita por 8 elementos:

AuthorizationContext

É a entidade central que contém todas as informações necessárias para uma autorização, que inclui informação de recursos e de meio ambiente. Isso significa que todas as outras entidades devem fornecer um AuthorizationContext com informações suficientes para que a autorização possa ocorrer. É também uma interface com o usuário.

GuardianInterceptor

Com o Esfinge Guardian é possível indicar quais operações e/ou entidades devem ser protegidos sem se preocupar com outras configurações. Toda operação e/ou entidade, quando protegidos pelos framework, devem ser interceptados de maneira transparente e não chamados diretamente. GuardianInterceptor é a entidade responsável por abstrair as diferentes tecnologias de intercepção existentes, como o aspecto da orientação, cglib (GERAÇÃO DE CÓDIGO DA BIBLIOTECA, 2010), proxy dinâmico, etc.

Invoker

Todo requisição feita para ama operação é interceptada, portanto, o framework deve ser responsável por replicar o pedido para o recurso se o acesso é concedido. Invoker é uma entidade com a capacidade de imitar a operação executada pelo sujeito em um recurso protegido. No âmbito Esfinge Guardian, esse elemento pode executar métodos; No entanto, é importante notar que é apenas uma das possibilidades uma vez que o modelo é de arquitectura geral. Uma característica adicional é que a entidade Invoker é o responsável por determinar quando a lógica de autorização é realizada. Em muitos casos, a aplicação lógica de autorização só faz sentido após a realização da proteção de uma operação. Por exemplo, considere o caso quando a operação recuperar uma coleção e a regra de autorização requer iteração sobre a coleção, a fim de verificar se o requisitor pode realmente acessar todos os seus itens. Desta forma, deve haver uma maneira para configurar o momento preciso em que a autorização deve ser executada.

Populator

É a entidade que contém a lógica de extração dos dados de autorização. informações para autorização podem estar em qualquer lugar, como bancos de dados, arquivos, variáveis compartilhadas, sessão do usuário, argumentos, Internet, etc. Por esta razão, Populator é uma entidade que sabe como obter informações de todos esses lugares. Pode haver zero ou mais Populators na aplicação, cada uma especializada na obtenção de um tipo diferente de informações de diferentes lugares.

PopulatorProcessor

Entidade que reúne e executa todas as instâncias de Populator definidas na aplicação.

Authorizer

Entidade que implementa a lógica da política de controle de acesso e pode usar as informações armazenadas no AuthorizationContext se necessário. Deve haver pelo menos um Authorizer. Cada Authorizer deve fornecer a sua resposta ao AuthorizationProcessor, geralmente um "sim" ou "não"; No entanto, deve ser possível incluir outros tipos de resposta, tais como "indeterminada".

AuthorizerProcessor

Entidade que contém o algoritmo para combinar todo Authorizer definidos na aplicação.

AuthorizationMetadata

Entidade que indica quais recursos - ou suas operações - devem ser interceptados pelo mecanismo de autorização. Um requisito é de que este elemento deve ser do tipo de metadados, de modo que ele pode ser usado de forma declarativa. O Esfinge Guardian usa anotações Java como implementação deste elemento; No entanto, ele pode ser considerado um elemento de marcação geral que é independente de uma tecnologia específica.

Visão estática e dinâmica da Arquitetura do Esfinge Guardian


As entidades de arquitetura apresentadas na seção anterior podem ser representadas em um diagrama de classe como na Figura 1, mostrando suas relações e responsabilidades.

Figura 1. Relacionamento entre os elementos de arquitetura do Esfinge Guardian.

A cardinalidade entre os elementos de arquitetura é basicamente de um-para-um, exceto para o AuthorizerProcessor e o PopulatorProcessor. Isso significa que, a entidade AuthorizerProcessor deve ter pelo menos um Authorizer, e o PopulatorProcessor pode ter zero ou mais Populators. É possível que não exista Populators a serem usados, o que significa que a autorização irá utilizar apenas uma informação definido na AuthorizationMetadata.
O diagrama de sequência na Figura 2 ilustra o despacho de autorização em que o elementos de arquitetura são chamados. Considerando a chamada após uma operação ser interceptada. O Invoker é chamado e decide se a autorização será realizada antes ou depois da execução da operação. O AuthorizerProcessor assume e ele solicita ao PopulatorProcessor para reunir informações de todos os Populators definidos. Depois de recuperar todas as informações a partir dos Populators, AuthorizerProcessor define todos Authorizers que serão executados. O recurso protegido é concedido se todos os Authorizers respondem com um "sim".

Figura 2. Diagrama de Sequencia da perpectiva de arquitetura do Esfinge Guardian.

Proteção de Métodos


Para exemplificar o uso do framework, considere a classe abaixo que precisa ter seus métodos protegidos:

class BankManager {
    public void creditLimitIncreaseRequest(Client c) {
        // request credit limit logic
    }
}

Utilizando Anotações Pré-definidas

Imagine que o método creditLimitIncreaseRequest() só possa ser acessado por gerentes. Neste caso, o método poderia ser definido da seguinte forma:
@Role(“Manager”)
public void creditLimitIncreaseRequest(Client c) {
    // request credit limit increase logic
}

Considere também que exista uma regra de segurança que defina que essa funcionalidade só possa ser acessada durante o horário do expediente. Segue como essa regra seria adicionada:
@Rule(“environment.currentTime >= ‘8:00:00’&& environment.currentTime
Ao criar regras, é possível acessar objetos em três diferentes escopos: subject (usuário), resource (o que está sendo acessado) e environment (ambiente geral da aplicação). No exemplo apresentado, é acessada uma variável no contexto environment chamada currentTime.

Encapsulando Regras em Anotações de Domínio

Esfinge Guardian dá suporte a criação de anotações de domínio. Elas permitem a utilização da terminologia de domínio nas anotações, não expondo nas classes de negócio as anotações específicas do framework. Outra vantagem dessa abordagem é que a mesma regra pode ser facilmente reutilizada em diversos locais. Segue como o exemplo ficaria com uma anotação de domínio:
@ManagersDuringWorkingHours
public void creditLimitIncreaseRequest(Client c) {
    // request credit limit increase logic
}

Nesse caso, a anotação de domínio deve ser anotada com as anotações do framework:

// Retention and ElementType annotations suprressed
@Rule(“environment.currentTime >= ‘8:00:00’
       && environment.currentTime

Protegendo objetos com o EsfingeGuardian

Para que um objeto seja protegido, é preciso encapsula-lo com um proxy do framework. Isso pode ser feito com o seguinte método:
BankManager bManager = AuthorizationContext.guard( new BankManager() );

Se você precisa adicionar outros objetos para serem utilizados nas regras de autorização, eles também podem ser passados para esse método. Considere os seguinte exemplo que mostra como podem ser inseridos objetos em cada um dos escopos:
WrappedObj wCTime = AuthorizationContext.wrapAsEnvironmentProp(“currentTime”, new Date());
WrappedObj wManager = AuthorizationContext.wrapAsSubjectProp(“Manager”, new Manager());
WrappedObj wClient = AuthorizationContext.wrapAsResourceProp(“Client”, new Client());

BankManager bManager = AuthorizationContext.guard( new BankManager(), wCTime, wManager, wClient );

Estendendo o Framework


O Esfinge Guardian pode ser estendido em diversos pontos. Essa seção descreve como estender o framework para adapta-lo a diferentes modelos de autorização e arquiteturas.

Criando Novas Anotações de Autorização

Qualquer classe que implementar a interface Authorizer pode ser associada a uma anotação e utilizada como uma regra de autorização. A anotação de autorização deve ser anotada com @AuthorizerClass, indicando a classe com a implementação da regra. O seguinte exemplo mostra a definição de uma nova anotação de autorização:
// Retention and ElementType suppressed
@AuthorizerClass(MyAuthorizerClass.class)
public @interface MyAuthorizationAnnotation {
}

A classe a seguir mostra como seria a implementação da classe de autorização:

public class MyAuthorizerClass implements Authorizer {

    public Boolean authorize(AuthorizationContext ctx, MyAuthorizationAnnotation maa) {
        //acessar as variáveis do contexto e executar regra de autorização
        return true;
    }
}

Adicionando Informações de Autorização

No exemplo apresentado anteriormente, as variáveis consideradas para autorização, disponíveis para serem acessadas eram adicionadas no método guard(). É possível criar classes que implementam a interface Populator que podem ser utilizadas para popular as informações necessárias que não foram adicionadas no método guard(), porém, são necessárias para a autorização. Desta forma é possível recuperar informações presentes em um banco de dados, na seção web do usuário, ou lógicas mais elaboradas. Veja um exemplo de como pode ser criado um Populator.
public class MyDatabasePopulator implements Populator {
    public void populate(AuthorizationContext context){
        // extraction logic of the data and put these data into the
        // appropriate scope (subject, environment, resource)
        // ex: context.getSubject().put(“myDataObjKey”, myDataObj);
    }
}

Configurando Populators

Para que o framework possa encontrar os populators, é preciso que o jar que possuir a classe adicione um arquivo chamado org.esfinge.guardian.populator.Populator no seguinte caminho META-INF\services\. Esse arquivo deve conter o nome completo de todas as classes, como o seguinte exemplo:
package.MyDatabasePopulator
package.MyWebSessionPopulator

 

 

 

Apoio

Todos os direitos reservados