Aqui na UFABC possuímos uma base para autenticação de usuários centralizada no LDAP. Para evitar desconfortos aos usuários, bem como para facilitar a vida de nós, que desenvolvemos as aplicações e, é claro, as interfaces de login em cada uma delas, comecei a pesquisar maneiras de realizar um Single Sign-On (SSO) para todas as aplicações já em produção e para as futuras.
Inicialmente pensei em simplesmente criar uma sessão genérica que pudesse ser acessada por diversas aplicações, porém, o que parecia ser mais simples e rápido acabou se mostrando menos seguro e infinitamente menos portável. Logo desisti da idéia e comecei a pesquisar outras soluções de SSO.
O Maurício me indicou uma série de sistemas/bibliotecas baseados em diferentes protocolos, todos para Ruby. No meio da lista o Rubycas me chamou atenção, principalmente por utilizar um protocolo já utilizado e implementado em forma de clients para outras linguagens e por possibilitar a autenticação no LDAP.
Não vou entrar em detalhes sobre a história e funcionamento do protocolo CAS de SSO, mas suas primeiras implementações foram feitas em Java, quando se tornou um projeto da Jasig.
Para saber mais sobre como funciona o protocolo CAS visite este link. Basicamente existe um server que é uma interface web que autentica um usuário em alguma base de autenticação (LDAP no caso da UFABC) e redireciona para algum client que é sua aplicação.
A primeira coisa que fiz após ler um pouco sobre o protocolo CAS e sobre o projeto Rubycas foi tentar fazer o download do rubycas-server, seguindo as instruções desta página, instalei a gem rubycas-server em uma nova rvm gemset e segui as instruções desta e desta pagina. As dores de cabeça começaram.
A gem possui dependências de gems antigas, o que ocasionou diversos problemas em alguns requires e em alguns métodos. Fiz alguns monkey patch’s para corrigir estes probleminhas, e após brigar muito com seu arquivo de configuração consegui fazer subir um “Frankenstein” no Webrick.
Foi um avanço, comecei a implementar os clients pois estava com pressa, mas mais tarde voltei ao server, definitivamente eu não queria fazer deploy de um Frankenstein:
- Clonei este projeto (O projeto!) do Github: $ git clone git://github.com/gunark/rubycas-server.git meu_diretorio/rubycas-server;
- Entrei na pasta do projeto, editei o arquivo rubycas-server.gemspec e troquei a dependência da gem sqlite3 pelo meu adaptador de bd preferido;
- Instalei todas as dependências: $ bundle install
- Executei $ ./bin/rubycas-server e o arquivo localizado em ./config/config.example.yml foi automaticamente copiado para /etc/rubycas-server/config.yml
- Editei o arquivo /etc/rubycas-server/config.yml configurando o meu servidor e porta da aplicação, o meu adaptador de banco de dados, e meu modo de autenticação (LDAP);
- Fiz a aplicação subir localmente no Webrick rodando novamente $ ./bin/rubycas-server
- Testei a aplicação em http://localhost:<porta_escolhida> e visualizei a interface de login com sucesso!
- Para fazer deploy, como centralizamos nossos códigos no SVN, importei o projeto para nosso servidor SVN e fiz o checkout na máquina de produção;
- Dentro da pasta do projeto na máquina de produção repeti as etapas 3, 4 e 5, mas no arquivo de configuração não escolhi o meu servidor (webrick, mongrel, phusion passenger – apache, etc);
- Como iria publicar o rubycas-server no Apache (com o Phusion Passenger previamente instalado) entrei no diretório /etc/apache2/vhosts.d e criei um novo arquivo de configuração direcionando o meu host para a pasta da minha aplicação;
- Reiniciei o Apache e minha interface de login (Rubycas-server) passou a funcionar em produção desde então!
RUBYCAS CLIENT
A instalação e configuração do rubycas-client foi bem menos traumática. Transformei duas de nossas aplicações em dois clients para se autenticarem noserver que eu já tinha configurado:
- Instalei a gem rubycas-client;
- Entrei no diretório do projeto da minha aplicação;
- Editei o arquivo ./config/environment.rb em uma aplicação feita em Rails 2.x.x e ./config/application.rb em uma feita em Rails 3.x.x e inseri o seguinte código:
require 'casclient' require 'casclient/frameworks/rails/filter' CASClient::Frameworks::Rails::Filter.configure( :cas_base_url => "https://<meu_server>/" ) - Editei o arquivo ./app/controllers/application_controller.rb e inseri o seguinte código no início do arquivo: before_filter CASClient::Frameworks::Rails::Filter
- Apartir deste momento as aplicações já passaram a funcionar como clients. Um client se comporta basicamente da seguinte maneira: Verifica se a sessão cas_user existe, caso positivo cabe à sua aplicação decidir se fornece ou não permissão ao usuário logado, caso negativo redireciona o usuário para o rubycas-server, onde deve ser feita a autenticação, caso o usuário digite seu login e senha corretamente ele é redirecionado para a aplicação anterior (client), com a sessão cas_user contendo uma string com seu nome de usuário;
- O client é bastante flexível. A documentação (http://rubycas-client.rubyforge.org/) me ajudou bastante, principalmente para me ajudar a implementar o logout e a fazer os testes automatizados
Vale lembrar que os clients do CAS podem ser implementados em outras linguagens além do Ruby (Java, PHP, .NET, etc), veja aqui.
Espero que tenha ajudado, ou ao menos dado alguma idéia. Qualquer coisa podem entrar em contato!


