RubyのoauthでSignature検証

なんかサンプルコードが見つからなかったので書いておく。

OAuth::Signitureというクラスが利用できる。

require 'oauth'

def verify(request)
  consumer = OAuth::Consumer.new(
    'SOME CONSUMER KEY', 'SOME CONSUMER SECRET',
    :site => 'http://api.example.com'
  )

  headers = oauth_headers(request)
  signature = OAuth::Signature.build(request) do
    [headers['oauth_token_secret'], consumer.secret]
  end

  signature.verify
end

def oauth_headers
  headers = {}
  request.env['HTTP_AUTHORIZATION'].split(',').each{|item| k, v = item.split('='); headers[k.strip] = v.gsub(/"/, '')}
  headers
end

OAuth::Signature.buildの部分は

signature = OAuth::Signature.build(request) 

だったり

signature = OAuth::Signature.build(request) do
  [nil, consumer.secret]
end

でよかったりすることもあると思いますよ。

コード解説

requestって何者

requestはRailsのコントローラ内で使えるものをそのまま渡せる。

Sinatraなどの場合もrequestという名前で定義されているものを基本そのまま渡せるが、以下のrequireが必要。

require 'oauth/request_proxy/rack_request'

requestは内部的にOAuth::RequestProxy::Baseのサブクラスに適宜変換される模様。

oauth_headersメソッド

oauth_headersメソッドはoauth_token_secretが取れなかったので作ったメソッド。

他のoauth_tokenなどの値はOAuth::RequestProxyを使うと取得できる。

request_proxy = OAuth::RequestProxy.proxy(request)
request_proxy.oauth_token
request_proxy.signature

などで取れるんだけど、なんでかoauth_token_secretは取れず。

自前でSignatureを求める

ついでにSignature Base Stringから自分で求めてみる方法も。

Signatureがどうしても一致しない場合の原因究明をする場合などに、自前でやる方法は把握しておくと役に立つ。
# というかRubyのoauthのドキュメントが整備不足なのでこのあたり自前実装している人が多いような気がする。

require 'openssl'
require 'oauth'

def my_signature(consumer, request)
  headers = oauth_headers(request)
  signature = OAuth::Signature.build(request) do
    [headers['oauth_token_secret'], consumer.secret]
  end

  digest = OpenSSL::Digest::Digest.new("sha1")
  secret = "#{escape(consumer.secret)}&#{escape(headers['oauth_token_secret'])}"
  signature_string = Base64.encode64(OpenSSL::HMAC.digest(digest, secret, signature.signature_base_string)).chomp.gsub(/\n/, "")
end

def escape(value)
  URI.escape(value.to_s, /[^a-zA-Z0-9\-\.\_\~]/) # Unreserved characters -- must not be encoded
end

# oauth_headersは略

上記コードの自前Signatureを求めるあたりはroauthから拝借した。

Signature Base String求めるとこは手抜きして既存のOAuth::Signatureを使ったもので。
まあSignature Base Stringがおかしい場合は目視でわかるので、自分でSignature計算する前にまずはそこを見てみればいいのかも。

前の記事

iOS開発 2010年6月終わり頃の記録