A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Controle de acesso no Joomla 1.5

Dom

4

Mai

2008


20:40

(29 votos, média 3.97 de 5) 


Joomla Analisando o controle de acesso no Joomla 1.5 acabei descobrindo que as novas versões vêm com o phpGACL completinho e que o uso deste excelente conjunto de funções é utilizado apenas uma vez (e de modo muito precário) na autenticação de usuários. É uma pena porque, se fosse devidamente explorado, poderíamos criar novos grupos de usuários, regras de acesso e muito mais. O pessoal anda comentando que estas novas mordomias provavelmente estarão disponíveis na versão 1.6 ou 2.0, mas como até lá tem muito chão teremos tempo de aprender como este troço funciona.

Porque um sistema de controle de acesso?

Imagine que você queira abrir partes do seu site só para determinados usuários e também queira sair da mesmice de usuário registrado, editor, publicador, admin, etc. No atual estágio do Joomla não é possível fazer isto sem gastar um bom dinheiro para adquirir componentes comerciais. Fuçando um pouco mais o assunto descobri um componente gratuito da jxTENDED, o Control, baseado no phpGACL e que permite criar e gerenciar todos os tipos de objetos necessários para um controle de acesso mais estruturado e efetivo. Como faltam algumas tabelas na base de dados do Joomla, este componente cria estas tabelas e deixa tudo no jeito para que possamos incorporar novas funcionalidades em módulos, componentes e plugins que viermos a criar. Foi daí que me deu uma vontade doida de saber o que é e como funciona o phpGACL. Para servir de referência quando eu precisar e para compartilhar com vocês esta "novidade", resolvi colocar tudo neste tutorial.

Aviso aos navegantes: o componente Control, citado acima, NÃO vai permitir controlar o componente nativo com_content, responsável pela apresentação das páginas do conteúdo. Ao invés de começar a hackear o código fonte do Joomla, o melhor é adquirir experiência com componentes próprios e deixar para os desenvolvedores deste CMS a tarefa de incorporar definitivamente o phpGACL de forma mais completa tongue

O que é o phpGACL?

O phpGACL é um conjunto de funções que permitem aplicar um controle de acesso em objetos dos tipos mais variados (páginas web, bases de dados, etc) através de outros objetos também de vários tipos (usuários, hosts remotos, etc). Ele oferece um controle de acesso de sintonia fina (ou de granularidade fina), com uma administração muito simples, e é muito rápido.

O porque do nome começar com php está na cara, mas o que vem a ser GACL? É Generic Access Control List, ou seja, Lista de Controle de Acesso Genérica. Este projeto é da autoria de Mike Benoit e pode ser encontrado na sourceforge.net. Taí o endereço, se bem que, como já disse, o Joomla traz a última versão (procure em /libraries/joomla/phpgacl - são apenas dois arquivos relativamente pequenos, o gacl.php e o gacl_api.php).

Entendendo o Controle de Acesso

Melhor do que ficar discutindo conceitos teóricos é partir para exemplos práticos. Vamos imaginar o seguinte cenário: Maremoto é o capitão do navio Princesa dos Mares e Barrica é seu imediato. Eles levam alguns passageiros a bordo: Zé Arruela, Zé do Boné, Margarida e Papagaio. Maremoto precisa definir restrições de acesso para vários recintos do navio: Cabine de Comando, Refeitório, Despensa e Casa das Máquinas.

Maremoto diz: "Eu e o Barrica precisamos ter acesso a qualquer recinto mas, depois que ele acabou com as barras de chocolate, proibi o Barrica de chegar perto da despensa. Os passageiros só podem entrar no refeitório".

A partir de agora vamos assumir que o acesso é booleano, isto é, a verificação do acesso de uma pessoa a um determinado recinto é PERMITIDO (ALLOW) ou PROIBIDO (DENY). Não existe mais ou menos, é sim ou não. Se mapearmos esta declaração numa matriz de acesso que mostre quem tem acesso a que, o resultado será este (0 significa PERMITIDO e X significa PROIBIDO):

Quem/Onde ComandoRefeitórioDespensaMáquinas
Maremoto 00 00
Barrica 00 X0
Arruela X0 XX
Boné X0 XX
Margarida X0 XX
Papagaio X0 XX

As colunas mostram os recintos de acesso restrito e as linhas mostram as pessoas que podem solicitar acesso a estes recintos. Em termos mais gerais, os "recintos" são "coisas cujo acesso precisa ser controlado". Chamamos estas "coisas" de Objetos de Acesso Controlado (ACO Access Control Objects). As pessoas são "coisas que solicitam acesso" e são chamadas de Objetos de Solicitação de Acesso (ARO Access Request Objects). As pessoas solicitam acesso aos recintos ou, na terminologia ACL, AROs solicitam acesso a ACOs.

Existe um terceiro tipo de objeto, o Objeto de eXtensão de Acesso (AXO Access eXtension Object) que será apresentado a vocês mais adiante. Estes objetos são coletivamente chamados de Objetos de Acesso (Access Objects).

Administrar acessos usando uma matriz de acesso como a mostrada acima tem vantagens e desvantagens. As vantagens são:

  • Sua granularidade é muito fina. É possível controlar o acesso para cada uma das pessoas se for necessário.
  • É muito fácil ver quem tem acesso a o que. A resposta fica na intersecção da pessoa e do recinto.

As desvantagens, por sua vez, são as seguintes:

  • Fica difícil administrar em larga escala. 6 passageiros e 4 recintos é uma coisa bastante simples, mas e se fosse um transatlântico com milhares de passageiros e centenas de recintos? E se fosse preciso restringir o acesso a grupos grandes e ainda assim manter uma granularidade suficiente para poder controlar as pessoas individualmente? A tarefa seria muito difícil, trabalhosa e propensa a erros.
  • Ficaria difícil resumir ou visualizar. O exemplo anterior é bastante simples, mas, e se a matriz fosse a mostrada logo abaixo? Mesmo com pouca gente a coisa fica bem mais complicada.
Quem/Onde ComandoRefeitórioDespensaMáquinas
Maremoto 00 00
Barrica 0X X0
Arruela X0 X0
Boné X0 XX
Margarida XX 0X
Papagaio 00 XX

Definindo o controle de acesso com o phpGACL

Parece que para situações mais complexas esta técnica da 'matriz de acesso' não é muito apropriada. Precisamos de um sistema melhor que mantenha as vantagens (controle de granularidade fina e uma noção clara de quem tem acesso a que), mas que elimine as desvantagens (dificuldade de resumir e dificuldade de administrar grandes grupos de pessoas). Uma das soluções é o phpGACL (não foi por acaso que os responsáveis pelo Joomla fizeram esta opção).

O phpGACL não descreve o acesso de 'baixo para cima' como as matrizes de acesso mostradas. Faz exatamente ao contrário, de 'cima para baixo', assim como a descrição textual da política de acesso feita pelo capitão Maremoto. Isto é um sistema muito flexível que permite administrar acessos de grupos grandes, sintetiza muito bem a política de acesso e fica fácil de ver quem pode acessar o que.

Uma árvore ARO define uma hierarquia de Grupos e de AROs (coisas que solicitam acesso). É muito parecida com a árvore de diretórios (pastas) e arquivos. As 'pastas' são os Grupos e os 'arquivos' são os AROs.

Vamos fazer uma árvore ACL para as pessoas do navio do Maremoto. Primeiramente definimos algumas categorias para as pessoas. É evidente que Maremoto e Barrica comandam o navio e que o restante das pessoas fazem parte da tripulação:

Princesa dos Mares
|
|- Grupo Comando
|  |- Maremoto ARO
|  |- Barrica  ARO
|
|- Grupo Tripulação
   |- Zé Arruela ARO
   |- Zé do Boné ARO
   |- Margarida  ARO
   |- Papagaio   ARO

Esta árvore, por si só, não especifica qualquer política de acesso - ela só mostra como estamos agrupando as pessoas que podem requisitar acesso (AROs). Podemos aplicar restrições de acesso colocando instruções sobre determinados recintos (ACOs) para Grupos ou AROs na árvore. Maremoto diz: "Como padrão, ninguém pode ter acesso a qualquer recinto do Princesa dos Mares. Mas o comando deve ter acesso a todos os recintos. A tripulação pode ter acesso apenas ao refeitório".

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- Maremoto
|  |- Barrica
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Zé Arruela
   |- Zé do Boné
   |- Margarida
   |- Papagaio

Para interpretar esta árvore ARO, começamos em cima e vamos abrindo caminho para baixo.

Em primeiro lugar, a política padrão é proibir o acesso. As permissões podem ser substituídas para o "Comando" de modo que este tenha acesso a tudo ("ALL" significa TUDO, todos os recintos: "Comando, Refeitório, Despensa, Máquinas"). A "tripulação" tem acesso apenas ao Refeitório.

Resumindo:

  • Access Control Objects (ACOs) são coisas cujo acesso queremos controlar (por exemplo, páginas web, bases de dados, recintos, etc).
  • Access Request Objects (AROs) são coisas que requisitam acesso (por exemplo, pessoas, computadores remotos, etc)
  • Árvores ARO definem uma hierarquia de Grupos e AROs. Grupos podem conter outros Grupos e AROs.
  • A política default 'pega-tudo' para a árvore ARO sempre é "DENY ALL".
  • Para definir uma política de acesso vá descendo a árvore e, quando necessário, assinale explicitamente as permissões para Grupos e AROs.

Controle de Acesso de granularidade fina

Xiiii, esquecemos que o Barrica não pode entrar na despensa. Como ele está no grupo Comando, ele acaba tendo acesso a todos os recintos. Peraí!

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- Maremoto
|  |- Barrica   [DENY: Despensa]
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Zé Arruela
   |- Zé do Boné
   |- Margarida
   |- Papagaio

Este é um exemplo do modo como se pode controlar a política de acesso usando a granularidade fina. Não é preciso colocar o Barrica num outro grupo, basta substituir a política de acesso num nível mais baixo.

Outro exemplo de controle de granularidade fina acontece quando o mar resolve encrespar: o capitão Maremoto precisa do Zé Arruela na casa das Máquinas e do seu Papagaio de estimação a seu lado, na cabine de comando:

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- Maremoto
|  |- Barrica   [DENY: Despensa]
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Zé Arruela [ALLOW: Máquinas]
   |- Zé do Boné
   |- Margarida
   |- Papagaio   [ALLOW: Comando]

Grupos Multi-Nível

Os grupos podem ser estendidos para qualquer nível na árvore ARO. Por exemplo, podemos adicionar o grupo "Cozinha" à "Tripulação". A maioria dos tripulantes seria categorizada como "Tripulação", mas o Zé do Boné (cozinheiro) e a Margarida (copeira) seriam colocados na "Cozinha" e poderiam ter privilégios extras (como o acesso à Despensa):

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- Maremoto
|  |- Barrica   [DENY: Despensa]
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Cozinha [ALLOW: Despensa]
   |  |- Zé do Boné
   |  |- Margarida
   |- Zé Arruela [ALLOW: Máquinas]
   |- Papagaio   [ALLOW: Comando]

Como o phpGACL determina permissões

Quando o computador do Princesa dos Mares checa acessos, a única pergunta que ele pode fazer a si mesmo (melhor dizendo, ao phpGACL) é "A pessoa X tem acesso ao recinto Y?" o que, na linguagem nativa ACL é "O ARO X tem acesso ao ACO Y?"

O phpGACL determina se uma pessoa específica X tem acesso a um recinto específico Y trabalhando de cima para baixo na árvore ARO até chegar à pessoa especificada e anotando explicitamente todos os controles de acesso que for encontrando pelo caminho. Quando ele alcança a referida pessoa, ele usa o último controle de acesso encontrado e o devolve como resultado da busca. Deste modo, podemos definir controles de acesso para grupos de pessoas que, se houver necessidade, podem ser substituídos por outros num nível mais baixo.

Exemplo: a pergunta é "Margarida pode entrar no Refeitório?"

Seguindo o caminho na árvore ARO, chegamos até a Margarida da seguinte forma:

  • Princesa dos Mares: DENY ALL (o padrão é TUDO PROIBIDO)
  • Tripulação: ALLOW Refeitório, então o resultado interno é PERMITIDO Refeitório.
  • Cozinha: nenhuma referência ao refeitório, então ele continua PERMITIDO.
  • Margarida: nenhuma referência ao refeitório, então ele continua PERMITIDO.
  • Não tem mais para onde ir: o resultado é ALLOW Refeitório.

O exemplo nos mostra que, se um Grupo não especificar explicitamente uma permissão a um recinto, então o Grupo herda as restrições de acesso do seu Grupo Pai. Se o nó raiz ("Princesa dos Mares") não especificar uma permissão, ele herda a condição básica ("DENY ALL").

Isto conduz a vários pontos interessantes a respeito da árvore ARO:

  • A árvore ARO sempre mostra a lista completa dos AROs. Não teria sentido perguntar se "Marola tem acesso à cabine de comando" porque o Marola não foi definido neste sistema. O phpGACL, no entanto, não checa se algum ARO ou ACO existe antes de fazer a pesquisa e o resultado a esta pergunta seria a padrão "DENY".
  • A árvore ARO pode não mostrar algum ACO definido. Neste caso, a política padrão é usada para definir o acesso. Por exemplo, o capitão Maremoto definiu um ACO "Banheiro". Qualquer pergunta do tipo "Papagaio tem acesso ao Banheiro?" teria a resposta "DENY" porque o "Banheiro" não foi citado explicitamente em nenhum ponto da árvore ARO. Quando examinar uma árvore ARO não se esqueça de que alguns ACOs podem não estar visíveis.

info Apesar de "parecer" correto, ao fazer perguntas phpGACL sobre um acesso a algum ACO não é possível usar Grupos como AROs. Por exemplo, é impossível responder a pergunta "A Tripulação tem acesso à Sala de Máquinas?" porque a resposta completa não seria "ALLOW" ou "DENY" - seria alguma coisa mais complexa como "Zé Arruela pode, mas Zé do Boné, Margarida e o Papagaio não". Lembre-se, o phpGACL é de poucas palavras: sim ou não.

Resolvendo conflitos

Quando a árvore ARO começa a ficar mais complexa pode acontecer de um ARO ter acessos conflitantes. Veja no exemplo abaixo, quando o capitão Maremoto resolveu que o Barrica teria de ajudar na cozinha por uns tempos para aprender a se controlar melhor e não avançar sobre qualquer alimento que aparecesse na sua frente smile :

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- Maremoto
|  |- Barrica   [DENY: Despensa]
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Cozinha [ALLOW: Despensa]
   |  |- Zé do Boné
   |  |- Margarida
   |  |- Barrica
   |- Zé Arruela [ALLOW: Máquinas]
   |- Papagaio   [ALLOW: Comando]

Observe que, se o computador do navio seguir o caminho para o grupo Comando, o Barrica tem um DENY à Despensa. Se o computador seguir o caminho para o grupo Tripulação, subgrupo Cozinha, o Barrica tem um ALLOW à Despensa. Como é que fica, ele tem ou não tem acesso à Despensa?

Quando há acessos ambíguos numa ACL esta é chamada de INCONSISTENTE. ACLs inconsistentes podem ser muito perigosas porque podem dar acessos indesejados a pessoas não autorizadas. Para nossa sorte, o phpGACL avisa quando encontra controles de acesso ambíguos, mas não os corrige. Se receber um destes avisos você precisa corrigir o conflito porque o phpGACL não vai fazer isto por você.


Nomeando Objetos de Acesso

O phpGACL identifica unicamente cada um dos Objetos de Acesso (AROs, AXOs e ACOs) com uma combinação de duas palavras-chave e o tipo de Objeto de Acesso. Assim, o trio (tipo de Objeto de Acesso, Seção, Valor) identifica unicamente qualquer Objeto de Acesso.

  • O primeiro elemento do trio é o tipo de Objeto de Acesso (ARO, AXO ou ACO).
  • O segundo elemento do trio, chamado de Seção (Section), é uma string definida pelo usuário que dá nome à categoria geral do Objeto de Acesso. Múltiplos Objetos de Acesso podem compartilhar o mesmo nome de Seção. O nome da Seção deve ser curto, mas ao mesmo tempo descritivo (é melhor ter seções chamadas de sistema, andares ou pessoas do que chamadas de a, b e c).
    As Seções são armazenadas num espaço de nomes linear; elas não podem ser aninhadas como os Grupos. Seções nada têm a ver com Grupos ou com árvores ARO/AXO - elas são apenas um mecanismo para ajudar a manter um grande número de Objetos de Acesso.
  • O terceiro elemento do trio é um nome definido pelo usuário para o Objeto de Acesso e é chamado de Valor (Value). Um valor não pode conter espaços (apenas os nomes das Seções podem).

info Os nomes das Seções e os Valores são sensíveis a maiúsculas/minúsculas. Por exemplo, a seção "Sistema" é diferente da seção "sistema".

info O motivo para usar nomes para seções e valores é para torná-los mais compreensíveis. O que você acha mais fácil de entender?

acl_check('sistema', 'login', 'usuarios', 'ana_maria');
      ou
 acl_check(10, 21004, 15, 20304);

Exemplo de "Seções > Valores" para ACOs

  • "Recintos > Comando"
  • "Recintos > Máquinas"
  • "Andares > Primeiro"
  • "Andares > Segundo"

Exemplos de "Seções > Valores" para AROs

  • "Comando > Maremoto"
  • "Marujos > Zé_Arruela"
  • "Aves > Papagaio"

Exemplo de uso

  • acl_check( aco_section, aco_value, aro_section, aro_value );
  • acl_check( 'Recintos', 'Comando', 'Aves', 'Papagaio' );

Adicionando Seções

Antes de adicionar um novo Objeto de Acesso é preciso definir sua Seção. Para adicionar uma nova seção use a função add_object_section().

add_object_section (
   string NOME,    // Uma breve descrição do que é a Seção (por exemplo, "A sala de comando").
   string VALOR,   // O nome da Seção (por exemplo, "Comando").
   int ORDEM,      // Um valor arbitrário que afeta a ordem de apresentação desta seção na UI.
   bool OCULTA,    // Se deve aparecer ou não na UI (TRUE significa que não é mostrada).
   string TIPO)    // Tipo de Objeto de Acesso ("aco", "aro" ou "axo")

O capitão Maremoto criou três tipos de ARO: "Comando", "Marujos" e "Aves":

Princesa dos Mares
|
|- Grupo Comando [ALLOW: ALL]
|  |- "Comando > Maremoto"
|  |- "Comando > Barrica"   [DENY: Despensa]
|
|- Grupo Tripulação [ALLOW: Refeitório]
   |- Cozinha [ALLOW: Despensa]
   |  |- "Marujos > Zé_do_Boné"
   |  |- "Marujos > Margarida"
   |- "Marujos > Zé_Arruela" [ALLOW: Máquinas]
   |- "Aves > Papagaio"   [ALLOW: Comando]

As seções são apenas uma forma de categorizar Objetos de Acesso, para fazer com que a interface do usuário (UI) seja mais amigável e para tornar o código do acl_check() mais legível. Elas não afetam o modo como o phpGACL determina o acesso a um objeto.


Finalmente os AXOs

Access eXtension Objects (AXOs) podem adicionar uma terceira dimensão às permissões que podem ser configuradas no phpGACL. Vimos como o phpGACL permite combinar um ARO e um ACO (duas dimensões) para criar uma Diretiva de Política de Acesso. Isto é o suficiente para uma solicitação de permissão simples como:

Papagaio (ARO) requisita acesso ao "Comando" (ACO)

Se isto é tudo o que você precisa, então ótimo porque os AXOs são totalmente opcionais. Mas como todos os ACOs são considerados iguais, fica difícil administrá-los quando existirem em grande número. Se este for o caso, podemos mudar o modo como olhamos para os Objetos de Acesso e facilitar as coisas.

AXOs são iguais aos AROs em muitos aspectos. Existe uma árvore AXO (separada da árvore ARO) com seus próprios Grupos e AXOs. Quando lidar com AXOs, considere os AXOs tomando o lugar dos ACOs (isto é, "coisas com acesso controlado") e passe a considerar os ACOs como "ações que são requisitadas".

Visão ARO e ACO

  • AROs: coisas requisitando acesso.
  • ACOs: coisas com acesso controlado.

Visão ARO, ACO e AXO

  • AROs: coisas requisitando acesso.
  • ACOs: ações que são requisitadas.
  • AXOs: coisas com acesso controlado.

Exemplo: um administrador de um site está tentando definir o acesso a projetos neste website. A árvore ARO compreende todos os usuários:

Website
|
|- Administradores
|  |- Júlia
|  |- João
|
|- Usuários
   |- Pedro
   |- Clara
   |- Helena

Os projetos estão organizados por Sistema Operacional em categorias na árvore AXO:

Projetos
|
|- Linux
|  |- Filtro de Spam
|  |- Firewall
|
|- Windows
   |- Exterminador de Assistentes do Office
   |- Devorador de Telas Azuis

As ações que podem ser requisitadas em cada projeto são "Ver" e "Editar". Estes são os ACOs.

Agora queremos que o Pedro tenha acesso para "Ver" todos os projetos Linux. Para isto adicionamos uma ACL que liga o ARO de Pedro ao ACO Ver e ao AXO Linux. A partir daí podemos fazer a pergunta:

Pedro (ARO) requesita acesso para "Ver" (ACO) o(s) projeto(s) chamados "Linux" (AXO)

Lembre-se de que os AXOs são opcionais. Se você não especificar um AXO quando chamar acl_check() e existir uma ACL sem um AXO, tudo bem. Entretanto, se existirem apenas ACLs com AXOs e você chamar acl_check() sem um AXO, a chamada vai falhar.

Basicamente, assim que você especificar um AXO ao chamar acl_check(), esta função irá procurar apenas ACLs que contenham AXOs. Se nenhum AXO for especificado, apenas ACLs sem AXOs serão pesquisadas.

Fonte de Referência

Generic Access Control Lists with PHP

Вадим Логофет детизаказ домаполигон ооо лобановский александрvsemsmart.ru vsemsmartкапитал mfx

Informações adicionais