pythonで署名付きリクエストを送る(2-legged OAuth)

最近、色んなサービスの認証シーンでOAuthをよく見かけます。例えばTwitterのアカウントを使って、全く別のマッシュアップサービスを使うような場合に使われていて、ユーザの予期せぬ権限委譲が話題にもなりましたね。

ところで普通OAuthと言うと、Provider(Twitter), Consumer(マッシュアップサービス), Userの3者間で認証を行うものだと思っていたのですが、実はProviderとConsumerの2者間での認証に使われる場合もあります。
前者は3-legged OAuthやOAuth Coreと、後者は2-legged OAuthとかOAuth Consumer Requestと呼ばれているようです。ここでは後者の認証をpythonでやります。

(※)以下の2-legged OAuthは署名アルゴリズムにHMAC-SHA1を使っているものとします。(他のアルゴリズムの場合はサーバ側でのリクエストの検証フローが違います。)

3-legged OAuthが権限委譲のコンセプトを含んだ新しい認証なのに比べて、2-legged OAuthはただの公開鍵共通鍵認証です。入門記事等で3-legged OAuthの比較的複雑な認証シーケンスを見ていたので、混乱してしまっていたのですが、2-legged OAuthはただの公開鍵共通鍵認証なので、以下の手順で行います。

  1. パラメータに公開鍵を含めて、HTTPリクエストの組み立て
  2. 1を元に秘密鍵で署名を作成
  3. 1に2を加えて送信

するとサーバでは送られてきた署名と公開鍵から、リクエストが有効かどうかを判断します。以下の手順でリクエストが有効かどうかを判断します。

  1. HTTPパラメータに含まれる公開鍵を元に(共通)秘密鍵を取得
  2. 秘密鍵とHTTPリクエストからクライアントでも行った署名の作成を行う
  3. 2の署名をクライアントから送られた署名と比較する

Providerが不正なリクエストをはじく為に使われる訳ですね。Userを守るのではなく、Providerの自己防衛の為の仕組みなので、Consumerからしたら何も嬉しくないですが、MixiモバイルYQLを初めとしてメジャーなサービスにも浸透してきています。

さて実際に先ほどの処理手順を実装する訳ですが、各言語用に軽いライブラリが用意されているのでそれを使います。

# まずインストール
$ easy_install oauth

面倒な署名の作成等はライブラリがやってくれるので簡単です。リクエストに署名する時に暗号化に使うアルゴリズムを選択できますが,大抵HMAC_SHA1で良いようです。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import urllib
from oauth import oauth

# ユーザ登録時にもらえる情報
consumer_key = 'your consumer key (public key)'
secret_key   = 'your private key'

# リクエストしたいURLとパラメータ
url   = 'http://query.yahooapis.com/v1/yql'
params = {
  'q'      : 'show tables',
  'format' : 'json'
}

# 1. Consumerオブジェクト作成
consumer = oauth.OAuthConsumer(consumer_key, secret_key)
# 2. HTTPリクエスト組み立て
request  = oauth.OAuthRequest.from_consumer_and_token(consumer, None, http_url=url, parameters=params)
# 3. リクエストに署名して発行
request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None)
stream = urllib.urlopen(request.to_url())
print stream.read()

2-legged OAuthなんて大げさな名前に腰が引けそうになりますが,ただの公開鍵共通鍵認証でした(3回目)。

追記 2009/10/12 02:19
ritou様よりご指摘を頂きまして、公開鍵認証だと騒いでたのを共通鍵認証に修正しました。それに伴い誤解していたサーバ側でのリクエストの検証手順も修正しました。また署名アルゴリズムはHMAC-SHA1に限定する文を追加しました。3度も強調した部分が間違っていて大変恥ずかしいです。これを書いた時に(H)MACという単語を全く理解していなかった事が原因でした。突っ込みを頂いたのは初めてですが、とてもありがたく感じました。ありがとうございました>ritou様

2 thoughts on “pythonで署名付きリクエストを送る(2-legged OAuth)”

  1. ritou様

    コメントありがとうございます。
    そしてすいません、完全に勘違いというか思い込みで書いてしまいました。

    consumer keyをリクエストパラメータに含めてるので、サーバ側ではconsumer keyで
    署名を復号するものとばかり思っていました。ご指摘を頂きまして、調べてみたところ(OpenPNEのソースを読みました)
    実際はconsumer keyを元にsecretキーをルックアップして、サーバ側でも署名を作成して、送信された署名との比較を取っていました。ご指摘の通りHMAC-SHA1方式での認証は共通鍵暗号化方式ですね。

    そもそもHMAC自体がそのような認証方式とは知らず、新しい暗号化アルゴリズムの1つと思い込んでおりました。

    上記修正致しますので、しばらくお待ちくださいませ。

Leave a Reply

Your email address will not be published. Required fields are marked *