最終回となる今回は、OAuth Service Providerの実装方法について、手順を追って解説します。
OAuth Service Providerがすべきこと
OAuth連載最終回は、OAuth Service Providerの実装を行います。Service Providerの役割は、大きく以下の3つに分けられます。
OAuth Consumerの管理
OAuth Request / Access Tokenの管理
OAuth経由のリソースへのアクセス管理
Rails OAuth Pluginを用いたOAuth Service Providerの実装
Railsではruby-oauth gemとOAuth Plugin を用いることで、簡単にOAuth Service Providerを実装することができます。以下実装手順です。
ruby-oauth gemのインストール(まだの場合)
gem install oauth
Railsアプリケーション作成およびpluginインストール
rails service_provider
cd service_provider
./script/plugin install git://github.com/pelle/oauth-plugin.git
ControllerおよびModel生成
./script/generate oauth_provider
これで以下のContorollerおよびModelが生成されます。
app/controllers/oauth_controller.rb
app/models/oautht_token.rb
app/models/access_token.rb
app/models/request_token.rb
app/models/client_application.rb
app/models/oauth_nonce.rb
最後にroutesとassociationを設定して、db:migrateを実行します。なおOAuth PluginはUserモデルおよびcurrent_user、login_requiredメソッドの存在を前提にしています。必要があれば適宜該当箇所を編集してください。
リスト:routes.rb
map.oauth '/oauth',:controller=>'oauth',:action=>'index'
map.authorize '/oauth/authorize',:controller=>'oauth',:action=>'authorize'
map.request_token '/oauth/request_token',:controller=>'oauth',:action=>'request_token'
map.access_token '/oauth/access_token',:controller=>'oauth',:action=>'access_token'
map.test_request '/oauth/test_request',:controller=>'oauth',:action=>'test_request'
assiciation (User model is required)
has_many :client_applications
has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]
rake db:migrate
ここまでで前述のService Providerに(最低限)必要な機能はそろい、以下のbefore_filterが利用可能になります。
before_filter :login_or_oauth_required
before_filter :oauth_required
なおService Provider Sample - github にもこれと同様のサンプルアプリケーションを公開していますので、適宜ダウンロードして動かしてみてください。
図1 サンプルアプリケーション
OAuth Consumerからアクセスする
前回 までで実装したConsumerから、今回実装したService Provider(もしくはService Provider Sample )にアクセスしてみましょう。
Service Providerを起動し、http://localhost:3001にアクセスしてください。
cd oauth_sample/oauth_service_provider
./script/server -p 3001
ログイン(任意のユーザ名を入力)して、"Register your application"というリンクからOAuth Consumerを登録します。
図2 OAuth Consumerの登録
Application URLとCallbackは、ひとまず以下のようにしてください。
Application URL : http://localhost:3000
Callback URL : http://localhost:3000/my_sample/callback
次に得られたConsumer KeyとConsumer SecretをConsumer Sampleアプリケーションに登録します。まずはOAuth Consumer Sampleのconfig/service_provider.ymlに今回実装したService Providerを追加し、起動してください。
Service Providerの追加
my_sample:
name: my sample
site: http://localhost:3001
request_token_url: http://localhost:3001/oauth/request_token
authorize_url: http://localhost:3001/oauth/authorize
access_token_url: http://localhost:3001/oauth/access_token
起動
cd oautht_sample/oauth_consumer
./script/server
Consumer SampleにログインしてConsumer KeyとConsumer Secretを入力し、Service Providerを登録します。
図3 Service Provider
最後に“ new access token” のリンクからmy_sampleの“ establish” ボタンをクリックすれば、Access Tokenの取得が行えます。
図4 Access Tokenの取得
OAuth Pluginの改善点
残念ながら、現状ではOAuth Pluginはまだ実用に堪えられるレベルには到達していません。OAuth Service Providerを実装するには、最低限以下の機能は追加する必要があるでしょう。
OAuth Consumerの削除(および編集)
OAuth Token一覧ページとOAutht Consumer一覧ページの分離
またデフォルトではTokenの有効期限やscopeはサポートされていないため、これらを扱いたい場合にはその部分も独自に実装する必要があります。
(補足)OAuth Signature
Service Providerでは、これらすべてのリクエストにおいてConsumerおよびTokenを認証するため、Signatureの検証を行います。Signatureを検証するために、Service ProviderはまずリクエストURLおよびリクエストに含まれるパラメータを正規化したSignature Base Stringを生成します。Signature Base Stringは以下の手順で生成されます。
参考:OAuth Core 1.0 - Signing Requests
リクエストパラメータを集める。
・HTTP Authorization headerに含まれるパラメータを集める ( realmを除く) 。
・HTTP POSTリクエストに含まれるパラメータを集める。
・HTTP GETリクエストに含まれるパラメータを集める。
集めたパラメータからoauth_signatureを取り除く。
パラメータをkeyの辞書順にソートする。同じkeyが複数含まれる場合は、それらをvalueの辞書順でソートする。
“ key1=value1&key2=value2” のようにパラメータを連結する。valueが空の場合は"key="とする。
リクエストURLを取得する。fragmentとqueryおよびデフォルトPort(80 for http、443 for https)は取り除き、schemeとdomainは小文字にすること。
HTTP method(大文字、HEAD or GET or POST)とリクエストURL、および正規化されたパラメータをそれぞれURLエンコード(UTF-8)した後“ &” で連結する。
Signature Base String生成後は、oauth_signature_methodパラメータで指定された方式でSignatureを生成し、Consumer側で生成されたoauth_signature(リクエストパラメータに含まれる)と一致するかどうか検証します。今回実装したOAuth Service Providerでは、ClientApplication.verify_request内でSignature Base Stringが生成&検証されています。
なおSignature Base StringにはリクエストURLが含まれるので、Service Provider側でproxyなどの影響でリクエストURLが変更される場合などは注意してください。
最後に
この連載では、OAuth ConsumerおよびOAuth Service Providerの実装を通じてOAuthを紹介してきました。今後OAuth ConsumerおよびService Providerを実装されるエンジニアの方に、何か1つでも参考になる情報があれば幸いです。
また先日TwitterのOAuthもpublic betaとして(ようやく)公開されました。smart.fmをはじめ、いままでTwitterユーザ名&パスワードの入力を求めていたサービスは、この機会にぜひTwitter OAuthを導入されることをお勧めします(第2回 と第3回 であつかったOAuth Consumer SampleにもTwitter対応を追加しておきました) 。
最後に、smart.fmおよびsmart.fm APIもよろしくお願いします(笑)