こんばんは、ritouです。
秋田はようやく、桜が咲き始めました。
以前紹介したOAuth 2.0 MAC Tokenですが、まだどこも対応してくれそうな気配がないので、自分で試してみました。
仕様 : draft-hammer-oauth-v2-mac-token-02 - HTTP Authentication: MAC Access Authentication
Clientがやること
ここで説明するのは、ClientがAccess Token + αを取得したあとからのリソースアクセス処理を想定しています。
1. MAC Credential(token,secret,algorithm)を用意
これらは、OAuth 2.0で定義されているフローで取得します。
ClientCredential(client_id/secret)は不要です。
2. timestamp,nonceを用意
timestampについては省略します。
nonceの作り方については、Clientの実装依存になります。
3. Resource Serverのデータを用意(method,URL,entitybody)
これらの値は、次に署名のもとになるSignature Base String作成のためにごにょごにょする必要があります。
まずは次のように分割します。
- method
- host
- port
- path
- query ← 連想配列みたいな形
その後に、queryに次のような処理をして文字列にします。
できあがったものがこちら的サンプルはこちらです。
=== b5=%3D%253D&c%40=&a2=r%20b&c2&a3=2+q === ↓ === a2=r%20b\n a3=2%20q\n b5=%3D%253D\n c%40=\n c2=\n ===
仕様の例では、上記の例にわざとらしくa3=aが追加されて(a3パラメータが)重複しているのですが、PHPでURLをparse_urlしてクエリをparse_strして配列にしてるうちに重複してる値がどっかいったので、とりあえず気にしないでおきます。
POSTなどでentitybodyを利用する場合は、その値をhashした文字列をbodyhashとして利用します。
POST+"application/x-www-form-urlencoded"のときにもentitybodyとして扱われますよ。
4. 署名のもとになる文字列を作成
今まで出てきた値を改行文字をつかって連結させます。
- token
- timestamp
- nonce
- bodyhash
- method
- host
- port
- path
- query
改行文字を\nで表記したサンプルはこちらです。
例 : GET h480djs93hd8\n 137131200\n dj83hs9s\n \n GET\n example.com\n 80\n /resource/1\n a=2\n b=1\n 例 : POST kkk9d7dh3k39sjv7\n 137131201\n 7d8f3e4a\n Lve95gjOVATpfV8EL5X4nxwjKHE=\n POST\n example.com\n 80\n /request\n a2=r%20b\n a3=2%20q\n b5=%3D%253D\n c%40=\n c2=\n
5. 署名作成
4で作った文字列を、secret+hmac関数で署名文字列を作成します。
6. Authorization Header を作成
サンプルはこちらです。(値は正しくありません。)
POSTのentitybodyが利用されるときは、AuthZ Headerにbodyhashが追加されます。
例 : GET Authorization: MAC token="h480djs93hd8", timestamp="137131200", nonce="dj83hs9s", signature="YTVjyNSujYs1WsDurFnvFi4JK6o= 例 : POST Authorization: MAC token="h480djs93hd8", timestamp="137131200", nonce="dj83hs9s", bodyhash="k9kbtCIy0CkI3/FEfpS/oIDjk6k=", signature="OQsqDpSwH9fv6E2Iy5xdGhMGyrE="
Resource Serverがやること
2. AuthZ Header中の必須パラメータチェック
これらの値がなければエラーですね。
- token
- timestamp
- nonce
- signature
- entitybodyがあるときはbodyhash
3. bodyhash検証
entitybodyに値が存在する場合はbodyhashを検証します。
Resource Server側でサポートしているハッシュアルゴリズムが単一の場合はこれは単純にsha1/sha256して比較します。
仮に、Token単位でアルゴリズムが異なる場合、リクエストの中にはアルゴリズムが指定されていませんので先にTokenの検証が必要かもしれません。
4. signature検証
とありますが、signatureの検証には、Tokenの検証が必要です。Secretを使いますからね。
Clientと同じ処理でSignatureを作成して比較します。
5. Timestamp,Nonceの検証
ここも実装依存にはなりますが、以下のような処理が行われるでしょう。
- xx分(秒)以内に作成されたリクエストのみ有効
- timestamp,nonce(もしくはnonce)の組み合わせが過去に利用されていないことを確認
6. Access Tokenの検証
ここからは、bearer tokenと同じですね。
ScopeやExpireなどを検証して、問題なければリソースアクセスの処理に入るのでしょう。
こんなところでしょうか。
図にした方が良かったのか…
PHPライブラリ
RubyやPerlなら他にライブラリ作って試してくれそうな人がいるので、PHPでちょっと作りました。
GitHub - ritou/php-OAuth2MacToken
AuthZ Request Headerの作り方はこんな感じです。
<?php include_once("lib/OAuth2MacTokenUtil.php"); $token = "j92fsdjf094gjfdi"; $secret = "8yfrufh348h"; $algorithm = "hmac-sha-1"; $timestamp = 137131206; $nonce = "f403hksd"; $method = "POST"; $url = "http://example.com/request"; $entitybody = "hello=world%21"; $AuthZHeader = OAuth2MacTokenUtil::genetateAuthZHeader($token, $secret, $algorithm, $timestamp, $nonce, $method, $url, $entitybody);
- AuthZ Request Header作成
- signature作成
- bodyhash計算
上記関数とcurlを使ったサンプルClientと、apache関連の関数を使ったサンプルResource Serverも置いときました。
様々なサービスがbearer tokenに対応していくなか、この署名付きリクエストははたして使われるのでしょうか。
いつかそんな時代がきたら参考にしていただければと思います。ではまた。