RailsでGoogle AppsのOpenID対応アプリを作る
RailsでGoogle Apps for your domainにOpenID認証をするサンプルアプリを作りました。
以下、サンプル作成手順です。
ruby-openidとruby-openid-apps-discoveryをインストール
>gem install ruby-openid >gem install ruby-openid-apps-discovery
app/controllers/consumer_controller.rbを作成
require 'pathname' require "openid" require 'openid/extensions/ax' require 'openid/store/filesystem' require 'gapps_openid' class ConsumerController < ApplicationController layout nil def index # render an openid form end def start begin domain = params[:domain] if domain.nil? flash[:error] = "Enter an Google Apps Domain" redirect_to :action => 'index' return end oidreq = consumer.begin(domain) rescue OpenID::OpenIDError => e flash[:error] = "Discovery failed for #{domain}: #{e}" redirect_to :action => 'index' return end ax = OpenID::AX::FetchRequest.new ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/contact/email', 'email', true)) ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/namePerson/first', 'firstname', true)) ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/namePerson/last', 'lastname', true)) oidreq.add_extension(ax) return_to = url_for :action => 'complete', :only_path => false realm = url_for :action => 'index', :only_path => false if oidreq.send_redirect?(realm, return_to) redirect_to oidreq.redirect_url(realm, return_to) else render :text => oidreq.html_markup(realm, return_to, {'id' => 'openid_form'}) end end def complete # FIXME - url_for some action is not necessarily the current URL. current_url = url_for(:action => 'complete', :only_path => false) parameters = params.reject{|k,v|request.path_parameters[k]} oidresp = consumer.complete(parameters, current_url) case oidresp.status when OpenID::Consumer::FAILURE if oidresp.display_identifier flash[:error] = ("Verification of #{oidresp.display_identifier}"\ " failed: #{oidresp.message}") else flash[:error] = "Verification failed: #{oidresp.message}" end when OpenID::Consumer::SUCCESS flash[:success] = ("Verification of #{oidresp.display_identifier}"\ " succeeded.") ax_resp = OpenID::AX::FetchResponse.from_success_response(oidresp) ax_message = "Attribute Exchange data was requested" if ax_resp.data.empty? ax_message << ", but none was returned." else ax_message << ". The following data were send:" ax_resp.data.each {|k,v| ax_message << "<br/><b>#{k}</b>: #{v}" } end flash[:ax_results] = ax_message when OpenID::Consumer::SETUP_NEEDED flash[:alert] = "Immediate request failed - Setup Needed" when OpenID::Consumer::CANCEL flash[:alert] = "OpenID transaction cancelled." else end redirect_to :action => 'index' end private def consumer if @consumer.nil? dir = Pathname.new(RAILS_ROOT).join('db').join('cstore') store = OpenID::Store::Filesystem.new(dir) @consumer = OpenID::Consumer.new(session, store) end return @consumer end end
app/view/consumer/index.html.erbを作成
<html> <head> <title>Rails OpenID Example for Google Apps</title> </head> <style type="text/css"> * { font-family: verdana,sans-serif; } body { width: 50em; margin: 1em; } div { padding: .5em; } .alert { border: 1px solid #e7dc2b; background: #fff888; } .error { border: 1px solid #ff0000; background: #ffaaaa; } .success { border: 1px solid #00ff00; background: #aaffaa; } #verify-form { border: 1px solid #777777; background: #dddddd; margin-top: 1em; padding-bottom: 0em; } </style> <body> <h1>Rails OpenID Example for Google Apps</h1> <% if flash[:alert] %> <div class='alert'> <%= h(flash[:alert]) %> </div> <% end %> <% if flash[:error] %> <div class='error'> <%= h(flash[:error]) %> </div> <% end %> <% if flash[:success] %> <div class='success'> <%= h(flash[:success]) %> </div> <% end %> <% if flash[:ax_results] %> <div class='alert'> <%= flash[:ax_results] %> </div> <% end %> <div id="verify-form"> <form method="get" accept-charset="UTF-8" action='<%= url_for :action => 'start' %>'> Domain: <input type="text" class="openid" name="domain" /> <input type="submit" value="Verify" /> </form> </div> </body> </html>
environment.rbを修正
DBは使わないので、active_recordを使わないように設定
config.frameworks -= [ :active_record ]
修正ポイント
このコードは以下の場所にあるruby-openidのサンプルを基にしています。
lib\ruby\gems\1.8\gems\ruby-openid-2.1.7\examples\rails_openid
そこからの修正ポイントは以下の通りです。
ドメインのみを入力すれば認証できるようにする
require 'gapps_openid'
って書きます。こう書くとドメインからOPのエンドポイントURLを探してきて、それで認証しようとしてくれます。
詳しくは⇒Discovering OpenID Endpoints for Hosted Domains - Google Federated Login API | Google Groups
Attribute Exchangeでログインユーザのアカウント情報をGoogleから取得
GoogleはAttribute Exchangeを使って、ユーザの属性情報を渡してくれます。
AXで渡してって書きます。
ax = OpenID::AX::FetchRequest.new ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/contact/email', 'email', true)) ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/namePerson/first', 'firstname', true)) ax.add(OpenID::AX::AttrInfo.new('http://axschema.org/namePerson/last', 'lastname', true)) oidreq.add_extension(ax)
返ってきたのを受け取ります。
ax_resp = OpenID::AX::FetchResponse.from_success_response(oidresp)
動かしてみます
>ruby script\server
http://localhost:3000/にアクセス。
Google Appsのドメインを入力します。
ログイン&アカウント情報取得できました。
終わり。次はOAuthとMarketplace。