OpenID対応

http://project.webjourney.org/issues/show/4

認証用のユーザーID, パスワード管理に解放されたくてConsumerを書いています。

まず、openid用のライブラリを導入。

sudo gem install ruby-openid

Railsで簡単なテスト用Applicationを書く。gem の中にサンプルがあるのでそれをさらにミニマイズしたものが以下。

# app/controller/id_test_controller.rb

require 'openid'
require 'openid/store/filesystem'

class IdTestController < ApplicationController
  def index
  end

  def begin
    @openid_url = params[:openid_url]
    if request.post?
      begin
        request = consumer.begin(@openid_url)
        redirect_to request.redirect_url(url_for(:controller =>''), return_to)
      rescue OpenID::OpenIDError => e
        flash[:error] = "Error authentication (#{e.message})."
        redirect_to :action => "index"
      end
    else
      redirect_to :action => "index"
    end
  end

  def complete
    parameters = params.reject{|k,v|request.path_parameters[k]}
    response = consumer.complete(parameters, return_to)
    case response.status
    when OpenID::Consumer::FAILURE
      flash[:error] = "Authentication Failure (#{response.message})."
      redirect_to :action => "index"
    when OpenID::Consumer::SUCCESS
      # ここに認証成功の処理を書く

    end
  end

  private
  def return_to
    url_for(:action => "complete", :only_path => false)
  end

  def consumer
    if @consumer.nil?
      dir = File.join(RAILS_ROOT, "tmp", "idstore")
      store = OpenID::Store::Filesystem.new(dir)
      @consumer = OpenID::Consumer.new(session, store)
    end
    @consumer
  end
end
<%# app/views/id_test/index.html %>
<html>
<body>
<h1>OpenID Consumer Test</h1>
<div><%= flash[:error] %></div>
<% form_tag :action => 'begin' do %>
<%= text_field_tag 'openid_url', @openid_url %>
<%= submit_tag 'login' %>
<% end %>
</body>
</html>
<%# app/views/id_test/complete.html %>
<html>
<body>
<h1>OpenID Authentication Success!!</h1>
</body>
</html>
  • consumer.begin で共通鍵を生成して、ユーザーにはOpenID Providerのサイトへリダイレクトしておく
  • ユーザーの認証情報がOpenID Providerサイトへ入力され、認証処理が行われる。
  • 結果がパラメーターで渡されて、Consumerサイトへ再度リダイレクトされる。
  • Consumerサイトでは、Filesystemからconsumerの情報をとって、認証結果を照合して、認証できたかどうかを判定できる。

なるほど。実際にコードを書いてみるまでよくわからなかったけど、これは中々おもしろい仕組みだなぁと。どこまでできるのかは要チェックかも。

とりあえず、既存のWjUserモデルには openid_url を追加すれば対応できそう。パスワードが不要になったり、いろいろとvalidationを買えなければならないけれど。あとはAjaxの部分HTMLで認証画面を遷移させている部分。。。iframeにすればOK??