ゼロから学ぶOAuth

第4回OAuth Service Providerの実装

最終回となる今回は、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 サンプルアプリケーション
図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の登録
図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
図3 Service Provider

最後に⁠new access token⁠のリンクからmy_sampleの⁠establish⁠ボタンをクリックすれば、Access Tokenの取得が行えます。

図4 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

  1. リクエストパラメータを集める。
    HTTP Authorization headerに含まれるパラメータを集める ⁠realmを除く⁠⁠。
    HTTP POSTリクエストに含まれるパラメータを集める。
    HTTP GETリクエストに含まれるパラメータを集める。

  2. 集めたパラメータからoauth_signatureを取り除く。

  3. パラメータをkeyの辞書順にソートする。同じkeyが複数含まれる場合は、それらをvalueの辞書順でソートする。

  4. ⁠key1=value1&key2=value2⁠のようにパラメータを連結する。valueが空の場合は"key="とする。

  5. リクエストURLを取得する。fragmentとqueryおよびデフォルトPort(80 for http、443 for https)は取り除き、schemeとdomainは小文字にすること。

  6. 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もよろしくお願いします(笑)

おすすめ記事

記事・ニュース一覧