«前の日記(2007-11-01 (木)) 最新 次の日記(2007-11-03 (土))»  

まちゅダイアリー


2007-11-02 (金)

Ruby で OAuth を使ってみた (2) (また失敗 → ちょっと成功)

昨日の日記の続き。 「諦めたらそこで試合終了ですよ」という声が聞こえたので、騙し騙し動かしてみることにした。 適当にRequestProxyを作ったり、動かないメソッドを直したりしたんだけど、こんなのでいいのだろうか。 ちなみに、元のソースは署名生成が明らかに間違ってた(ハッシュをそのままテキストにしてる)。

リクエストを作れるようになったので、 Twitter の APIに登録して Consumer Key と Consumer Secret を取得。 OAuth Request URLsを見て、OAuth Request Token URL を呼んでみた。 …結果はNG。署名生成で失敗しているのかなぁ。

とりあえず正しいリクエストが分からないと比較もできないので、先に PHP の実装を試してみることにする。

追記

PHPだと動いた。 署名生成についての僕の知識がやっぱり間違ってたみたい。 なので、下記のパッチは役に立たないや。あとで直します。

追記2

PHP版の実行結果を見ながらRuby版でも動くようにした。 とりあえず最初のステップの RequestToken だけだけど。

サンプルソースは以下の通り。

require 'oauth'
require 'oauth_token'
require 'oauth_request'
require 'oauth_consumer'
require 'oauth_signature'
require 'base64'
require 'uri'
require 'openssl'

consumer_key = "Twitterから取得したkey"
consumer_secret = "Twitterから取得したsecret"
consumer = OAuth::Consumer.new(consumer_key, consumer_secret)

endpoint = {
  :req_token => "http://twitter.com/oauth/request_token",
  :user_auth => "http://twitter.com/oauth/authorize",
  :access_token => "http://twitter.com/oauth/access_token"
}

params = {
  :method => 'GET',
  :uri => endpoint[:req_token],
  :parameters => { :oauth_version => '1.0' }
}
req = OAuth::Request.new(consumer, nil, params)
query = req.parameters.map {|k,v| "#{k}=#{v}" unless v.empty? }.compact.sort.join("&");

puts endpoint[:req_token] + '?' + query

OAuthライブラリへのパッチは以下の通り。

Index: oauth_signature.rb
===================================================================
--- oauth_signature.rb  (revision 205)
+++ oauth_signature.rb  (working copy)
@@ -20,8 +20,19 @@
     class UnknownSignatureMethod < Exception; end

     class Base
+      attr_reader :request
+
+      def initialize(request)
+        @request = request
+      end
+
+      def escape(text)
+        # unsafe caractor: http://oauth.googlecode.com/svn/spec/branches/1.0/drafts/4/spec.html#encoding_parameters
+        URI.escape(text, /[^a-zA-Z\d\-\._~]/)
+      end
+
       def signature
-        Base64.encode64(digest).chomp
+        escape(Base64.encode64(digest).chomp)
       end

       def ==(cmp_signature)
@@ -103,6 +114,10 @@
       class SHA1 < Base
         private
         def hmac_class; HMAC::SHA1; end
+
+        def self.digest(secret, message)
+          OpenSSL::HMAC::digest(OpenSSL::Digest::SHA1.new, secret, message)
+        end
       end

       class SHA2 < Base
Index: oauth_request.rb
===================================================================
--- oauth_request.rb    (revision 205)
+++ oauth_request.rb    (working copy)
@@ -1,9 +1,23 @@
 module OAuth
+  class RequestProxy
+    attr_reader :parameters, :method, :uri
+
+    def initialize(request = {})
+      @parameters = request[:parameters] || {}
+      @method = request[:method] || 'GET'
+      @uri = request[:uri]
+    end
+
+    def self.proxy(request)
+      OAuth::RequestProxy.new(request)
+    end
+  end
+
   class Request
     attr_accessor :consumer, :token, :request, :realm, :signature_method, :nonce, :timestamp
     attr_reader :parameters_for_signature

-    def initialize(consumer, token, request, realm = '', signature_method => 'HMAC-SHA1', nonce = nil, timestamp = nil)
+    def initialize(consumer, token, request, realm = '', signature_method = 'HMAC-SHA1', nonce = nil, timestamp = nil)
       @consumer = consumer
       @token ||= OAuth::Token.new('', '')
       @request = OAuth::RequestProxy.proxy(request)
@@ -23,8 +37,8 @@
       "oauth_token=\"#{token.token}\", " +
       "oauth_signature_method=\"#{signature_method}\", " +
       "oauth_signature=\"#{signature}\", " +
-      "oauth_timestamp=\"#{oauth_timestamp}\", " +
-      "oauth_nonce=\"#{oauth_nonce}\""
+      "oauth_timestamp=\"#{timestamp}\", " +
+      "oauth_nonce=\"#{nonce}\""
     end

     def method
@@ -43,6 +57,8 @@
       else
         @parameters_for_signature = request.parameters
       end
+      # convert hash to query string
+      @parameters_for_signature = @parameters_for_signature.map {|k,v| "#{k}=#{v}" unless v.empty? }.compact.sort.join("&")

       OAuth::Signature.sign(self)
     end

ノートPCの電源がなくなったので、今日はここまで。

Tags: ruby oauth

奈良

出張で奈良に行ってきた。 鹿がいるとは聞いていたけど、普通に路上で生活しているとは思わなかったよ。

奈良の鹿 / Deer in Nara, Japan

その後、東大寺の大きさに圧倒される。

東大寺 / Todaiji-Temple

奈良はオムライス屋が何軒かあった。名物なのかな?

pinocchio

ここのお店で食べたレアチーズケーキは絶品だった。店内の雰囲気も良かったし。

Sweets in pinocchio

関係ないけど、奈良県の人口が140万人というのにちょっと驚いた。 福岡市と変わらないくらいか。

Tags: Life
本日のツッコミ(全1件) [ツッコミを入れる]
agni (2007-11-07 (水) 04:08)

関西旅行おつかれさまでした(*'ヮ')<br>Flickr拝見しましたが鹿こうやって見ると結構かわいいですねw<br>東大寺の大きさには私も始めて見たとき圧倒された覚えがあります。<br>写真どれも構図とかキマってて素敵でした。<br>奈良とか久しぶりに行ってみようかしら。。