第4回では、 RailsのOpenID Authenticationプラグインを使って、
そのため、 OpenID認証だけでなくパスワードによる認証も併用したい場合もあります。そこで前回作成したアプリケーションを改造し、
また、
パスワードによる認証機能を提供するRESTful Authentication
第4回でも軽くご紹介しましたが、 RESTful Authentication はパスワードによる認証機能を提供する Rails プラグインです。これまでによく使われていたacts_
- salt付きハッシュによるパスワードの暗号化
(パスワードを復号できないので、 正確には暗号化ではなくハッシュ化です) - メールアドレスを用いたユーザのアクティベーション
- Cookieを用いた
「次回から自動的にログイン」 機能
RESTful Authenticationプラグインは、
$ ./script/plugin install restful_authentication
プラグインをインストールすると、
$ ./script/generate authenticated user sessions
generateコマンドを実行すると、
パスワード認証機能の組み込み
第4回で作成した画面遷移図を、

色がついている画面や矢印が、
(1) 利用者がIDとパスワードを入力し、ログインボタンをクリックします (2) 利用者から送信されたパラメータを解析し、OpenID認証とパスワード認証のどちらであるかを判定します (2-A) パスワード認証であればデータベースに登録したパスワードと照合し、一致すればログイン成功とみなしサービス画面を表示します (2-B) パスワードが一致しなければログイン画面にエラーメッセージを表示します(2-C) OpenID認証であれば外部のOpenID Providerへ利用者を誘導します(従来の機能)
また、
コントローラ | アクション | 修正内容 |
---|---|---|
Sessions | new | IDとパスワードの入力フォームを追加 |
Sessions | create | パスワード認証を利用するユーザの認証処理を追加 |
Users | new | パスワード認証を利用するユーザの登録フォーム画面を追加 |
Users | create | パスワード認証を利用するユーザの登録処理を追加 |
ログイン処理の修正(Sessionsコントローラ)
まずはログイン画面から修正します。これまでのログイン画面はOpenIDのアカウント名を入れるフォームが存在するだけでした。ここに、

OpenIDでのログインとパスワードでのログインのどちらであっても、
def create
if using_open_id?
# OpenID による認証
open_id_authentication
else
# パスワードによる認証
password_authentication
end
end
using_

open_
def open_id_authentication
# OpenID でユーザを認証する (begin, completeの両方に対応)
authenticate_with_open_id do |result, identity_url|
# 第4回と同じコードのため省略
end
end
password_
def password_authentication
# ID とパスワードでユーザを認証する
self.current_user = User.authenticate(params[:login], params[:password])
if logged_in?
# サービス画面へ遷移する
successful_login
else
failed_login 'ユーザIDまたはパスワードが異なっています'
end
end
ちなみに、
ユーザ登録処理の修正(Usersコントローラ)
パスワード認証の利用者とOpenID認証の利用者では、
- パスワード認証 … ユーザが入力したパスワードを登録する
- OpenID認証 … OpenID認証によって確認できたOpenIDアカウント名
(User-Supplied Identifier) を登録する
パスワード認証の場合のユーザ登録画面は、

OpenID認証の場合のユーザ登録画面は、

ホワイトリストを使ってログインを許可するOPを制限する
連載の始めに、
この問題は、
OPを識別する方法
今回はOPを制限する一つの方法として、
さて、

ちなみに、
$ ./discover flickr.com ================================================== Running discovery on flickr.com Claimed identifier: http://flickr.com/ Discovered services: 1. Server URL : https://open.login.yahooapis.com/openid/op/auth Type URIs: * http://specs.openid.net/auth/2.0/server * http://specs.openid.net/extensions/pape/1.0 $ ./discover yahoo.com ================================================== Running discovery on yahoo.com Claimed identifier: http://www.yahoo.com/ Discovered services: 1. Server URL : https://open.login.yahooapis.com/openid/op/auth Type URIs: * http://specs.openid.net/auth/2.0/server * http://specs.openid.net/extensions/pape/1.0
ログイン処理の改造
ホワイトリストを管理するために、
@@ -25,9 +25,13 @@
protected
def open_id_authentication
# OpenID でユーザを認証する (begin, completeの両方に対応)
- authenticate_with_open_id do |result, identity_url|
+ authenticate_with_open_id do |result, identity_url, sreg, open_id_response|
if result.successful?
- if @current_user = User.find_by_identity_url(identity_url)
+ server_url = open_id_response.endpoint.server_url
+ if not TrustedServer.find_by_url(server_url)
+ # 信頼していないOPでのログインは拒否する
+ failed_login "Sorry, untrusted OpenID server: #{server_url}"
+ elsif @current_user = User.find_by_identity_url(identity_url)
# 認証成功でユーザが登録済みの場合はログイン成功 (A)
successful_login
else
OpenIDレスポンスのOP Endpoint URLがTrustedServerに含まれていなければ、

open_
@@ -106,13 +106,13 @@
case open_id_response.status
when OpenID::Consumer::SUCCESS
- yield Result[:successful], identity_url, OpenID::SReg::Response.from_success_response(open_id_response)
+ yield Result[:successful], identity_url, OpenID::SReg::Response.from_success_response(open_id_response), open_id_response
when OpenID::Consumer::CANCEL
- yield Result[:canceled], identity_url, nil
+ yield Result[:canceled], identity_url, nil, open_id_response
when OpenID::Consumer::FAILURE
- yield Result[:failed], identity_url, nil
+ yield Result[:failed], identity_url, nil, open_id_response
when OpenID::Consumer::SETUP_NEEDED
- yield Result[:setup_needed], open_id_response.setup_url, nil
+ yield Result[:setup_needed], open_id_response.setup_url, nil, open_id_response
end
end
なお、
まとめ
今回はパスワード認証との併用、