「ゼロから学ぶOAuth」のサンプルをUbuntu9.10で試したときのメモとOAuhプロトコルの詳細について
OAuthの勉強中です。日本語の説明だとゼロから学ぶOAuthが丁寧でわかりやすかったです。
自分でもサンプルを動かして見ましたが、Ubuntu9.10の環境だといくつか手順が必要だったのでそれをメモしておきます。
それと、記事自体には通信のトレースがすべて載っていなかったので、Consumer Key、Consumer Secretを使った3 legged Oauthの通信について一通り載せて、本家への参照も含めて解説をつけてみました。
サンプルアプリケーションを動かす
Ubuntu9.10で普通にrailsをインストールすると2.3.5が入るので、一つ前のrailsを入れる必要があります。
$gem install -v=2.3.4 rails
あと、db:migrateでライブラリが足りないエラーが出ました。
$ rake db:migrate --trace ...中略... rake aborted! no such file to load -- net/https /home/hrendoh/.gem/ruby/1.8/gems/rails-2.3.4/lib/initializer.rb:271:in `require_frameworks' ...以下略...
libopenssl-rubyを入れれば解決します。
$sudo apt-get install libopenssl-ruby
後は、記事のとおりで問題なくサンプルアプリケーションのセットアップは終了です。
あと、tcpflowをインストールしておきます。
$sudo apt-get install tcpflow
では実際にサンプルを動かして、一通りの通信キャプチャして置きます。
tcpflowをインストールして、起動しておきます。
$sudo apt-get install tcpflow $sudo tcpflow -i eth0 -c
今回サンプルは、twitterで試しました。以下、通信内容について説明。
リクエストトークンの取得
twitterの場合は、「http://twitter.com/oauth/request_token」に対してリクエストを投げます。
POST /oauth/request_token HTTP/1.1 Accept: */* Connection: close User-Agent: OAuth gem v0.4.0 Content-Type: application/x-www-form-urlencoded Authorization: OAuth oauth_callback="http%3A%2F%2Flocalhost%3A3000%2Foauth%2Ftwitter%2Fcallback", oauth_consumer_key="QwvCxMupZsztCNB6BTigg", oauth_nonce="cKXne6v4YF6KBc0WwfB5nLI9Zioo43EBFHeucBGU", oauth_signature="jpSOTIqlNEHrDQSt4Xw8FqhX638%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1273216539", oauth_version="1.0" Content-Length: 0 Host: twitter.com
サンプルで利用しているRuby OAuth GEMのOAuth::ConsumerクラスはデフォルトではPOSTでリクエストを実行します。
twitterのrequest_token取得はGETでOKだった気がしますが、どっちでも受け付けるみたいです。
Request Tokenの取得で重要なのはAuthorizationヘッダの内容です。
詳しくは、本家の「6.1. Obtaining an Unauthorized Request Token」に書かれています。
ここでも、簡単に各パラメータについて説明します。
oauth_consumer_key
Consumer Keyを指定します。
oauth_signature
著名の生成方法は本家の「http://oauth.net/core/1.0a/#signing_process:title=9.1. Signature Base String」に、例が「Appendix A.5. Accessing Protected Resources」にあります。
ハッシュされる文字列は以下の項目を&でつなげます。
- リクエストメソッド、必ず大文字。サンプルでは「POST」を指定。
- リクエストトークンを取得するURL、パラメータとデフォルトポートは取り除いたURLをエンコードしたもの。twitterのリクエストトークン取得用のURL「http://twitter.com/oauth/request_token」をURLエンコードしたもの「http%3A%2F%2Ftwitter.com%2Foauth%2Frequest_token」を指定
- Authorizationヘッダのrealmとoauth_signatureを除いたパラメータと、GETのパラメータまたはPOSTのリクエストボディ(application/x-www-form-urlencoded)をソートして"&"で全部連結してエンコードした文字列。twitterの場合はAuthorizationヘッダの内容だけ含めます。
上記をまとめると以下のような文字列になります。
POST&http%3A%2F%2Ftwitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3000%252Foauth%252Ftwitter%252Fcallback%26oauth_consumer_key%3DQwvCxMupZsztCNB6BTigg%26oauth_nonce%3DcKXne6v4YF6KBc0WwfB5nLI9Zioo43EBFHeucBGU%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1273216539%26oauth_version%3D1.0
ハッシュのキーはconsumer_secretとsecret tokenを"&"で連結したものになります。Secret Tokenはまだ取得していないので空のままで「5Jyyw4BRadq2leA7bQ5wqthckxXIUh62mK3yelk8Oo4&」になります。
HMAC-SHA1でハッシュしてbase64エンコードすると、確かに「jpSOTIqlNEHrDQSt4Xw8FqhX638=」になります。
oauth_timestamp
リクエスト時のタイムスタンプ
oauth_nonce
リクエストを一意に識別するためのランダム文字列
oauth_version
今のところ1.0しかないので「1.0」を指定します。
oauth_callback
ユーザの認可プロセスの後、コールバックされるのURL(絶対URL)を指定します。
拡張プロパティ
サービスプロバイダが定義している場合にのみ指定します。
上記の処理は、実際にはライブラリが上記の処理をやってくれるので実際には簡単です。
twitterからのレスポンスは以下の通り
HTTP/1.1 200 OK Date: Fri, 07 May 2010 07:15:40 GMT Server: hi Status: 200 OK X-Transaction: 1273216540-78368-12436 ETag: "e638e712cb5670c932b5dcbf6cac27d8" Last-Modified: Fri, 07 May 2010 07:15:40 GMT X-Runtime: 0.01365 Content-Type: text/html; charset=utf-8 Content-Length: 147 ...中略... oauth_token=eF3CkFCGjHxdQW77sTID1eYXrIj3No0kuv5CuUbD2bw&oauth_token_secret=IThdlEEvHRWDlRbx6zav6Zam5Xnf2wjWBb7i84ZC9s&oauth_callback_confirmed=true
oauth_tokenとoauth_token_secretがレスポンスボディ含まれていることが確認できます。
oauth_callback_confirmedは、サービスプロバイダがコールバックの値を受け取ったことを確認するフラグです。
認可の処理
リクエストトークンを取得した後は、TwitterのAuthorization ページ「http://twitter.com/oauth/authorize」にリダイレクトします。
そのとき、取得したoauth_tokenをパラメータに渡しています。
GET /oauth/authorize?oauth_token=eHoZfAGDrwTMOg3JA1FKgm11zEqq1yRLqTEXjsOl2ow HTTP/1.1 Host: twitter.com User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://localhost:3000/oauth_access_tokens/new Cookie: k=118.109.37.193.1273213822457314; guest_id=127321382247235591; ...以下略...
Authorization URLはGETアクセスになります。
仕様的には、パラメータは以下のものが指定できるようです。
指定しない場合は、ユーザにコンシューマを選択させるページが出てくるなどサービスプロバイダーの実装依存らしいです。
- 追加パラメータ:サービスプロバイダーの追加パラメータ
Twitterの場合は、以下の認可のページが表示されます。
サービスコンシューマにリダイレクト
認可処理の後Twitter(サービスプロバイダー)はoauth_callbackに指定したページにリダイレクトします。
http://localhost:3000/oauth/twitter/callback?oauth_token=XokKLV51dDcro5RsfbD7EmWq4JlnIQCseeyON3oJTU&oauth_verifier=8UDFkwyliMuhAej6I3CqKaGWMayeprd3vUi7rY1xmUc
コールバックされるURLには、パラメータoauth_token(認可ページに渡した値と同じ)とoauth_verifierが追加されます。6.2.3. Service Provider Directs the User Back to the Consumer
oauth_verifierの値は、次のアクセストークンの取得時で使います。
アクセストークンの取得
Twitterからリダイレクトされてきたら、実際にデータを取得するために使うアクセストークンを取得します。
アクセストークンの取得はTwitterの場合は「http://twitter.com/oauth/access_token」にリクエストします。
POST /oauth/access_token HTTP/1.1 Accept: */* Connection: close User-Agent: OAuth gem v0.4.0 Authorization: OAuth oauth_body_hash="2jmj7l5rSw0yVb%2FvlWAYkK%2FYBwk%3D", oauth_consumer_key="QwvCxMupZsztCNB6BTigg", oauth_nonce="MUtMyu7plWjvN55dVLR6IUL6jlYIWlOjyX8nDTmEbA", oauth_signature="3w8dkE8xQbUrg86NG83BPkLv0ng%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1273216548", oauth_token="RNgtclAx0rxKXxzwdNcFJJzcaKiW5AvHhAJMJQ5I4U", oauth_verifier="JgKcB1D60lFYm5nUitEvJmwPZto1adx5luUFEXKHg", oauth_version="1.0" Content-Length: 0 Host: twitter.com
リクエストトークンの取得と同様にAuthorizationヘッダには、決められたパラメータを指定する必要があります。
ただoauth_verifier以外は、同じですので説明は省略します。
oauth_verifierは、コールバックされる際にパラメータに付加されてきた値を指定します。
また、リクエストトークンの取得の際にsecret_tokenを取得しているので、ハッシュのキーに追加します。
HTTP/1.1 200 OK Date: Fri, 07 May 2010 07:15:48 GMT Server: hi Status: 200 OK X-Transaction: 1273216548-71383-4937 ETag: "a8b81b16d65f80679b89b0a777a3031a" Last-Modified: Fri, 07 May 2010 07:15:48 GMT X-Runtime: 0.02295 Content-Type: text/html; charset=utf-8 Content-Length: 162 Pragma: no-cache X-Revision: DEV Expires: Tue, 31 Mar 1981 05:00:00 GMT Cache-Control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0 Set-Cookie: k=118.109.37.193.1273216548784786; path=/; expires=Fri, 14-May-10 07:15:48 GMT; domain=.twitter.com Set-Cookie: guest_id=127321654878970392; path=/; expires=Sun, 06 Jun 2010 07:15:48 GMT Set-Cookie: _twitter_sess=BAh7CToPY3JlYXRlZF9hdGwrCLW%252FnnEoAToRdHJhbnNfcHJvbXB0MDoHaWQi%250AJTY2YmIzYzEzYzNjODMyYTVkNDdmMTM1ODA2MjAyZThkIgpmbGFzaElDOidB%250AY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--e91c921b41ceed45cc5b11b4f2f0821034dca09c; domain=.twitter.com; path=/ Vary: Accept-Encoding Connection: close oauth_token=26410135-WavDm9AQHiILT9sIyHukDTTgQVmasdmVpiIHXYbqI&oauth_token_secret=efd5PNmzNPLmcUUBBFkk5J4a5jkz6mz9LQhd6TI9XEI&user_id=26410175&screen_name=hrendoh
レスポンスボディに、アクセストークンとトークンシークレットが含まれています。
とりあえず、あとは取得したアクセストークンとトークンシークレットで情報の取得の手順がありますが、著名の作成については、リクエストトークンの手順と同じなので後は本家の「7. Accessing Protected Resources」を見てみてください。
参考にさせていただいたサイト
http://techno-st.net/2009/11/26/twitter-api-oauth-0.html
http://sayama-yuki.cocolog-nifty.com/blog/2009/09/twitteroauth-d7.html
あとがき
OAuth周りの実装をする場合、実際にはConsumer Key & Secretの仕組みとPublic Certificatesの仕組みを両方対応しないとならないし、今回の説明は3-legged OAuthなので、2-legged OAuthも実装しないとならないのでそれなりに大変かも。
それと、TwitterのConsumer KeyとSecretはほぼ実際に使ったものが載せてありますが、リセット済みですのでご心配なく。