Login centralizzato tra applicazioni Rails
In un articolo precedente ho affrontato la questione del login centralizzato tra più applicazioni attraverso il protocollo CAS (Central Authentication Service). La soluzione presentata risulta una buona scelta nel momento in cui si debba gestire un’autenticazione comune tra applicazioni eternogenee, web o desktop, scritte in Rails, Java, PHP, Python o .NET.
Se però consideriamo una suite di applicazioni sviluppate in Ruby on Rails su uno stesso dominio, possiamo “giocare” con la gestione delle sessioni per condividere le credenziali degli utenti tra le applicazioni della suite.
Tipicamente, infatti, il controllo degli accessi viene implementato attraverso il salvataggio in sessione di un identificativo dell’utente, in seguito all’inserimento da parte di quest’ultimo di username e password validi. La condivisione dell’autenticazione, quindi, si riconduce alla condivisione delle sessioni tra le applicazioni.
Rails e le sessioni
In Rails una sessione è una struttura simile ad un hash (coppie chiave-valore) che permette di rendere persistenti i dati tra una richiesta e l’altra. In sessione può essere salvato ogni tipo di dato, dal momento in cui questi vengono serializzati in una delle seguenti opzioni di storage:
- CookieStore (default)
- ActiveRecordStore
- SQLSessionStore
- DRBStore
- MemCacheStore
I criteri di scelta del tipo di session storage variano in funzione dei requisiti di spazio, sicurezza e performance. La soluzione basata sui cookie, ad esempio, è caratterizzata da un limite di storage di 4K ma da una velocità molto superiore rispetto alle altre. Questo è il motivo per cui è stata scelta come opzione di default. L’integrità dei dati è supportata dalla crittazione delle informazioni attraverso un algoritmo di digest (SHA1) e una chiave segreta univoca per ogni applicazione. Due applicazioni, quindi, condividono la stessa sessione se condividono la stessa chiave.
Login centralizzato
Consideriamo una suite di applicazioni identificate da sottodomini diversi dello stesso dominio:
- app1.example.com
- app2.example.com
- app3.example.com
Per fare in modo che le applicazioni condividano la sessione, è sufficiente specificare in ogni environment.rb la stessa configurazione:
1 config.action_controller.session = { 2 :session_key => '_example_session', 3 :secret => 'shared_secret_long_string' 4 } 5 6 # rails 2.3 7 config.action_controller.session[:domain] = '.example.com' 8 9 # per le versioni di rails precedenti alla 2.3 10 # ActionController::Base.session_options[:session_domain] = '.example.com'
Supponiamo che app1 contenga il model User e la logica di autenticazione. Una volta effettuato l’accesso, anche app2 e app3 vedono lo stesso user_id in sessione. A questo punto basta definire in app1 e app2 il model User connesso al database di app1:
1 2 self.abstract_class = true 3 establish_connection( 4 :adapter => "mysql", 5 :host => "localhost", 6 :username => "ateapick", 7 :password => "supersecret", 8 :database => "app1" 9 ) 10 end
Un caso di studio: formula-brake.com
Di recente abbiamo implementato un’autenticazione centralizzata su una serie di webapp aziendali per Formula, uno dei nostri clienti. In particolare, una delle applicazioni (security.formula-brake.com) ha un’area riservata per la gestione di tutti gli utenti aziendali e dei loro privilegi ed una parte pubblica che funge da gateway di autenticazione per tutte le altre applicazioni.
Per la gestione delle sessioni utente abbiamo utilizzato authlogic, un’ottima gemma realizzata dal bravissimo Ben Johnson di Binary Logic.
Per passare da una webapp all’altra, esiste infine un header condiviso con i link a tutte le applicazioni della suite, sulla falsa riga di quello presente su Google.
