OAuth Request Body Hashとは、OAuthの拡張仕様の一つです。
OAuth Coreではapplication/x-www-form-urlencodedなリクエストに対してのみ正当性を保証します。そのためPOSTでXMLを送信したいときなどには別の手段が必要になります。OAuth Request Body Hashは、そのようなnon-form-encodedなリクエストボディに対する正当性を保証するための仕組みです。
詳細は下記をどうぞ。
http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
(oauth body hashでググるとドラフトがトップに出るようですが(2010-04-17現在)、Finalバージョンはすでにあがっているようです)
YahooのTech Blogも参考になります。
http://techblog.yahoo.co.jp/web/openid/oauth_1/
このoauth_body_hashなのですが、日本語の情報が少なく、今のところライブラリで対応しているものがあまり無いようなので自分で実装してみました。
せっかくなので2-legged OAuthでoauth_body_hashを使う場合のサンプルコードをさらしておきます。
<?php
$consumer_key = "consumer_key";
$consumer_secret = "consumer_secret";
$version = "1.0";
$timestamp = time();
$nonce = (string)rand();
$signature_method = "HMAC-SHA1";
$url = "http://example.com/";
$request_body = '<?xml version="1.0" encoding="utf-8"?><foo>bar</foo>';
$body_hash = urlencode(base64_encode(hash("SHA1", $request_body, true)));
$params = sprintf('oauth_body_hash=%s&oauth_consumer_key=%s&oauth_nonce=%s&oauth_signature_method=%s&oauth_timestamp=%d&oauth_version=%s',
$body_hash, $consumer_key, $nonce, $signature_method, $timestamp, $version);
$sbs = sprintf('POST&%s&%s', urlencode($url), urlencode($params));
$signature = urlencode(base64_encode(hash_hmac("SHA1", $sbs, $consumer_secret."&", true)));
$auth_header = sprintf('OAuth oauth_body_hash="%s",oauth_consumer_key="%s",oauth_version="%s",oauth_timestamp="%d",oauth_nonce="%s",oauth_signature_method="%s",oauth_signature="%s',
$body_hash, $consumer_key, $version, $timestamp, $nonce, $signature_method, $signature);
$headers = array("Host: example.com",
"Accept: */*",
"Authorization: $auth_header",
"Content-Type: text/xml; charset=utf-8",
"Content-Length: ".strlen($request_body));
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_exec($ch);
curl_close($ch);
なお、PHPに限らずOAuthを自分で実装する時の注意点としては以下のような感じでしょうか
* oauth_body_hashの値はurlencodeした値です。signatureを計算する時はsignature base stringに組み込んだあともう一度urlencodeします。
* oauth_body_hashの計算に秘密鍵は必要ありません。つまりHMACではなく、単なるダイジェスト値です。
* base64 encodeの実装によっては末尾に改行を付加するものがありますが、改行は不要です。(PHPの場合は上記のサンプルと通りでOKですが、Javaのcom.sun.mail.util.BASE64EncoderStreamなどでは改行を付加するものがあるようです)
* timestampは秒までの整数値です。当然と言えば当然なのですが、なにも知らずに時間取得関数を使うとミリ秒まで返してくるものがあるので、はまると気づきにくいかもしれません。
* 2-legged OAuthの場合はaccess tokenが不要ですので、signatureを計算する時の秘密鍵はconsumer_secretに&をつけたものになります。
* signature base stringをつくるときのパラメータはアルファベット順にソートする必要があります。
* signature base string自体はurlencodeする必要はありません。urlencodeするのはURLとパラメータです。
参考:
http://oauth.net/core/1.0/