oauth_simple 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/README.rdoc +93 -0
- data/lib/oauth_simple.rb +9 -0
- data/lib/oauth_simple/helper_functions.rb +83 -0
- data/lib/oauth_simple/http.rb +267 -0
- data/lib/oauth_simple/request_helper.rb +98 -0
- data/lib/oauth_simple/request_helper_factory.rb +72 -0
- data/lib/oauth_simple/request_param_list.rb +144 -0
- data/rakefile.rb +13 -0
- data/test/helper_path_setting.rb +4 -0
- data/test/test_http.rb +43 -0
- data/test/test_main.rb +151 -0
- metadata +61 -0
data/.gemtest
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
= oauth_simple [RubyGem]
|
2
|
+
|
3
|
+
== Example
|
4
|
+
|
5
|
+
Following example shows you how to obtain a request token from Twitter server:
|
6
|
+
|
7
|
+
require "oauth_simple"
|
8
|
+
|
9
|
+
req_uri_str = 'https://api.twitter.com/oauth/request_token'
|
10
|
+
req_method = 'POST'
|
11
|
+
consumer_sec = 'your_consumer_secret'
|
12
|
+
|
13
|
+
req_helper = OAuthSimple::RequestHelper.new(
|
14
|
+
URI.parse( uri_str ),
|
15
|
+
req_method,
|
16
|
+
"#{OAuthSimple::HelperFunctions.enc_perenc(consumer_sec)}&",
|
17
|
+
OAuthSimple::RequestParamList.new( [
|
18
|
+
[ 'oauth_consumer_key', 'your_consumer_key' ],
|
19
|
+
[ 'oauth_signature_method', 'HMAC-SHA1' ],
|
20
|
+
[ 'oauth_timestamp', OAuthSimple::HelperFunctions.create_timestamp_str() ],
|
21
|
+
[ 'oauth_nonce', OAuthSimple::HelperFunctions.create_nonce_str() ],
|
22
|
+
[ 'oauth_version', '1.0' ],
|
23
|
+
] ),
|
24
|
+
)
|
25
|
+
|
26
|
+
require 'net/https'
|
27
|
+
http = Net::HTTP.new( req_helper.host, req_helper.port )
|
28
|
+
http.use_ssl = true # SSLを有効に
|
29
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # 認証モードをセット
|
30
|
+
http.start do |http|
|
31
|
+
http.request_post( req_helper.qpath, req_helper.req_body,
|
32
|
+
{ 'Authorization' => req_helper.oauth_header_str } ) do |res|
|
33
|
+
if res.code == '200'
|
34
|
+
res.read_body do |str|
|
35
|
+
puts 'str: ', str
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Alternatively, you can use OAuthSimple::HTTP, which is a subclass of Net::HTTP.
|
42
|
+
Following example shows you how to obtain a temporaty credentials (request token)
|
43
|
+
from Twitter server,
|
44
|
+
how to obtain a token credentials (access token), and how to issue a authenticated request:
|
45
|
+
|
46
|
+
require 'net/https' # if you use ssl
|
47
|
+
require 'oauth_simple'
|
48
|
+
#
|
49
|
+
# OAuthSimple::HTTP is a subclass of Net::HTTP
|
50
|
+
http = OAuthSimple::HTTP.new( 'api.twitter.com', 443 )
|
51
|
+
#
|
52
|
+
# SSL setting
|
53
|
+
http.use_ssl = true
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # 認証モードをセット
|
55
|
+
#
|
56
|
+
# OAuth setting (this feature is provided by OAuthSimple::HTTP)
|
57
|
+
http.use_oauth = true
|
58
|
+
http.set_oauth_client_credentials( 'YOUR_CLIENT_CREDENTIALS', 'YOUR_CLIENT_SECRET' )
|
59
|
+
http.set_oauth_signature_method( 'HMAC-SHA1' ) # at this time, only 'HMAC-SHA1' is supported
|
60
|
+
#
|
61
|
+
# connection start
|
62
|
+
http.start() do |http|
|
63
|
+
# == Obtaining Temporary Credentials ==
|
64
|
+
token, secret = http.request_oauth_temp_credentials( '/oauth/request_token', 'oob' ) do |res_failed|
|
65
|
+
# when response code is not '200', this block is called
|
66
|
+
raise res_failed.body
|
67
|
+
end
|
68
|
+
# token and secret are set to OAuthSimple::HTTP object automatically in the request_oauth_temp_credentials method,
|
69
|
+
# so you need not set them explicitly as follows
|
70
|
+
# http.set_oauth_user_credentials( token, secret )
|
71
|
+
#
|
72
|
+
# == Resource Owner Authorization ==
|
73
|
+
puts "access to https://api.twitter.com/oauth/authorize?oauth_token=#{OAuthSimple::HelperFunctions.enc_perenc(token)} " +
|
74
|
+
'and input verifier'
|
75
|
+
$stdout << 'verifier : '
|
76
|
+
verifier = $stdin.gets.chomp
|
77
|
+
#
|
78
|
+
# == Obtaining Token Credentials ==
|
79
|
+
token, secret = http.request_oauth_token_credentials( '/oauth/access_token', verifier ) do |res_failed|
|
80
|
+
# when response code is not '200', this block is called
|
81
|
+
raise res_failed.body
|
82
|
+
end
|
83
|
+
# token and secret are set to OAuthSimple::HTTP object automatically in the request_oauth_token_credentials method,
|
84
|
+
# you need not set them explicitly as follows
|
85
|
+
# http.set_oauth_user_credentials( token, secret )
|
86
|
+
#
|
87
|
+
# == Authenticated Requests ==
|
88
|
+
http.set_oauth_user_credentials( token, secret )
|
89
|
+
http.request_get( '/1/statuses/home_timeline.json?include_entities=true' ) do |res|
|
90
|
+
p res.code
|
91
|
+
p res.body
|
92
|
+
end
|
93
|
+
end
|
data/lib/oauth_simple.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# coding : utf-8
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module OAuthSimple
|
6
|
+
module HelperFunctions
|
7
|
+
|
8
|
+
# ====================
|
9
|
+
# MODULE FUNCTIONS
|
10
|
+
# ====================
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# nonce 用にランダムに文字列生成するメソッド
|
14
|
+
NONCE_STRING_SOURCE = ('a'..'z').to_a() + ('A'..'Z').to_a() + ('0'..'9').to_a()
|
15
|
+
def create_nonce_str( length = 16 )
|
16
|
+
Array.new( length ).map{ NONCE_STRING_SOURCE[rand(NONCE_STRING_SOURCE.size)] }.join('')
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_timestamp_str( time = Time.now )
|
20
|
+
( time - Time.utc( 1970, 1, 1 ) ).to_i().to_s()
|
21
|
+
end
|
22
|
+
|
23
|
+
# HMAC-SHA1
|
24
|
+
# RSA-SHA1
|
25
|
+
def calc_signature( method, uri_str, param_list, secret_str )
|
26
|
+
params_str = param_list.get_normalized_params_str()
|
27
|
+
#sb_str = String.new()
|
28
|
+
#list.each do |item|
|
29
|
+
# if ( sb_str != "" ) then
|
30
|
+
# sb_str << "&"
|
31
|
+
# end
|
32
|
+
# sb_str << encode( item[0] ) << "=" << encode( item[1] )
|
33
|
+
#end
|
34
|
+
base_str = [ method, uri_str, params_str ].map{ |e| enc_perenc(e) }.join('&')
|
35
|
+
digest = OpenSSL::HMAC::digest( OpenSSL::Digest::SHA1.new(), secret_str, base_str )
|
36
|
+
return [digest].pack('m').gsub!( /\n/u, '' )
|
37
|
+
end
|
38
|
+
|
39
|
+
# param : String
|
40
|
+
# return : [ [ String, String or nil ], ... ]
|
41
|
+
def decode_from_percent_encoded_str( str )
|
42
|
+
str.split( '&', -1 ).map! do |s|
|
43
|
+
if s.empty?
|
44
|
+
[ '', nil ]
|
45
|
+
else
|
46
|
+
pair = s.split( '=', -1 ).map!{ |s| dec_perenc( s ) }
|
47
|
+
# TODO: pair の要素数は 1 以上 2 以下 ('=' がない場合など, 1 個だけの場合もある)
|
48
|
+
[ pair[0], pair[1] ]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# param : [ [ String, String or nil ], ... ]
|
54
|
+
# return : String
|
55
|
+
def encode_to_percent_encoded_str_pairs( str_pairs )
|
56
|
+
str_pairs.map do |pair|
|
57
|
+
pair[1].nil? ? enc_perenc( pair[0] )
|
58
|
+
: enc_perenc( pair[0] ) + '=' + enc_perenc( pair[1] )
|
59
|
+
end.join( '&' )
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO これで良いか?
|
63
|
+
# UTF-8 エンコードされたものをパーセントエンコードしているとみなしてデコードする
|
64
|
+
# パーセントエンコードする際には文字列を UTF-8 エンコードするのは OAuth 1.0 の仕様
|
65
|
+
# だが, デコード時はこれでよいか?
|
66
|
+
def dec_perenc( str )
|
67
|
+
str.gsub( /%[a-fA-F\d]{2}/u ){ |s| [s[1,2]].pack('H*') }.force_encoding( Encoding::UTF_8 )
|
68
|
+
end
|
69
|
+
|
70
|
+
def enc_perenc( str )
|
71
|
+
str.gsub( /[^a-zA-Z\d\-\._\~]/u ) do |s|
|
72
|
+
d_str = s.unpack("H*")[0].upcase()
|
73
|
+
e_str = String.new()
|
74
|
+
while ( d_str[0,2] != "" ) do
|
75
|
+
e_str << "%" << d_str[0,2]
|
76
|
+
d_str[0,2] = ""
|
77
|
+
end
|
78
|
+
e_str
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# coding : utf-8
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'oauth_simple/helper_functions'
|
5
|
+
require 'oauth_simple/request_param_list'
|
6
|
+
|
7
|
+
module OAuthSimple
|
8
|
+
|
9
|
+
###
|
10
|
+
# Subclass of Net::HTTP, which has feature of OAuth authentication
|
11
|
+
class HTTP < Net::HTTP
|
12
|
+
|
13
|
+
include HelperFunctions
|
14
|
+
|
15
|
+
module DefaultOAuthParamSettable
|
16
|
+
def set_default_oauth_client_credentials( key, secret )
|
17
|
+
@client_credentials = [ key, secret ]
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_default_oauth_user_credentials( key, secret )
|
21
|
+
@user_credentials = [ key, secret ]
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_default_oauth_signature_method( sig_met )
|
25
|
+
@signature_method = sig_met
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_default_params
|
29
|
+
params = {}
|
30
|
+
params[:oauth_client_credentials] = @client_credentials if @client_credentials
|
31
|
+
params[:oauth_user_credentials ] = @user_credentials if @user_credentials
|
32
|
+
params[:signature_method ] = @signature_method if @signature_method
|
33
|
+
return params
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# :stopdoc:
|
38
|
+
# 空のハッシュを表す定数
|
39
|
+
EMPTY_HASH = {}.freeze
|
40
|
+
# :startdoc:
|
41
|
+
|
42
|
+
def initialize( *args )
|
43
|
+
super
|
44
|
+
self.set_oauth_params_location( LOC_AUTHORIZATION_HEADER )
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.create_subclass_with_default_oauth_params( oauth_params = EMPTY_HASH )
|
48
|
+
klass = Class.new( self ) do
|
49
|
+
def initialize( *args )
|
50
|
+
super
|
51
|
+
default_params = self.class.get_default_params
|
52
|
+
self.use_oauth = true
|
53
|
+
if default_params.has_key? :oauth_client_credentials
|
54
|
+
self.set_oauth_client_credentials( *default_params[:oauth_client_credentials] )
|
55
|
+
end
|
56
|
+
if default_params.has_key? :oauth_user_credentials
|
57
|
+
self.set_oauth_user_credentials( *default_params[:oauth_user_credentials] )
|
58
|
+
end
|
59
|
+
if default_params.has_key? :signature_method
|
60
|
+
# at this time, only 'HMAC-SHA1' is supported
|
61
|
+
self.set_oauth_signature_method( default_params[:signature_method] )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
klass.extend DefaultOAuthParamSettable
|
66
|
+
# TODO oauth_params で渡されたパラメータをここでセット
|
67
|
+
#
|
68
|
+
return klass
|
69
|
+
end
|
70
|
+
|
71
|
+
# @consumer_key
|
72
|
+
# @token
|
73
|
+
# @signature_method
|
74
|
+
# (timestamp, nonce, version)
|
75
|
+
# -> signature
|
76
|
+
#
|
77
|
+
# @consumer_secret
|
78
|
+
# @token_secret
|
79
|
+
|
80
|
+
###
|
81
|
+
# Override: Net::HTTP#transport_request
|
82
|
+
def transport_request( req )
|
83
|
+
if use_oauth?
|
84
|
+
req_method = req.method.upcase
|
85
|
+
uri_str_scheme = use_ssl? ? 'https' : 'http'
|
86
|
+
uri_str_host = addr_port.downcase # デフォルトでない場合ポート番号含む
|
87
|
+
# TODO: path 中の '#' はどのように扱われるべき?
|
88
|
+
qpath, uri_str_fragment = req.path.split( '#', 2 )
|
89
|
+
uri_str_path, query_str = qpath.split( '?', 2 )
|
90
|
+
# OAuth Header (基本的には自分で用意)
|
91
|
+
#req.get_fields( 'Authorization' )
|
92
|
+
# ...
|
93
|
+
# body parameters (必要な場合だけ)
|
94
|
+
# Protocol parameters can be transmitted in the HTTP request entity-
|
95
|
+
# body, but only if the following REQUIRED conditions are met:
|
96
|
+
# o The entity-body is single-part.
|
97
|
+
# o The entity-body follows the encoding requirements of the
|
98
|
+
# "application/x-www-form-urlencoded" content-type as defined by
|
99
|
+
# [W3C.REC-html40-19980424].
|
100
|
+
# o The HTTP request entity-header includes the "Content-Type" header
|
101
|
+
# field set to "application/x-www-form-urlencoded".
|
102
|
+
body_str = nil
|
103
|
+
if req.request_body_permitted?
|
104
|
+
content_type = req.content_type || 'application/x-www-form-urlencoded'
|
105
|
+
if content_type == 'application/x-www-form-urlencoded'
|
106
|
+
body_str = req.body
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
secret_str = [ @oauth_consumer_secret, @oauth_token_secret ].
|
111
|
+
map {|e| e.nil? ? '' : enc_perenc( e ) }.
|
112
|
+
join( '&' )
|
113
|
+
|
114
|
+
# for debug
|
115
|
+
#puts "request method - #{req_method }"
|
116
|
+
#puts "http or https - #{uri_str_scheme}"
|
117
|
+
#puts "host[:port] - #{uri_str_host }"
|
118
|
+
#puts "path - #{uri_str_path }"
|
119
|
+
#puts "query str - #{query_str.nil? ? '<nil>' : query_str}"
|
120
|
+
#puts "body str - #{body_str.nil? ? '<nil>' : body_str }"
|
121
|
+
|
122
|
+
p_params = RequestParamList.new()
|
123
|
+
{
|
124
|
+
'oauth_consumer_key' => @oauth_consumer_key,
|
125
|
+
'oauth_token' => @oauth_token,
|
126
|
+
'oauth_signature_method' => @oauth_signature_method,
|
127
|
+
}.each_pair{|k,v| p_params.add( k, v ) if v }
|
128
|
+
p_params.add( 'oauth_timestamp' , create_timestamp_str() )
|
129
|
+
p_params.add( 'oauth_nonce' , create_nonce_str() )
|
130
|
+
p_params.add( 'oauth_version' , '1.0' )
|
131
|
+
if req.respond_to? :oauth_params
|
132
|
+
req.oauth_params.each_pair do |key,value|
|
133
|
+
p_params.add( key, value )
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
param_list = RequestParamList.new()
|
138
|
+
param_list.concat p_params
|
139
|
+
param_list.concat RequestParamList.from_percent_encoded_str query_str if query_str
|
140
|
+
param_list.concat RequestParamList.from_percent_encoded_str body_str if body_str
|
141
|
+
|
142
|
+
# signature の計算
|
143
|
+
uri_str = "#{uri_str_scheme}://#{uri_str_host}#{uri_str_path}"
|
144
|
+
signature = calc_signature( req_method, uri_str, param_list, secret_str )
|
145
|
+
|
146
|
+
case @oauth_params_loc
|
147
|
+
when LOC_AUTHORIZATION_HEADER
|
148
|
+
# Authorization Header
|
149
|
+
p_params.add( 'oauth_signature', signature )
|
150
|
+
req.add_field( 'Authorization', 'OAuth ' + p_params.to_header_string() )
|
151
|
+
when LOC_REQBODY_OR_REQQUERY
|
152
|
+
# req body or req query
|
153
|
+
raise 'not implemented yet'
|
154
|
+
when LOC_REQQUERY
|
155
|
+
# req query
|
156
|
+
raise 'not implemented yet'
|
157
|
+
else
|
158
|
+
# error
|
159
|
+
raise 'invalid location'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
return super # 引数, block をそのまま継承先へ渡す
|
163
|
+
end
|
164
|
+
|
165
|
+
def use_oauth=( val )
|
166
|
+
@use_oauth = val
|
167
|
+
end
|
168
|
+
|
169
|
+
def use_oauth?
|
170
|
+
@use_oauth
|
171
|
+
end
|
172
|
+
|
173
|
+
def set_oauth_client_credentials( key, secret )
|
174
|
+
@oauth_consumer_key = key
|
175
|
+
@oauth_consumer_secret = secret
|
176
|
+
end
|
177
|
+
|
178
|
+
def set_oauth_user_credentials( token, secret )
|
179
|
+
@oauth_token = token
|
180
|
+
@oauth_token_secret = secret
|
181
|
+
end
|
182
|
+
|
183
|
+
def set_oauth_signature_method( sigmet )
|
184
|
+
if sigmet != 'HMAC-SHA1'
|
185
|
+
raise %q{at this time, only 'HMAC-SHA1' is supported}
|
186
|
+
end
|
187
|
+
@oauth_signature_method = sigmet
|
188
|
+
end
|
189
|
+
|
190
|
+
LOC_AUTHORIZATION_HEADER = :auth_header
|
191
|
+
LOC_REQBODY_OR_REQQUERY = :reqbody_or_reqquery
|
192
|
+
LOC_REQQUERY = :reqquery
|
193
|
+
def set_oauth_params_location( location )
|
194
|
+
@oauth_params_loc = location
|
195
|
+
end
|
196
|
+
|
197
|
+
# TODO: POST メソッド以外も使えるように
|
198
|
+
def request_oauth_temp_credentials( path, oauth_callback_uri, &block )
|
199
|
+
req = Post.new( path )
|
200
|
+
req.set_oauth_param( 'oauth_callback', oauth_callback_uri )
|
201
|
+
token = nil
|
202
|
+
secret = nil
|
203
|
+
request( req ) do |res|
|
204
|
+
if res.code == '200'
|
205
|
+
params = RequestParamList.from_percent_encoded_str res.body
|
206
|
+
token = params.get_values( 'oauth_token' )[0]
|
207
|
+
secret = params.get_values( 'oauth_token_secret' )[0]
|
208
|
+
else
|
209
|
+
if block
|
210
|
+
block.call res
|
211
|
+
else
|
212
|
+
raise 'error' # TODO
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Set credentials automatically
|
218
|
+
set_oauth_user_credentials( token, secret )
|
219
|
+
return token, secret
|
220
|
+
end
|
221
|
+
|
222
|
+
# TODO: POST メソッド以外も使えるように
|
223
|
+
def request_oauth_token_credentials( path, oauth_verifier, &block )
|
224
|
+
req = Post.new( path )
|
225
|
+
req.set_oauth_param( 'oauth_verifier', oauth_verifier )
|
226
|
+
token = nil
|
227
|
+
secret = nil
|
228
|
+
request( req ) do |res|
|
229
|
+
if res.code == '200'
|
230
|
+
params = RequestParamList.from_percent_encoded_str res.body
|
231
|
+
token = params.get_values( 'oauth_token' )[0]
|
232
|
+
secret = params.get_values( 'oauth_token_secret' )[0]
|
233
|
+
else
|
234
|
+
if block
|
235
|
+
block.call res
|
236
|
+
else
|
237
|
+
raise 'error'
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
set_oauth_user_credentials( token, secret )
|
242
|
+
return token, secret
|
243
|
+
end
|
244
|
+
|
245
|
+
module OAuthParamsHandler
|
246
|
+
def set_oauth_param( name, value )
|
247
|
+
# TODO: name must start with 'oauth_'
|
248
|
+
@oauth_params ||= {}
|
249
|
+
@oauth_params[ name ] = value
|
250
|
+
end
|
251
|
+
def get_oauth_param( name )
|
252
|
+
( @oauth_params || {} )[ name ]
|
253
|
+
end
|
254
|
+
def oauth_params
|
255
|
+
@oauth_params || {}
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class Get < Net::HTTP::Get
|
260
|
+
include OAuthParamsHandler
|
261
|
+
end
|
262
|
+
class Post < Net::HTTP::Post
|
263
|
+
include OAuthParamsHandler
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# coding : utf-8
|
2
|
+
|
3
|
+
require 'oauth_simple/helper_functions'
|
4
|
+
|
5
|
+
module OAuthSimple
|
6
|
+
class RequestHelper
|
7
|
+
|
8
|
+
include HelperFunctions
|
9
|
+
|
10
|
+
###
|
11
|
+
# req_uri : URI or String object
|
12
|
+
# req_method : String
|
13
|
+
def initialize( req_uri, req_method, oauth_secret, protocol_params, query_params = nil, body_params = nil )
|
14
|
+
# URI
|
15
|
+
@req_uri = req_uri # 後ろの処理で query は nil になる
|
16
|
+
# String or Symbol?
|
17
|
+
@req_method = req_method
|
18
|
+
# String or Symbol?
|
19
|
+
@sig_method = nil
|
20
|
+
# String
|
21
|
+
@secret_str = oauth_secret
|
22
|
+
# RequestParamList
|
23
|
+
@p_params = protocol_params
|
24
|
+
# RequestParamList or nil
|
25
|
+
q_params_list = []
|
26
|
+
if @req_uri.query
|
27
|
+
q_params_list << RequestParamList.from_percent_encoded_str( @req_uri.query )
|
28
|
+
@req_uri.query = nil
|
29
|
+
end
|
30
|
+
if query_params
|
31
|
+
q_params_list << query_params
|
32
|
+
end
|
33
|
+
@q_params = q_params_list.empty? ? nil : q_params_list.inject{|a,b| a.concat b}
|
34
|
+
# RequestParamList or nil
|
35
|
+
@b_params = body_params
|
36
|
+
|
37
|
+
params = RequestParamList.new()
|
38
|
+
params.concat @p_params
|
39
|
+
params.concat @q_params if @q_params
|
40
|
+
params.concat @b_params if @b_params
|
41
|
+
|
42
|
+
# URI の処理
|
43
|
+
# The scheme, authority, and path of the request resource URI [RFC3986]
|
44
|
+
# are included by constructing an "http" or "https" URI representing
|
45
|
+
# the request resource (without the query or fragment) as follows:
|
46
|
+
# 1. The scheme and host MUST be in lowercase.
|
47
|
+
uri_str = ''
|
48
|
+
# scheme
|
49
|
+
uri_str << @req_uri.scheme.downcase
|
50
|
+
uri_str << '://'
|
51
|
+
uri_str << @req_uri.host.downcase
|
52
|
+
# 3. The port MUST be included if it is not the default port for the
|
53
|
+
# scheme, and MUST be excluded if it is the default. Specifically,
|
54
|
+
# the port MUST be excluded when making an HTTP request [RFC2616]
|
55
|
+
# to port 80 or when making an HTTPS request [RFC2818] to port 443.
|
56
|
+
# All other non-default port numbers MUST be included.
|
57
|
+
if @req_uri.port != @req_uri.default_port
|
58
|
+
uri_str << ":#{@req_uri.port}"
|
59
|
+
end
|
60
|
+
uri_str << @req_uri.path
|
61
|
+
|
62
|
+
@p_params.add( 'oauth_signature', calc_signature( req_method, uri_str, params, @secret_str ) )
|
63
|
+
end
|
64
|
+
|
65
|
+
def host
|
66
|
+
@req_uri.host
|
67
|
+
end
|
68
|
+
|
69
|
+
def port
|
70
|
+
@req_uri.port
|
71
|
+
end
|
72
|
+
|
73
|
+
def request_method
|
74
|
+
@req_method
|
75
|
+
end
|
76
|
+
|
77
|
+
###
|
78
|
+
# path + '?' + query
|
79
|
+
def qpath
|
80
|
+
@req_uri.path
|
81
|
+
end
|
82
|
+
|
83
|
+
def qpath_with_oauth_params
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def req_body
|
88
|
+
end
|
89
|
+
|
90
|
+
def req_body_with_oauth_params
|
91
|
+
end
|
92
|
+
|
93
|
+
def oauth_header_str( realm_str = nil )
|
94
|
+
'OAuth ' + @p_params.to_header_string()
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# coding : utf-8
|
2
|
+
|
3
|
+
require 'oauth_simple/helper_functions'
|
4
|
+
|
5
|
+
module OAuthSimple
|
6
|
+
class RequestHelperFactory
|
7
|
+
|
8
|
+
include HelperFunctions
|
9
|
+
|
10
|
+
###
|
11
|
+
# consumer_secret
|
12
|
+
# token_secret
|
13
|
+
# consumer_key
|
14
|
+
# token
|
15
|
+
# clients MAY omit the parameter.
|
16
|
+
# signature_method
|
17
|
+
# timestamp
|
18
|
+
# MAY be omitted when using the "PLAINTEXT" signature method.
|
19
|
+
# nonce
|
20
|
+
# MAY be omitted when using the "PLAINTEXT" signature method.
|
21
|
+
# version
|
22
|
+
# OPTIONAL. If present, MUST be set to "1.0".
|
23
|
+
# :consumer_key, :consumer_secret, :token, :token_secret, :signature_method
|
24
|
+
# :use_default_timestamp, :use_default_nonce, :use_default_version
|
25
|
+
def initialize( args )
|
26
|
+
args = {
|
27
|
+
:use_default_timestamp => true,
|
28
|
+
:use_default_nonce => true,
|
29
|
+
:use_default_version => true,
|
30
|
+
}.merge args
|
31
|
+
# String object or nil
|
32
|
+
@consumer_key = args.delete( :consumer_key )
|
33
|
+
@consumer_secret = args.delete( :consumer_secret )
|
34
|
+
@token = args.delete( :token )
|
35
|
+
@token_secret = args.delete( :token_secret )
|
36
|
+
@signature_method = args.delete( :signature_method )
|
37
|
+
# boolean
|
38
|
+
@use_default_timestamp = args.delete( :use_default_timestamp )
|
39
|
+
@use_default_nonce = args.delete( :use_default_nonce )
|
40
|
+
@use_default_version = args.delete( :use_default_version )
|
41
|
+
# TODO: args に key が残っている場合, 警告を表示
|
42
|
+
end
|
43
|
+
|
44
|
+
###
|
45
|
+
# create RequestHelper object
|
46
|
+
def create( req_uri, req_method, option_params )
|
47
|
+
# secret_str 生成
|
48
|
+
cons_sec = option_params[:consumer_secret] || @consumer_secret
|
49
|
+
tokn_sec = option_params[:token_secret ] || @token_secret
|
50
|
+
secret_str = "#{cons_sec}&#{tokn_sec}"
|
51
|
+
|
52
|
+
# protocol params
|
53
|
+
p_params = RequestParamList.new()
|
54
|
+
p_params.add( 'oauth_consumer_key' , @consumer_key ) if @consumer_key
|
55
|
+
p_params.add( 'oauth_token' , @token ) if @token
|
56
|
+
p_params.add( 'oauth_signature_method', @signature_method ) if @signature_method
|
57
|
+
p_params.add( 'oauth_timestamp' , create_timestamp_str() ) if @use_default_timestamp
|
58
|
+
p_params.add( 'oauth_nonce' , create_nonce_str() ) if @use_default_nonce
|
59
|
+
p_params.add( 'oauth_version' , '1.0' ) if @use_default_version
|
60
|
+
p_params2 = option_params.delete( :protocol_params )
|
61
|
+
p_params.concat p_params2 if p_params2
|
62
|
+
|
63
|
+
# query_params and body_params
|
64
|
+
q_params = option_params.delete( :query_params )
|
65
|
+
b_params = option_params.delete( :body_params )
|
66
|
+
|
67
|
+
# RequestHelper object 生成
|
68
|
+
RequestHelper.new( req_uri, req_method, secret_str, p_params, q_params, b_params )
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# coding : utf-8
|
2
|
+
|
3
|
+
require 'oauth_simple/helper_functions'
|
4
|
+
|
5
|
+
module OAuthSimple
|
6
|
+
class RequestParamList
|
7
|
+
|
8
|
+
include HelperFunctions
|
9
|
+
|
10
|
+
# instance variable
|
11
|
+
# @list : [ [ String obj, String obj or nil ], ... ]
|
12
|
+
|
13
|
+
def initialize( arg = Array.new() )
|
14
|
+
if ( arg.is_a? Array ) then
|
15
|
+
arg.each do |item|
|
16
|
+
if not item.is_a?( Array ) or item.length != 2 or not item[0].is_a?( String ) or not ( item[1].is_a?( String ) or item[1].nil? ) then
|
17
|
+
raise "引数として与えられた Array が正しい形式ではありません. " +
|
18
|
+
'引数として与えられた Array オブジェクトの各要素は, String オブジェクト ' +
|
19
|
+
'2 つ (または 2 つめは nil) からなる Array オブジェクトである必要があります'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@list = arg
|
23
|
+
elsif ( arg.is_a? Hash ) then
|
24
|
+
@list = Array.new()
|
25
|
+
arg.each do |key,val|
|
26
|
+
@list.push( [key, val] )
|
27
|
+
end
|
28
|
+
elsif ( arg.is_a? String ) then
|
29
|
+
@list = Array.new()
|
30
|
+
if ( /%(?![a-fA-F\d]{2})/u =~ arg ) then
|
31
|
+
# OAuth の仕様どおりではないが, URL エンコードの形式ならば受け付ける
|
32
|
+
raise "引数として与えられた String オブジェクトが正しく encode されたものではありません"
|
33
|
+
end
|
34
|
+
param_list = arg.split( /&/u )
|
35
|
+
param_list.each do |item|
|
36
|
+
if ( item.nil? || item == "" ) then
|
37
|
+
next
|
38
|
+
end
|
39
|
+
pair = item.split( /=/u )
|
40
|
+
@list.push( [decode( pair[0] ), decode( pair[1].to_s() )] )
|
41
|
+
end
|
42
|
+
else
|
43
|
+
raise "型エラー : ParameterList の初期化時に与えることができる引数の型は Array と String のみです"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.from_percent_encoded_str( str )
|
48
|
+
# HelperFunctions モジュールで定義されている... 関数呼び出しにはできない?
|
49
|
+
new HelperFunctions.decode_from_percent_encoded_str( str )
|
50
|
+
end
|
51
|
+
|
52
|
+
public
|
53
|
+
def +( other )
|
54
|
+
return ParameterList.new( self.get_list() + other.get_list() )
|
55
|
+
end
|
56
|
+
|
57
|
+
def concat( other )
|
58
|
+
@list.concat( other.get_list() )
|
59
|
+
return self
|
60
|
+
end
|
61
|
+
|
62
|
+
def add( name, value )
|
63
|
+
@list.push( [name, value] )
|
64
|
+
return nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_values( name )
|
68
|
+
res_list = Array.new()
|
69
|
+
@list.each do |item|
|
70
|
+
if ( item[0] == name ) then
|
71
|
+
res_list.push( item[1] )
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return res_list
|
75
|
+
end
|
76
|
+
|
77
|
+
alias :[] :get_values
|
78
|
+
|
79
|
+
def each()
|
80
|
+
@list.each do |item|
|
81
|
+
yield( item[0], item[1] )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_header_string()
|
86
|
+
#list = get_sorted_list()
|
87
|
+
sb_str = String.new()
|
88
|
+
@list.each do |item|
|
89
|
+
if ( sb_str != "" ) then
|
90
|
+
sb_str << ", "
|
91
|
+
end
|
92
|
+
sb_str << enc_perenc( item[0] ) << '="' << enc_perenc( item[1] ) << '"'
|
93
|
+
end
|
94
|
+
return sb_str
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_query_string()
|
98
|
+
#list = get_sorted_list()
|
99
|
+
sb_str = String.new()
|
100
|
+
@list.map{ |e| enc_perenc( e[0] ) + ( e[1] ? "=#{enc_perenc( e[1] )}" : '' ) }.join( '&' )
|
101
|
+
end
|
102
|
+
|
103
|
+
=begin
|
104
|
+
def to_signature_string( method, url, key )
|
105
|
+
list = get_sorted_list()
|
106
|
+
sb_str = String.new()
|
107
|
+
list.each do |item|
|
108
|
+
if ( sb_str != "" ) then
|
109
|
+
sb_str << "&"
|
110
|
+
end
|
111
|
+
sb_str << encode( item[0] ) << "=" << encode( item[1] )
|
112
|
+
end
|
113
|
+
base_string = encode( method ) + "&" + encode( url ) + "&" + encode( sb_str )
|
114
|
+
digest = OpenSSL::HMAC::digest( OpenSSL::Digest::SHA1.new(), key, base_string )
|
115
|
+
sig = [digest].pack("m").gsub!( /\n/u, "" )
|
116
|
+
return sig
|
117
|
+
end
|
118
|
+
=end
|
119
|
+
|
120
|
+
protected
|
121
|
+
def get_list()
|
122
|
+
return @list
|
123
|
+
end
|
124
|
+
|
125
|
+
public
|
126
|
+
# http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
|
127
|
+
def get_normalized_params_str()
|
128
|
+
@list.
|
129
|
+
map do |e| # [ key, val ]
|
130
|
+
[ enc_perenc( e[0] ), e[1] ? enc_perenc( e[1] ) : '' ]
|
131
|
+
end.
|
132
|
+
sort do |a,b|
|
133
|
+
case a[0] <=> b[0]
|
134
|
+
when 1 then rel = 1
|
135
|
+
when -1 then rel = -1
|
136
|
+
when 0 then rel = a[1] <=> b[1]
|
137
|
+
end
|
138
|
+
end.
|
139
|
+
map{ |e| "#{e[0]}=#{e[1]}" }.
|
140
|
+
join( '&' )
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
data/rakefile.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
task :default => [:test]
|
6
|
+
|
7
|
+
Rake::TestTask.new do |test|
|
8
|
+
# $LOAD_PATH に追加するパス (デフォルトで 'lib' は入っている)
|
9
|
+
test.libs << 'test'
|
10
|
+
# テスト対象ファイルの指定
|
11
|
+
test.test_files = Dir[ 'test/**/test_*.rb' ]
|
12
|
+
test.verbose = true
|
13
|
+
end
|
data/test/test_http.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path File.join( File.dirname(__FILE__), 'helper_path_setting' )
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'minitest/unit'
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'oauth_simple'
|
10
|
+
require 'oauth_simple/http'
|
11
|
+
|
12
|
+
class TestHttp < MiniTest::Unit::TestCase
|
13
|
+
|
14
|
+
# OAuthSimple::HTTP is a subclass of Net::HTTP
|
15
|
+
MyHTTP = OAuthSimple::HTTP.create_subclass_with_default_oauth_params()
|
16
|
+
MyHTTP.set_default_oauth_client_credentials( 'key', 'secret' )
|
17
|
+
#MyHTTP.set_default_oauth_user_credentials( key, secret )
|
18
|
+
MyHTTP.set_default_oauth_signature_method( 'HMAC-SHA1' )
|
19
|
+
|
20
|
+
###
|
21
|
+
# test by using OAuth Test Server : http://term.ie/oauth/example/
|
22
|
+
def test_getting_request_token
|
23
|
+
|
24
|
+
http = MyHTTP.new( 'term.ie' )
|
25
|
+
# connection start
|
26
|
+
http.start() do |http|
|
27
|
+
assert_equal( http.class, MyHTTP )
|
28
|
+
http.request_post( '/oauth/example/request_token.php', nil ) do |res|
|
29
|
+
assert_equal( '200', res.code )
|
30
|
+
assert_equal( 'oauth_token=requestkey&oauth_token_secret=requestsecret', res.body )
|
31
|
+
end
|
32
|
+
|
33
|
+
token, secret = http.request_oauth_temp_credentials( '/oauth/example/request_token.php', 'oob' )
|
34
|
+
assert_equal( 'requestkey' , token )
|
35
|
+
assert_equal( 'requestsecret', secret )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
__END__
|
42
|
+
|
43
|
+
assert( .... )
|
data/test/test_main.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path File.join( File.dirname(__FILE__), 'helper_path_setting' )
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
require 'minitest/unit'
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'oauth_simple'
|
10
|
+
require 'oauth_simple/http'
|
11
|
+
|
12
|
+
class TestMain < MiniTest::Unit::TestCase
|
13
|
+
|
14
|
+
def test_proxy
|
15
|
+
http = OAuthSimple::HTTP.Proxy( '96.32.133.3', '8085' ).new( 'api.twitter.com' )
|
16
|
+
assert( http.is_a? OAuthSimple::HTTP )
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_sign_simple
|
20
|
+
base_str = 'GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal'
|
21
|
+
secret_str = 'kd94hf93k423kf44&pfkkdhi9sl3r4s00'
|
22
|
+
signature = 'tR3+Ty81lMeYAr/Fid0kMTYa/WM='
|
23
|
+
digest = OpenSSL::HMAC::digest( OpenSSL::Digest::SHA1.new(), secret_str, base_str )
|
24
|
+
assert_equal( signature, [digest].pack('m').gsub!( /\n/u, '' ) )
|
25
|
+
base_str = 'POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q%26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk9d7dh3k39sjv7'
|
26
|
+
secret_str = 'j49sk3j29djd&dh893hdasih9'
|
27
|
+
signature = 'r6%2FTJjbCOr97%2F%2BUU0NsvSne7s5g%3D'
|
28
|
+
digest = OpenSSL::HMAC::digest( OpenSSL::Digest::SHA1.new(), secret_str, base_str )
|
29
|
+
assert_equal( signature, OAuthSimple::HelperFunctions.enc_perenc( [digest].pack('m').gsub!( /\n/u, '' ) ) )
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_nonce_string_creation
|
33
|
+
# 引数を与えなければ, 16 文字の文字列
|
34
|
+
nonce_str = OAuthSimple::HelperFunctions.create_nonce_str()
|
35
|
+
assert_equal( nonce_str.class, String )
|
36
|
+
assert_equal( nonce_str.length, 16 )
|
37
|
+
# 0 以上の整数を引数として与えると, その長さの文字列
|
38
|
+
[ 20, 0, 300, 432, 125432 ].each do |len|
|
39
|
+
nonce_str = OAuthSimple::HelperFunctions.create_nonce_str( len )
|
40
|
+
assert_equal( nonce_str.class, String )
|
41
|
+
assert_equal( nonce_str.length, len )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_helper
|
46
|
+
req_helper = OAuthSimple::RequestHelper.new(
|
47
|
+
URI.parse( 'https://api.twitter.com/oauth/request_token' ),
|
48
|
+
'POST',
|
49
|
+
'CONS_SECRET_XXXX&',
|
50
|
+
OAuthSimple::RequestParamList.new( [
|
51
|
+
# TwitVC
|
52
|
+
[ 'oauth_consumer_key', 'CONS_KEY_XXXX' ],
|
53
|
+
[ 'oauth_signature_method', 'HMAC-SHA1' ],
|
54
|
+
[ 'oauth_timestamp', ( Time.now() - Time.utc( 1970, 1, 1 ) ).to_i().to_s() ],
|
55
|
+
[ 'oauth_nonce', 'dfaeaveafefea' ],
|
56
|
+
[ 'oauth_version', '1.0' ],
|
57
|
+
] ),
|
58
|
+
)
|
59
|
+
assert_equal( req_helper.host, 'api.twitter.com' )
|
60
|
+
assert_equal( req_helper.port, 443 )
|
61
|
+
end
|
62
|
+
|
63
|
+
# RFC5849 Sec. 3.1 の試験
|
64
|
+
# http://tools.ietf.org/html/rfc5849
|
65
|
+
#
|
66
|
+
# POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1
|
67
|
+
# Host: example.com
|
68
|
+
# Content-Type: application/x-www-form-urlencoded
|
69
|
+
#
|
70
|
+
# c2&a3=2+q
|
71
|
+
#
|
72
|
+
# The client assigns values to the following protocol parameters using
|
73
|
+
# its client credentials, token credentials, the current timestamp, a
|
74
|
+
# uniquely generated nonce, and indicates that it will use the
|
75
|
+
# "HMAC-SHA1" signature method:
|
76
|
+
# oauth_consumer_key: 9djdj82h48djs9d2
|
77
|
+
# oauth_token: kkk9d7dh3k39sjv7
|
78
|
+
# oauth_signature_method: HMAC-SHA1
|
79
|
+
# oauth_timestamp: 137131201
|
80
|
+
# oauth_nonce: 7d8f3e4a
|
81
|
+
def test_sign
|
82
|
+
client_secret = 'j49sk3j29djd'
|
83
|
+
token_secret = 'dh893hdasih9'
|
84
|
+
req_helper = OAuthSimple::RequestHelper.new(
|
85
|
+
URI.parse( 'http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b' ),
|
86
|
+
'POST',
|
87
|
+
"#{client_secret}&#{token_secret}",
|
88
|
+
OAuthSimple::RequestParamList.new( [
|
89
|
+
[ 'oauth_consumer_key', '9djdj82h48djs9d2' ],
|
90
|
+
[ 'oauth_token', 'kkk9d7dh3k39sjv7' ],
|
91
|
+
[ 'oauth_signature_method', 'HMAC-SHA1' ],
|
92
|
+
[ 'oauth_timestamp', '137131201' ],
|
93
|
+
[ 'oauth_nonce', '7d8f3e4a' ],
|
94
|
+
] ),
|
95
|
+
nil,
|
96
|
+
OAuthSimple::RequestParamList.new( [
|
97
|
+
[ 'c2', nil ],
|
98
|
+
[ 'a3', '2 q' ],
|
99
|
+
] ),
|
100
|
+
)
|
101
|
+
#p req_helper.oauth_header_str
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_factory
|
105
|
+
rhf = OAuthSimple::RequestHelperFactory.new(
|
106
|
+
:consumer_key => '9djdj82h48djs9d2',
|
107
|
+
:consumer_secret => 'j49sk3j29djd' ,
|
108
|
+
:token => 'kkk9d7dh3k39sjv7',
|
109
|
+
:token_secret => 'dh893hdasih9' ,
|
110
|
+
:signature_method => 'HMAC-SHA1' ,
|
111
|
+
)
|
112
|
+
req_helper = rhf.create(
|
113
|
+
URI.parse( 'http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b' ),
|
114
|
+
'POST',
|
115
|
+
:body_params => OAuthSimple::RequestParamList.new( [
|
116
|
+
[ 'c2', nil ],
|
117
|
+
[ 'a3', '2 q' ],
|
118
|
+
] )
|
119
|
+
)
|
120
|
+
assert_equal( req_helper.class, OAuthSimple::RequestHelper )
|
121
|
+
#p req_helper.oauth_header_str
|
122
|
+
end
|
123
|
+
|
124
|
+
###
|
125
|
+
# test by using OAuth Test Server : http://term.ie/oauth/example/
|
126
|
+
def test_getting_request_token
|
127
|
+
# OAuthSimple::HTTP is a subclass of Net::HTTP
|
128
|
+
http = OAuthSimple::HTTP.new( 'term.ie' )
|
129
|
+
|
130
|
+
# OAuth setting (this feature provided by OAuthSimple::HTTP)
|
131
|
+
http.use_oauth = true
|
132
|
+
http.set_oauth_client_credentials( 'key', 'secret' )
|
133
|
+
http.set_oauth_signature_method( 'HMAC-SHA1' ) # at this time, only 'HMAC-SHA1' is supported
|
134
|
+
|
135
|
+
# connection start
|
136
|
+
http.start() do |http|
|
137
|
+
assert_equal( http.class, OAuthSimple::HTTP )
|
138
|
+
http.request_post( '/oauth/example/request_token.php', nil ) do |res|
|
139
|
+
assert_equal( '200', res.code )
|
140
|
+
assert_equal( 'oauth_token=requestkey&oauth_token_secret=requestsecret', res.body )
|
141
|
+
end
|
142
|
+
|
143
|
+
token, secret = http.request_oauth_temp_credentials( '/oauth/example/request_token.php', 'oob' )
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
__END__
|
150
|
+
|
151
|
+
assert( .... )
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oauth_simple
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.pre
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- NOBUOKA Yu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-11 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: nobuoka@vividcode.info
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README.rdoc
|
20
|
+
files:
|
21
|
+
- README.rdoc
|
22
|
+
- rakefile.rb
|
23
|
+
- .gemtest
|
24
|
+
- lib/oauth_simple/request_param_list.rb
|
25
|
+
- lib/oauth_simple/helper_functions.rb
|
26
|
+
- lib/oauth_simple/request_helper_factory.rb
|
27
|
+
- lib/oauth_simple/request_helper.rb
|
28
|
+
- lib/oauth_simple/http.rb
|
29
|
+
- lib/oauth_simple.rb
|
30
|
+
- test/helper_path_setting.rb
|
31
|
+
- test/test_http.rb
|
32
|
+
- test/test_main.rb
|
33
|
+
homepage: https://github.com/nobuoka/ruby-OAuthSimple
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --charset=UTF-8
|
38
|
+
- --main
|
39
|
+
- README.rdoc
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>'
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.1
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.8.24
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Helper for OAuth 1.0
|
60
|
+
test_files:
|
61
|
+
- test/test_main.rb
|