Devise を知るにはまず Warden を知るが良い

背景

devise という gem があるが、warden をベースにした認証の仕組みだということだった。
devise を知るには、まず warden を知らなければなるまい。
そう思った俺は warnden を rack ベースでいじってみることにした。

warden とは

これのこと。
https://github.com/hassox/warden
wiki が充実していたのでかなりわかりやすかった。
https://github.com/hassox/warden/wiki

とりあえずやってみる、以下メモ書き。

config.rb

require 'rack'
require 'pp'
require 'warden'

class Application

  def call(env)
    request = Rack::Request.new(env)
    response = if request.path_info = '/'
                 body = "#{request.request_method}: Hello! #{request.params['name']}!"
                 Rack::Response.new(body, "200", {'Content-Type' => 'text/plain'})
               else
                 Rack::Response.new('Not Found', "404", {'Content-Type' => 'text/plain'})
               end
    response.finish
  end

end


app = Rack::Builder.new do
  use Rack::Session::Cookie, :secret => "replace this with some secret key"

  use Warden::Manager do |manager|
    manager.default_strategies :password, :basic
    #manager.failure_app = BadAuthenticationEndsUpHere
  end

  run lambda { |env| Application.new().call(env) }
end

run app

基本的に, default_strategies で定義した順に行われて、一つでも成功したら成功になる模様。

cookie セットされている

試しに nil を返した時。

明らかに error ハンドラがないぞッて感じのエラーが出ているので、
雰囲気でBadAuthenticationEndsUpHere クラスを足してみる。

class BadAuthenticationEndsUpHere
  def self.call(env)
    p env
    p "BadAuthenticationEndsUpHere"
    Rack::Response.new('Not Found', "404", {'Content-Type' => 'text/plain'})
  end
end

思い通りだ。 error ハンドラとして BadAuthenticationEndsUpHere クラスが呼ばれた。

それでは、正しく期待している serialize_from_session が動くように User.get を定義する。

def get(id)
    ## 永続化されたものから引いてうまく引けたと過程して返す
    return User.new(id)
  end

1回目、とりあえずログインされるはず。

サーバのデバッグログ

“Authenticate!!!!!!!!!!!!”
“serialize into session!!!!!!!!!!!!”

ログから、セッションに値が仕込まれた模様。

2回目、セッションから値を引いてみる。
あれ、ミス。。あ、 serialize_from_session が読んでるのは User.get(id) だから class method だった。。
修正して再チャレンジ。

ちゃんときたっぽい!

デバッグログ

“Authenticate!!!!!!!!!!!!”
“serialize from session!!!!!!!!!!!!”
127.0.0.1 - - [01/Mar/2014 18:54:54] “GET /?password=hoge HTTP/1.1” 200 13 0.0022

get されている模様!

これで user にアクセスできる。

p "warden user is "
p env['warden'].user

ドキュメントを読むと、
Warden::Strategies で定義した #valid? に関しては、定義されてようがなかろうが呼ばれるらしい。

試しにこの時点で #valid? で nil を返すと次の strategy にチャレンジがうつった。
すべての strategy で失敗したら、 failure_app が呼ばれる。

特筆すべきは、ここで呼ばれるのが /unauthenticated だということだ。
この url http://localhost:9292/?password=hoge を叩くと
127.0.0.1 - - [01/Mar/2014 19:01:45] “GET /unauthenticated?password=hoge HTTP/1.1” 404 9 0.0012
がデバッグログに表示されている。

class BadAuthenticationEndsUpHere
  def self.call(env)
    p "in BadAuthenticationEndsUpHere!!!!!!!!!!!!"
    request = Rack::Request.new(env)

    p "request.path_info is "
    p request.path_info

    Rack::Response.new('Not Found', "404", {'Content-Type' => 'text/plain'})
  end
end

をデバッグとして試しに書いてみた。
やはり、内部的に path_info を unauthenticated に書き換えているようだ。
これは lib/warden/manager.rb のあたりを見ればわかる。
def process_unauthenticated(env, options={})

def call_failure_app(env, options = {})
で実際にそのように書かれている。
と思ったら
https://github.com/hassox/warden/wiki/Failures
ここにめっちゃそのように書いてあった。

halt! や success など便利なメソッドが strategy で使える模様。
https://github.com/hassox/warden/wiki/Strategies 詳細はコチラを参照。

このような認証の仕組みが rack で使えて、 認証自体が strategy パターンになっているので
いい感じに他の人が作った strategy を使えるようになっている。

https://github.com/hassox/warden/wiki/Setup#advanced-setup-with-scopes
これを見ると、warden は、認証の scope を分けられるようになっている。
それぞれの認証で、違うロジックを定義して、認証できるようだ。
特に指定がない場合は、 env[‘warden’] は user として認証する。
しかし、これは上書きができるようだ。
default の設定上書きとは別に、明示的にスコープを指定することもできる。

env['warden'].authenticate! :scope => :api

callback

"serialize into session!!!!!!!!!!!!"
"after_set_user caled!"
"auth is"
Warden::Proxy:70106638122900 @config={:default_scope=>:default, :scope_defaults=>{}, :default_strategies=>{:_all=>[:password, :basic]}, :intercept_401=>true, :failure_app=>BadAuthenticationEndsUpHere}
"logout called!!!!!!!!!!!"
"in BadAuthenticationEndsUpHere!!!!!!!!!!!!"
"request.path_info is "
"/unauthenticated"
127.0.0.1 - - [01/Mar/2014 19:55:10] "GET /unauthenticated?password=hoge HTTP/1.1" 404 9 0.0025

これも結構参考になる。
https://gist.github.com/lukesutton/107966

所感

warden 大体わかった。

このエントリーをはてなブックマークに追加