2010-08-23
2-legged OAuthを理解する
APIの認証ってどうやってるんだろーって思っているときに、Google Dev Quizで2-legged OAuthの問題があったので、やりながら理解する事にした。perlで書いてみました。
OAuthのcpanモジュールを使った場合
この場合、簡単にできます。OAuth::Lite::Consumerにconsumer_keyとconsumer_secretとrealmを渡して作成してやった後、method, url, paramsを指定してrequestするだけです。timestamp値やnonceなどはすべて自動で付けて、署名を作ってくれています。
use strict; use warnings; use OAuth::Lite; use OAuth::Lite::Consumer; my $ua = LWP::UserAgent->new; my $request_url = 'http://gdd-2010-quiz-japan.appspot.com/oauth/hogehogehoge'; my $consumer = OAuth::Lite::Consumer->new( consumer_key => 'hogehoge', consumer_secret => 'piyopiyo', realm => 'devquiz', ); my $res = $consumer->request( method => 'POST', url => $request_url, params => {hello => 'world'}, ); use YAML; warn YAML::Dump($res);
OAuthモジュールを使わない場合
さすがに上のコードでは、ラップされすぎていて理解できなかったので、OAuthモジュールを使わずになんとか自分でやってみました。適当にいじっていったので、むちゃくちゃ汚いコードになっていますが、下のようになりました。
use strict; use warnings; use String::Random; use DateTime; use URI::Escape; use Digest::HMAC_SHA1 qw(hmac_sha1); use MIME::Base64; use LWP::UserAgent; my $realm = 'devquiz'; # realm my $param = { hello => 'world' }; # 送りたいparameter my $url = 'http://gdd-2010-quiz-japan.appspot.com/oauth/hogehogehoge'; # 送りたいurl my $oauth_consumer_secret = 'piyopiyp'; # 秘密鍵 my $oauth_param = { oauth_consumer_key => 'hogehoge', oauth_nonce => String::Random->new->randregex('\w{20}'), oauth_timestamp => DateTime->now->epoch, oauth_version => '1.0', oauth_signature_method => 'HMAC-SHA1' }; # Authorizationヘッダの作成 my $header = join(', ', map { $_ . '=' . '"' . $oauth_param->{$_} . '"'; } keys %$oauth_param); $header = qq{OAuth realm="${realm}", } . $header; # signatureの為のベース文字列を作成 my $signature_string = "POST&" . uri_escape($url); my $signature_param = { %$oauth_param, %$param, }; my $parameter_string .= join('&', map { $_ . '=' . $signature_param->{$_}; } sort keys %$signature_param); $signature_string .= '&' . uri_escape($parameter_string); # signatureの作成 my $hmac_sha1_key = $oauth_consumer_secret . '&'; $signature_string = hmac_sha1($signature_string, $hmac_sha1_key); $signature_string = encode_base64($signature_string); chomp $signature_string; # なぜか改行コードが追加されてる...orz # headerへ代入 $header .= ', oauth_signature="' . $signature_string . '"'; # 送信 my $ua = LWP::UserAgent->new; my $res = $ua->post($url, $param, 'Authorization' => $header); use YAML; warn YAML::Dump($res);
2-legged OAuthの手順
モジュールを使わずにやってみたら、手順が理解できたので、まとめておきます。
1.様々なパラメータから署名を作成する
- リクエストメソッド名(GET, POSTなど)
- リクエストURLをuri_escapeしたもの(GETの場合パラメータは除く)
- consumer_secretとrealm以外のOAuthパラメータと送信したいパラメータを、キー名=値という形にして&でつなげ、uri_escapeしたもの。ただし、キー名でソートした順番になっていなければならない。
- 今回だったら次のようになります。「hello%3Dworld%26oauth_consumer_key%3Dhogehoge%26oauth_nonce%3DRJQX3sK5nIodUcRS426k%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1282447259%26oauth_version%3D1.0」
次にconsumer_secretとtokenを&で繋いだものをキーとして、hmac_sha1でダイジェスト値を作ります。今回だったらtokenは空なので「piyopiyo&」のような文字列をキーとします。
最後にダイジェスト値をbase64でエンコードします。これで署名は完成します。
2.Authorizationヘッダを作成する
oauthに必要な情報を「OAuth キー名="値", キー名="値", ...」というように繋げた文字列を作ります。今回であれば必要な情報は下の通りです。
- oauth_consumer_key
- oauth_nonce
- oauth_timestamp
- oauth_version
- oauth_signature_method
- realm
- oauth_signature
ヘッダとしては以下のようになりました。
OAuth realm="devquiz", oauth_timestamp="1282447809", oauth_nonce="nVj2Up8xkA2fJkyGLE4X", oauth_consumer_key="hogehoge", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_signature="lKWlM2ZnyCAmCDOSIMZGSyNB4Nc="
3.送信
1,2で必要な情報は揃ったので、後はこれらを添えて普通にリクエストするだけです。perlだったらLWP::UserAgentを使って出来ます。
まとめ
cpanのモジュールを使うと、いろいろな事が簡単に出来てしまうんですが、たまには仕組みを理解する為に車輪の再発明をしてみるのもよさそうですね。またたまにはやってみようと思います。
- 12 http://reader.livedoor.com/reader/
- 8 http://b.hatena.ne.jp/entry/d.hatena.ne.jp/shiba_yu36/20100823/1282531802
- 8 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&q=Google+2-legged OAuth 自動&btnG=検索
- 7 http://www.google.co.jp/search?q=2-legged+OAuth&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja-JP-mac:official&hl=ja&client=firefox-a
- 7 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLL_jaJP384JP385&q=SIGNATURE_STRING
- 6 http://twitter.com/shiba_yu36
- 6 http://www.google.co.jp/reader/view/
- 5 http://b.hatena.ne.jp/entrymobile/24283224
- 5 http://www.google.co.jp/url?sa=t&rct=j&q=2-legged oauth&source=web&cd=12&ved=0CDUQFjABOAo&url=http://d.hatena.ne.jp/shiba_yu36/20100823/1282531802&ei=A374TsbBM6XKmAW2xqWHAg&usg=AFQjCNEu124F1DHrNXHZ-0fqh2ovbp-RLw&sig2=qjKsyDWL3hv9ScvEzFKt0A
- 4 http://b.hatena.ne.jp/t/perl
