Blog da Improve It

Controle de Acesso

Publicado por Marcos Tapajós há aproximadamente 1 ano.

Recentemente um cliente da Improve it me perguntou se existe algum plugin para fazer controle de acesso em Ruby on Rails e como eu não conhecia nenhum iniciei uma processo de pesquisa e experimentos com alguns plugins que eu encontrei.

Antes de continuar falando em controle de acesso acho importante explicar a diferença entre Autenticação e Autorização já que normalmente eu vejo nas listas de Rails as pessoas confundirem esses conceitos.

Autenticação:

"Autenticação (do grego : αυθεντικός = real ou genuíno, de 'authentes' = autor) é o ato de estabelecer ou confirmar algo (ou alguém) como autêntico, isto é, que reivindica a autoria ou a veracidade de alguma coisa. A autenticação também remete à confirmação da procedência de um objeto ou pessoa, neste caso, frequentemente relacionada com a verificação da sua identidade."(wikipedia)

Quando se fala em Autenticação, em Ruby on Rails, uma unanimidade é o plugin Restful Authentication. Trata-se de um excelente plugin e acredito que no que diz respeito a autenticação o problema foi bem resolvido por ele.

Autorização:

"Autorização, em segurança da informação, é o mecanismo responsável por garantir que apenas usuários autorizados consumam os recursos protegidos de um sistema computacional. Os recursos incluem arquivos, programas de computador, dispositivos de hardware e funcionalidades disponibilizadas por aplicações instaladas em um sistema. Podem ser considerados consumidores de recursos, as pessoas que utilizam um sistema através de uma interface, programas e outros dispositivos de um computador.

O processo de autorização decide se uma pessoa, programa ou dispositivo X tem permissão para acessar determinado dado, programa de computador ou serviço Y." (wikipedia)

Com essa diferença esclarecida vou falar um pouco sobre os plugins de autorização que eu considerei mais interessantes.

Um plugin de autorização é bem mais difícil de se implementar pois normalmente cada aplicação necessita de uma forma de controle de acesso diferente e personalizável.

Os plugins:

Vale lembrar que nossa necessidade era de autorização baseada em controle de acesso(RBAC).

1. Acl System:

O Acl System é um plugin bem simples, com pouco código e que baseia em um relacionamento has_and_belongs_to_many entre os modelos User e Role.

User <= habtm => Role

Seu uso é bem simples e não pretendo entrar em maiores detalhes já que está tudo explicado na documentação. Vou apenas mostrar um pequeno exemplo e comentar alguns pontos interessantes.

class PostController < ApplicationController
  before_filter :login_required, :except => [:list, :index]
  access_control [:new, :create, :update, :edit] => '(admin | user | moderator)',
                 :delete => 'admin & (!moderator & !blacklist)'

A implementação do método access_control busca os papeis de um usuário através da chamada current_user.roles. Essa implementação é bem interessante pelo fato de usar o método current_user para obter o usuário autenticado, tornando esse plugin compatível com o uso do Restful Authentication.

O ponto negativo é que a implementação do método access_control não permite aumentar a granularidade dando permissões específicas a um usuário sem precisar criar um novo papel com apenas essa permissão. Isso se dá ao fato dele ser "RBAC schema level 1".

Acredito que para muitos casos essa implementação é mais do que suficiente e o plugin funciona muito bem. Só não faço mais nenhum elogio a ele pois sua base de testes é ínfima.

2. Active RBAC:

O Active RBAC é bem mais complexo que o Acl System e seu entendimento não é a coisa mais simples do mundo. Esse plugin é bem completo e implementa o "RBAC schema level 2".

Arbac Schema Level 2

Novamente eu não vou entrar em detalhes do seu uso pois existe uma página explicando isso. Vou apenas fazer alguns comentários.

Como eu disse anteriormente, esse plugin é bem completo só eu considero completo demais! Ele implementa uma autenticação bem parecida com a do acts_as_authenticated, que já não é mais usado.

Na minha opinião esse é um dos pontos fracos desse plugin, já que o Restful Authentication trata a autenticação de uma forma bem melhor. Isso não quer dizer que ele é incompatível com o Restful Authentication, mas que me deu um pouco mais de trabalho para usar.

A documentação dos conceitos é bem feita, porém ele peca pela falta de exemplos na hora de detalhar como se usa. Definitivamente ele seria bem mais fácil de usar se tivesse uma documentação mais detalhada.

O plugin trabalha como uma espécie de módulos e isso permite que você utilize mesmo sem seguir os nomes de tabela que ele sugere. Esse é um ponto positivo pois ele é bem flexível tanto na parte dos modelos quanto na hora de checar as permissões nos controladores.

A parte ruim desses módulos é que algumas coisas não muito intuitivas e a falta de documentação torna seu entendimento bem complexo.

Ele tem um gerador para auxiliar o seu uso mas que é MUITO mal feito! Ele copia alguns arquivos e isso pode fazer o seu projeto parar de funcionar. Sem contar o fato dele copiar algumas migrations e não coloca-las com a numeração correta.

Segundo a documentação do Active RBAC ele está sendo reinscrito porém o SVN dele está sem modificações por mais de um ano. Isso me leva a suspeitar que ele foi abandonado.

Resumo

Ambos os plugins são bons, tem pontos positivos e pontos negativos mas não consigo considerar nenhum dos dois como uma solução definitiva para o problema da autorização. Infelizmente não consegui achar nenhum outro plugin melhor do que esses e resolvi partir para modificar o Active RBAC para resolver o cliente precisava usando o Restful Authentication. Gostaria de saber se alguém conhece algum outro plugin que seja bom.

Desde sexta feira ando pensando na possibilidade de fazer o meu próprio plugin para resolver esse problema só de uma certa forma seria reinventar a roda já que existem esses outros. Mas ao mesmo tempo eles não são perfeitos, então pensei em pegar o mais completo deles e fazer um fork.

Infelizmente não terei tempo para me dedicar sozinho a esse plugin já que eu estou envolvido em vários. Um dos motivos desse post é recrutar um time para desenvolver esse plugin junto comigo. Como eu sou uma pessoa muito chata eu tenho algumas exigências com relação ao plugin e não abro mão de nenhuma delas.

  1. O plugin deve ter testes para TUDO.

  2. Todo o código e a documentação deve ser em inglês já que será um plugin para uso global. Isso não impede uma documentação em português.

  3. A documentação deverá ser bem detalhada e com muitos exemplos.

  4. Vamos seguir o K.I.S.S.

Se você acredita na minha ideia, e concorda com as minhas exigências, entre em contato comigo.

9 comentários

O que você achou? Coloque seus comentários e sugestões abaixo!

Acompanhe o RSS dessa página.

Comentários (9 até o momento)

  1. Celestino Gomes disse aproximadamente 3 horas depois:

    Nem preciso dizer que estou dentro, né? Vamos logo rapá!

    :)

  2. Marcus Derencius disse aproximadamente 11 horas depois:

    Esse é um assunto bem bacana, pois ainda não achei o plugin ideal para autorização.

    Em projetos simples já usei o base_auth, que é bem legal mas sem nenhum teste e pouca documentação.

    O "authorization" é um outro bem legal baseado em DSL mas um pouco complexo.

    De qualquer maneira, vou participar dessa iniciativa.

    Abs. Marcus

  3. Ozéias Sant'ana disse aproximadamente 13 horas depois:

    Eu uso o simples access control, mais tem limitações.

    Então também estou dentro!

    []'s

  4. Eduardo Fiorezi disse aproximadamente 14 horas depois:

    No que puder ajudar estou dentro..

    Abraços

  5. Alisson disse aproximadamente 20 horas depois:

    Eu simplesmente uso STI, não é a melhor alternativa, mas é simples e direta!

  6. Bueno disse 1 dia depois:

    Acabei de encontrar esse cara no Del.icio.us: http://lockdown.rubyforge.org/

    Não testei ainda. Mas eles prometem resolver problemas de autorização/autenticação.

  7. Everton J. Carpes disse 7 dias depois:

    Ola, eu tou dentro de ajudar e concordo sim com os termos.

    No ultimo FISL discuti bastante sobre isso, pq esse eh um problema que a muito me incomoda. Pelo que lembro, ateh mostrei algumas coisa que eu fiz para o Vinicius Teles.

    Tenho algumas coisas que venho construindo a tempos com intuito de solucionar esse mesmo problema em projetos onde trabalhei. Estas coisas estao agrupadas no formato de uma engine, mas somente atendendo minhas necessidades mais praticas. A maior deficiencia hj dela eh que nao esta testada e as actions nao estao em EN... na verdade eu jamais coloquei elas em EN pq nao cheguei a nenhuma conclusao sobre como aplicar de forma nao intrusiva i18n e l10n na coisa (acredite isos eh um desafio quando se fala de plugins)!

    O que eu fiz nao inclui authenticacao, pois considero que eh um problema isolado e com varias solucoes jah apresentadas.

    Em relacao ao controle de acesso, eu nao apliquei o controle diretamente sobre controllers/actions... na verdade eu construi um conceito orientado por roles e "categorias de ferramentas"... atraves da Engine tu define que determinada action pertence a uma determinada "categoria"... eu fiz isso, pq nos projetos em que apliquei o controle de acesso, varias roles tinham conceitos iguais de acesso para roles em certos controllers separados... desta forma eu tive uma liberdade maior para definicao de controle.

    O controle propriamente eh feito atraves de filtros, mas isto eh praticamente indiferente... basicamente eu construi varios methodos que facilitam a verificacao de controle de acesso baseado naquilo que eu chamei de funcoes, que na verdade sao uma das 4 operacoes CRUD... explicando melhor:

    O engine possui controle de acesso onde tu discrimina que determinada role tem acesso para ler e criar (C e R) em determinada categoria de ferramentas... e em outro lado vc discrimina que determinada action pertence a esta ou aquela categoria.

    Para que o sistema saiba que a action X eh na verdade C, R, U ou D eu criei uma micro "DSLzinha" para os controllers que funciona +- como as definicoes private, protected, public, ou seja, no controller vc diz:

    class PostsController < ApplicationController
    
    def index 
      ...
    end
    
    def show
      ...
    end
    
    create
    def new
      ...
    end
    
    def create
      ...
    end
    end
    

    A partir de onde vc disse create, todas as actions serao consideradas do tipo Create (o default eh Read).

    Com isso, o controle de acesso ficou bastante simples, pois a engine adiciona no modelo de usuario (atraves de um actsas***), methodos do tipo cancreate?, canupdate? e claro canaccess?, onde vc passa o nome do controller e action que deseja ter verificar e o methodo retorna true ou false.

    Eu agreguei a isso mais algumas funcionalidades, onde por exemplo, eu sobrescrevi os linkto e linkto_remote para utilizarem o mesmo sistema de controle de acesso e retornar '' (string em branco) se o cara nao tem acesso.

    Como dah pra ver pelo exemplo do controller acima, eu construi essa DSL para poder associar a uma funcao, mesmo as telas "anteriores" a action em si, como por exemplo o new. Isso pra mim eh essencial, pq se uma pessoa nao pode criar determinada coisa, ela nao pode nem mesmo acessar a action new. Claro que isso ainda me deixou com um problema: quando eu tenho um formulario em uma action Read que serve pra create (como por exemplo este formulario de comentario que esta na show de um post!). Para estes casos a solucao soh eh possivel se vc enclausurar TUDO do formulario no proprio form e sobrescrever o formtag da mesma forma que o linkto (eu particularmente ainda nao testei isso).

    Eu construi uma feature a pouco que era essencial para mim: actions publicas... que sao actions que burlam este esquema de controle de acesso. Nesse caso, vc alem de ter as 4 funcoes (CRUD) ainda pode dizer que ela eh publica e daih o sistema ignora a verificacao.

    A minha engine entre ouras coisas, carrega dados de TODOS os controlers que estiverem no path da aplicacao, inclusive o de outras engines e dela propria. Na propria interface existem formas de tu recarregar estas informacoes, e para inicio de uso eu criei uma migration que tbm faz uma carga inicial, que na verdade cria previamente uma categoria para cada controllers e joga as actions de cada controller nestas categorias (isso eh soh pra facilitar o inicio do uso).

    A unica coisa mais critica que nao tenho ainda eh controle de acesso baseado no owner de algum recurso (fulano pode editar posts, mas soh se os mesmos forem dele)! Essa eh a proxima feature que eu pretendo implementar! Para tal precisarei reimplementar muita coisa, pois ateh hj nada levava em consideracao os ids, se limitando a controllers/actions...

    Buenas, como falei isso tudo eu fui criando para uso pessoal, pq sempre achei que era algo MUITO intrusivo, mas nao tenho nenhum problema em liberar isso. Jah aviso, o coohdigo nao tah testado e ainda tem problemas, mas muitos dos problemas que vcs irao passar ao tentar fazer essa coisa, eu jah passei (como o problema da carga dos controllers/actions, etc). Mesmo que nao queiram utilizar o que eu criei, acho que eh interessante para terem uma base, ou referencia.

    De qqr forma, eu aproveito o embalo e peco mais uma vez (eu fiz isso no passado, na lista nacional), que se alguem tiver interesse em me ajudar, entre em contato. Quem sabe poderiamos juntar forcas e atingir um sistema de controle de acesso realmente interessante para todos. Acredito que isso ainda seja uma deficiencia no mundo Rails, pois a muito venho procurando algo que realmente satisfaca o problema, ou pelomenos minimize-o, e assim como eu, varias outras pessoas devem procurar o mesmo... uma prova eh este post oO

    O que eu fiz ateh aqui nao solucionou todo o problema, mas jah minimizou muita coisa e estou realmente perto de chegar aonde eu queria com a engine. Qqr ajuda eh super bem vinda!

  8. Tapajós disse 10 dias depois:

    Pessoal, eu não desisti do projeto não. Estou um pouco sem tempo para analisar as alternativas que me foram passadas. Quero analisar tudo antes para evitar de começar um projeto que já exista um bom. Se já existir um +/- completo é só partir para colaborar nele.

    []'s

  9. Guilherme disse aproximadamente 1 ano depois:

    Olá, como está o andamento dessa ideia?

    abs.