動機
いろんなWeb APIを触ってみようと思った。
できた物
- WSSE.py (ファイル前半)
WSSE認証
このへんを見ながらちょこちょこと作り始めました。
送信プロトコル
WSSE認証をする場合はまずサービスのエンドポイントに特定のHTTPリクエストを送る必要があります。PythonでHTTPリクエストを送る場合にはhttplibのHTTPConnectionメソッドを使います。
HTTPリクエストのHTTPヘッダにはX-WSSEプロパティにbase64にエンコードした各ユーザ名、パスワードなどを送信する必要があります。
- リクエスト
GET /_atom/blog HTTP/1.1 X-WSSE: UsernameToken Username="user_name", PasswordDigest="fSzKHSagDuwiAWR092gIteMLgwo=", Nonce="MmtxM2Z2aTV0djQx", Created="2005-06-04T13:44:30Z" Host: blog.so-net.ne.jp
プロパティのエンコード方法とかはこんな感じ
Username -- ユーザー名。(はてなフォトライフAPIでははてなアカウントのid)
Nonce -- HTTPリクエスト毎に生成したセキュリティ・トークン*1
Created -- Nonceが作成された日時をISO-8601表記で記述したもの
PasswordDigest -- Nonce, Created, パスワード(はてなアカウントのパスワード)を文字列連結しSHA1アルゴリズムでダイジェスト化して生成された文字列を、Base64エンコードした文字列
WSSEプロパティ作成部分のコードはこんな感じ
def createHeaderToken(userid, password): nonce = sha.sha(str(time.time() + random.random())).digest() nonce64 = base64.encodestring(nonce).strip() created = datetime.datetime.now().isoformat() + 'Z' passdigest = sha.sha(nonce + created + password).digest() pass64 = base64.encodestring(passdigest).strip() wsse = 'UsernameToken Username="%(u)s", PasswordDigest="%(p)s", Nonce="%(n)s", Created="%(c)s"' value = dict(u = userid, p = pass64, n = nonce64, c = created) return wsse % value
その後エンドポイントにリクエストを送ります。その部分はこんな感じ。
def atomRequest(self, wsse, method, endpoint, body, content_type): header_info = {'X-WSSE': wsse, 'Content-Type': content_type, 'Authorization': 'WSSE profile="UsernameToken"', 'User-Agent': 'Python WSSE'} conninfo = urllib.splittype(endpoint) conntypeinfo = conninfo[0] connhostinfo = urllib.splithost(conninfo[1]) conn = httplib.HTTPConnection(connhostinfo[0]) conn.request(method, connhostinfo[1], body, header_info) r = conn.getresponse() if r.status in [200, 201]: raise Exception('login failure') response = dict(status = r.status, reason = r.reason, data = r.read()) conn.close() return response
基本的な流れとしては
- ルートエンドポイントにHTTPリクエストを送る
- サービスエンドポイントのURLをHTTPレスポンスによって得る
- サービスエンドポイントに各種メソッド(GET/POST/PUT/DELETE)を使って必要なデータを送信する
という感じです。上記のatomRequest()はとりあえずHTTPリクエストを送って、HTTPレスポンスを得る部分でのイディオムとなっています。