Costruiamo un sistema di autenticazione con Sinatra e Warden - Parte 3

Nella prima puntata di questa mini serie abbiamo visto tutta la business logic per autenticare i nostri utenti, censiti su un LDAP. Nella seconda puntata abbiamo visto all’opera Warden ed abbiamo constatato quanto sia semplice farne il setup di fatto realizzando un solido sistema di autenticazione con veramente poche linee di codice.

Photo by John Haslam

Nella prima puntata di questa mini serie abbiamo visto tutta la business logic per autenticare i nostri utenti, censiti su un LDAP. Nella seconda puntata abbiamo visto all’opera Warden ed abbiamo constatato quanto sia semplice farne il setup di fatto realizzando un solido sistema di autenticazione con veramente poche linee di codice.

Oggi ci concentriamo con le rotte, le viste e come bonus track scriviamo uno script che faccia funzioni di console per il debug, Sinatra non ha infatti un equivalente a rails console per intenderci.

Quattro rotte, quattro

Ci servono 4 endpoint per gestire l’autenticazione dei nostri utenti.

Atterraggio

La rotta più semplice gestisce l’atterraggio di utenti non autenticati al sistema. Solitamente a questo link si viene gentilmente accompagnati quando si tenta di accedere ad una risorsa protetta.

get '/' do
  redirect '/auth/login' unless authenticated?
end

Quello che andremo a fare è unicamente presentare la maschera di login.

get '/auth/login' do
  haml :login
end

Il nostro login.haml (che andremo a posizionare nella directory views/ sarà simile a questo.

.container
  %form.form-signin{:action => "/auth/login", :method => "post"}
    %span#reauth-email.reauth-email
    %input#inputEmail.form-control{:autofocus => "", :placeholder => "Domain user", :required => "", :type => "text", :name => "user[username]"}/
    %input#inputPassword.form-control{:placeholder => "Password", :required => "", :type => "password", :name=>"user[password]"}/

Scopriamo quindi la seconda rotta che dovremo implementare, quella che gestisce il submit della form.

Biglietti prego

Nella rotta che gestisce la POST ad /auth/login dobbiamo chiamare warden e chiedere di autenticare il nostro utente. Se ci ricordiamo quando abbiamo definito le nostre strategie di autenticazione, abbiamo implementato un metodo authenticate! che invocava il metodo opportuno della classe User per autenticare il nostro utente.

Ora è giunto il momento di connettere i punti, quindi in risposta a questa POST, passeremo la palla a Warden.

post '/auth/login' do
  env['warden'].authenticate!
  flash[:success] = env['warden'].message

  if session[:return_to].nil?
    redirect '/'
  else
    redirect session[:return_to]
  end
end

Ricordate che di default, quando abbiamo configurato Warden abbiamo indicato /auth/unauthenticated come action nel caso l’autenticazione non vada a buon fine.

Si ritorni in fila

La nostra terza rotta sarà quindi quella di default quando l’autenticazione non va a buon fine. Tuttavia qui c’è veramente poco da fare.

post '/auth/unauthenticated' do
 redirect '/'
end

E’ stato bello

L’ultima rotta che dobbiamo dare ai nostri utenti è quella per il logout volontario.

get '/auth/logout' do
  env['warden'].raw_session.inspect
  env['warden'].logout
  flash[:success] = 'Successfully logged out'
  redirect '/'
end

Anche in questo caso ci affidiamo ad un metodo di default di Warden per il logout.

Console

Come promesso ecco la bonus track. In Sinatra non c’è come dicevamo, l’equivalente di rails console o della console di padrino. A volte, anzi sempre, è utile testare modelli, helper via IRB. Per fare questo il nostro script, che chiameremo /bin/console, non dovrà fare altro che includere la nostra applicazione, app.rb, ed avviare IRB.

#!/usr/bin/env ruby

require 'irb'
require './app'

IRB.start
Kernel.exit(0)

Tutto qui? Sì, tutto qui. Se lo confrontate con il config.ru, noterete che sono pressoché identici. La differenza più importante è che, al posto di lanciare la nostra applicazione, si lancierà IRB.

require './app'

run Unlock

Nel caso di config.ru più complessi e quindi applicazioni Sinatra con più modelli, più controller, un mapping delle rotte più granulare la regola aurea per creare un bin/console è quella di copiare il config.ru, eliminare l’ultima parte del file ed avviare IRB dopo che sono state caricate tutte le dipendenze. L’ultima riga, la Kernel.exit(0) ci assicura che non parta Sinatra una volta usciti da IRB, facendo terminare correttamente lo script.

Off by one

Abbiamo quasi finito. Il nostro sistema ora permette di autenticare gli utenti su active directory e gestire la loro sessione tramite Warden. Nella prossima puntata inseririremo la protezione per il cross site request forgery ed un meccanismo per inserire controlli per evitare l’immissione di password troppo semplici da parte dei nostri utenti.

Enjoy it!

comments powered by Disqus