mojodna-oauth 0.3.4 → 0.3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +8 -0
- data/examples/yql.rb +1 -1
- data/lib/oauth/cli.rb +54 -12
- data/lib/oauth/client/helper.rb +2 -0
- data/lib/oauth/client/net_http.rb +13 -1
- data/lib/oauth/consumer.rb +45 -5
- data/lib/oauth/oauth.rb +5 -1
- data/lib/oauth/request_proxy/base.rb +8 -0
- data/lib/oauth/tokens/consumer_token.rb +1 -0
- data/lib/oauth/tokens/request_token.rb +4 -0
- data/lib/oauth/version.rb +1 -1
- data/oauth.gemspec +1 -1
- data/test/test_consumer.rb +35 -1
- metadata +1 -1
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.3.5
|
2
|
+
|
3
|
+
* `query` CLI command to access protected resources (Seth)
|
4
|
+
* Added -H, -Q CLI options for specifying the authorization scheme (Seth)
|
5
|
+
* Added -O CLI option for specifying a file containing options (Seth)
|
6
|
+
* Support streamable body contents for large request bodies (Seth Cousins)
|
7
|
+
* Support for OAuth 1.0a (Seth)
|
8
|
+
|
1
9
|
== 0.3.4 2009-05-06
|
2
10
|
|
3
11
|
* OAuth::Client::Helper uses OAuth::VERSION (chadisfaction)
|
data/examples/yql.rb
CHANGED
@@ -39,6 +39,6 @@ consumer = OAuth::Consumer.new \
|
|
39
39
|
|
40
40
|
access_token = OAuth::AccessToken.new(consumer)
|
41
41
|
|
42
|
-
response = access_token.request(:get,
|
42
|
+
response = access_token.request(:get, "/v1/yql?q=#{OAuth::Helper.escape(query)}&format=json")
|
43
43
|
rsp = JSON.parse(response.body)
|
44
44
|
pp rsp
|
data/lib/oauth/cli.rb
CHANGED
@@ -6,6 +6,7 @@ module OAuth
|
|
6
6
|
SUPPORTED_COMMANDS = {
|
7
7
|
"authorize" => "Obtain an access token and secret for a user",
|
8
8
|
"debug" => "Verbosely generate an OAuth signature",
|
9
|
+
"query" => "Query a protected resource",
|
9
10
|
"sign" => "Generate an OAuth signature"
|
10
11
|
}
|
11
12
|
|
@@ -41,38 +42,59 @@ module OAuth
|
|
41
42
|
case command
|
42
43
|
# TODO move command logic elsewhere
|
43
44
|
when "authorize"
|
44
|
-
# Y! token authority requires realm=yahoo.com when headers are in use
|
45
|
-
# TODO remove :scheme when that's been fixed
|
46
|
-
# TODO determine endpoints w/ X-RDS-Simple
|
47
45
|
consumer = OAuth::Consumer.new \
|
48
46
|
options[:oauth_consumer_key],
|
49
47
|
options[:oauth_consumer_secret],
|
50
48
|
:access_token_url => options[:access_token_url],
|
51
49
|
:authorize_url => options[:authorize_url],
|
52
50
|
:request_token_url => options[:request_token_url],
|
53
|
-
:scheme => :
|
51
|
+
:scheme => options[:scheme]
|
52
|
+
|
53
|
+
# parameters for OAuth 1.0a
|
54
|
+
oauth_verifier = nil
|
54
55
|
|
55
56
|
# get a request token
|
56
|
-
request_token = consumer.get_request_token
|
57
|
+
request_token = consumer.get_request_token(:oauth_callback => options[:oauth_callback])
|
58
|
+
|
59
|
+
if request_token.callback_confirmed?
|
60
|
+
stdout.puts "Server appears to support OAuth 1.0a; enabling support."
|
61
|
+
options[:version] = "1.0a"
|
62
|
+
end
|
57
63
|
|
58
64
|
stdout.puts "Please visit this url to authorize:"
|
59
65
|
stdout.puts request_token.authorize_url
|
60
66
|
|
61
|
-
|
62
|
-
|
67
|
+
if options[:version] == "1.0a"
|
68
|
+
stdout.puts "Please enter the verification code provided by the SP (oauth_verifier):"
|
69
|
+
oauth_verifier = stdin.gets.chomp
|
70
|
+
else
|
71
|
+
stdout.puts "Press return to continue..."
|
72
|
+
stdin.gets
|
73
|
+
end
|
63
74
|
|
64
75
|
begin
|
65
76
|
# get an access token
|
66
|
-
access_token = request_token.get_access_token
|
77
|
+
access_token = request_token.get_access_token(:oauth_verifier => oauth_verifier)
|
67
78
|
|
68
79
|
stdout.puts "Response:"
|
69
80
|
access_token.params.each do |k,v|
|
70
|
-
stdout.puts " #{k}: #{v}"
|
81
|
+
stdout.puts " #{k}: #{v}" unless k.is_a?(Symbol)
|
71
82
|
end
|
72
83
|
rescue OAuth::Unauthorized => e
|
73
84
|
stderr.puts "A problem occurred while attempting to obtain an access token:"
|
74
85
|
stderr.puts e
|
75
86
|
end
|
87
|
+
when "query"
|
88
|
+
consumer = OAuth::Consumer.new \
|
89
|
+
options[:oauth_consumer_key],
|
90
|
+
options[:oauth_consumer_secret],
|
91
|
+
:scheme => options[:scheme]
|
92
|
+
|
93
|
+
access_token = OAuth::AccessToken.new(consumer, options[:oauth_token], options[:oauth_token_secret])
|
94
|
+
|
95
|
+
response = access_token.request(options[:method].downcase.to_sym, options[:uri])
|
96
|
+
puts "#{response.code} #{response.message}"
|
97
|
+
puts response.body
|
76
98
|
when "sign"
|
77
99
|
parameters = prepare_parameters
|
78
100
|
|
@@ -147,7 +169,9 @@ module OAuth
|
|
147
169
|
parse_options(arguments[0..-1])
|
148
170
|
end
|
149
171
|
|
150
|
-
def option_parser
|
172
|
+
def option_parser(arguments)
|
173
|
+
# TODO add realm parameter
|
174
|
+
# TODO add user-agent parameter
|
151
175
|
option_parser = OptionParser.new do |opts|
|
152
176
|
opts.banner = "Usage: #{$0} [options] <command>"
|
153
177
|
|
@@ -157,6 +181,8 @@ module OAuth
|
|
157
181
|
options[:oauth_timestamp] = OAuth::Helper.generate_timestamp
|
158
182
|
options[:oauth_version] = "1.0"
|
159
183
|
options[:params] = []
|
184
|
+
options[:scheme] = :header
|
185
|
+
options[:version] = "1.0"
|
160
186
|
|
161
187
|
## Common Options
|
162
188
|
|
@@ -168,7 +194,19 @@ module OAuth
|
|
168
194
|
options[:oauth_consumer_secret] = v
|
169
195
|
end
|
170
196
|
|
171
|
-
|
197
|
+
opts.on("-H", "--header", "Use the 'Authorization' header for OAuth parameters (default).") do
|
198
|
+
options[:scheme] = :header
|
199
|
+
end
|
200
|
+
|
201
|
+
opts.on("-Q", "--query-string", "Use the query string for OAuth parameters.") do
|
202
|
+
options[:scheme] = :query_string
|
203
|
+
end
|
204
|
+
|
205
|
+
opts.on("-O", "--options FILE", "Read options from a file") do |v|
|
206
|
+
arguments.unshift(*open(v).readlines.map { |l| l.chomp.split(" ") }.flatten)
|
207
|
+
end
|
208
|
+
|
209
|
+
## Options for signing and making requests
|
172
210
|
|
173
211
|
opts.on("--method METHOD", "Specifies the method (e.g. GET) to use when signing.") do |v|
|
174
212
|
options[:method] = v
|
@@ -233,6 +271,10 @@ module OAuth
|
|
233
271
|
options[:authorize_url] = v
|
234
272
|
end
|
235
273
|
|
274
|
+
opts.on("--callback-url URL", "Specifies a callback URL.") do |v|
|
275
|
+
options[:oauth_callback] = v
|
276
|
+
end
|
277
|
+
|
236
278
|
opts.on("--request-token-url URL", "Specifies the request token URL.") do |v|
|
237
279
|
options[:request_token_url] = v
|
238
280
|
end
|
@@ -240,7 +282,7 @@ module OAuth
|
|
240
282
|
end
|
241
283
|
|
242
284
|
def parse_options(arguments)
|
243
|
-
option_parser.parse!(arguments)
|
285
|
+
option_parser(arguments).parse!(arguments)
|
244
286
|
end
|
245
287
|
|
246
288
|
def prepare_parameters
|
data/lib/oauth/client/helper.rb
CHANGED
@@ -29,11 +29,13 @@ module OAuth::Client
|
|
29
29
|
|
30
30
|
def oauth_parameters
|
31
31
|
{
|
32
|
+
'oauth_callback' => options[:oauth_callback],
|
32
33
|
'oauth_consumer_key' => options[:consumer].key,
|
33
34
|
'oauth_token' => options[:token] ? options[:token].token : '',
|
34
35
|
'oauth_signature_method' => options[:signature_method],
|
35
36
|
'oauth_timestamp' => timestamp,
|
36
37
|
'oauth_nonce' => nonce,
|
38
|
+
'oauth_verifier' => options[:oauth_verifier],
|
37
39
|
'oauth_version' => '1.0'
|
38
40
|
}.reject { |k,v| v.to_s == "" }
|
39
41
|
end
|
@@ -11,6 +11,12 @@ class Net::HTTPRequest
|
|
11
11
|
# this may add a header, additional query string parameters, or additional POST body parameters.
|
12
12
|
# The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
|
13
13
|
# header.
|
14
|
+
#
|
15
|
+
# * http - Configured Net::HTTP instance
|
16
|
+
# * consumer - OAuth::Consumer instance
|
17
|
+
# * token - OAuth::Token instance
|
18
|
+
# * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
|
19
|
+
# +signature_method+, +nonce+, +timestamp+)
|
14
20
|
#
|
15
21
|
# This method also modifies the <tt>User-Agent</tt> header to add the OAuth gem version.
|
16
22
|
#
|
@@ -34,7 +40,13 @@ class Net::HTTPRequest
|
|
34
40
|
# on the <tt>options[:scheme]</tt> being used so this must match what will be used for the request
|
35
41
|
# itself. The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
|
36
42
|
# header.
|
37
|
-
#
|
43
|
+
#
|
44
|
+
# * http - Configured Net::HTTP instance
|
45
|
+
# * consumer - OAuth::Consumer instance
|
46
|
+
# * token - OAuth::Token instance
|
47
|
+
# * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
|
48
|
+
# +signature_method+, +nonce+, +timestamp+)
|
49
|
+
#
|
38
50
|
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
39
51
|
def signature_base_string(http, consumer = nil, token = nil, options = {})
|
40
52
|
options = { :request_uri => oauth_full_request_uri(http),
|
data/lib/oauth/consumer.rb
CHANGED
@@ -97,18 +97,40 @@ module OAuth
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
def get_access_token(request_token, request_options = {}, *arguments)
|
101
|
+
response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token, request_options, *arguments)
|
102
|
+
OAuth::AccessToken.from_hash(self, response)
|
103
|
+
end
|
104
|
+
|
100
105
|
# Makes a request to the service for a new OAuth::RequestToken
|
101
106
|
#
|
102
107
|
# @request_token = @consumer.get_request_token
|
103
108
|
#
|
109
|
+
# To include OAuth parameters:
|
110
|
+
#
|
111
|
+
# @request_token = @consumer.get_request_token \
|
112
|
+
# :oauth_callback => "http://example.com/cb"
|
113
|
+
#
|
114
|
+
# To include application-specific parameters:
|
115
|
+
#
|
116
|
+
# @request_token = @consumer.get_request_token({}, :foo => "bar")
|
117
|
+
#
|
118
|
+
# TODO oauth_callback should be a mandatory parameter
|
104
119
|
def get_request_token(request_options = {}, *arguments)
|
120
|
+
# if oauth_callback wasn't provided, it is assumed that oauth_verifiers
|
121
|
+
# will be exchanged out of band
|
122
|
+
request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND
|
123
|
+
|
105
124
|
response = token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil, request_options, *arguments)
|
106
|
-
OAuth::RequestToken.
|
125
|
+
OAuth::RequestToken.from_hash(self, response)
|
107
126
|
end
|
108
127
|
|
109
128
|
# Creates, signs and performs an http request.
|
110
129
|
# It's recommended to use the OAuth::Token classes to set this up correctly.
|
111
|
-
#
|
130
|
+
# request_options take precedence over consumer-wide options when signing
|
131
|
+
# a request.
|
132
|
+
# arguments are POST and PUT bodies (a Hash, string-encoded parameters, or
|
133
|
+
# absent), followed by additional HTTP headers.
|
112
134
|
#
|
113
135
|
# @consumer.request(:get, '/people', @token, { :scheme => :query_string })
|
114
136
|
# @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
|
@@ -159,7 +181,14 @@ module OAuth
|
|
159
181
|
case response.code.to_i
|
160
182
|
|
161
183
|
when (200..299)
|
162
|
-
|
184
|
+
# symbolize keys
|
185
|
+
# TODO this could be considered unexpected behavior; symbols or not?
|
186
|
+
# TODO this also drops subsequent values from multi-valued keys
|
187
|
+
CGI.parse(response.body).inject({}) do |h,(k,v)|
|
188
|
+
h[k.to_sym] = v.first
|
189
|
+
h[k] = v.first
|
190
|
+
h
|
191
|
+
end
|
163
192
|
when (300..399)
|
164
193
|
# this is a redirect
|
165
194
|
response.error!
|
@@ -280,8 +309,19 @@ module OAuth
|
|
280
309
|
if data.is_a?(Hash)
|
281
310
|
request.set_form_data(data)
|
282
311
|
elsif data
|
283
|
-
|
284
|
-
|
312
|
+
if data.respond_to?(:read)
|
313
|
+
request.body_stream = data
|
314
|
+
if data.respond_to?(:length)
|
315
|
+
request["Content-Length"] = data.length
|
316
|
+
elsif data.respond_to?(:stat) && data.stat.respond_to?(:size)
|
317
|
+
request["Content-Length"] = data.stat.size
|
318
|
+
else
|
319
|
+
raise ArgumentError, "Don't know how to send a body_stream that doesn't respond to .length or .stat.size"
|
320
|
+
end
|
321
|
+
else
|
322
|
+
request.body = data.to_s
|
323
|
+
request["Content-Length"] = request.body.length
|
324
|
+
end
|
285
325
|
end
|
286
326
|
|
287
327
|
request
|
data/lib/oauth/oauth.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module OAuth
|
2
|
+
# request tokens are passed between the consumer and the provider out of
|
3
|
+
# band (i.e. callbacks cannot be used), per section 6.1.1
|
4
|
+
OUT_OF_BAND = "oob"
|
5
|
+
|
2
6
|
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
3
|
-
PARAMETERS = %w(oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_version oauth_signature)
|
7
|
+
PARAMETERS = %w(oauth_callback oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier oauth_version oauth_signature)
|
4
8
|
|
5
9
|
# reserved character regexp, per section 5.1
|
6
10
|
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
|
@@ -18,6 +18,10 @@ module OAuth::RequestProxy
|
|
18
18
|
|
19
19
|
## OAuth parameters
|
20
20
|
|
21
|
+
def oauth_callback
|
22
|
+
parameters['oauth_callback']
|
23
|
+
end
|
24
|
+
|
21
25
|
def oauth_consumer_key
|
22
26
|
parameters['oauth_consumer_key']
|
23
27
|
end
|
@@ -48,6 +52,10 @@ module OAuth::RequestProxy
|
|
48
52
|
parameters['oauth_token']
|
49
53
|
end
|
50
54
|
|
55
|
+
def oauth_verifier
|
56
|
+
parameters['oauth_verifier']
|
57
|
+
end
|
58
|
+
|
51
59
|
def oauth_version
|
52
60
|
parameters["oauth_version"]
|
53
61
|
end
|
@@ -9,6 +9,10 @@ module OAuth
|
|
9
9
|
build_authorize_url(consumer.authorize_url, params)
|
10
10
|
end
|
11
11
|
|
12
|
+
def callback_confirmed?
|
13
|
+
params[:oauth_callback_confirmed] == "true"
|
14
|
+
end
|
15
|
+
|
12
16
|
# exchange for AccessToken on server
|
13
17
|
def get_access_token(options = {}, *arguments)
|
14
18
|
response = consumer.token_request(consumer.http_method, (consumer.access_token_url? ? consumer.access_token_url : consumer.access_token_path), self, options, *arguments)
|
data/lib/oauth/version.rb
CHANGED
data/oauth.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{oauth}
|
5
|
-
s.version = "0.3.4"
|
5
|
+
s.version = "0.3.4.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Pelle Braendgaard", "Blaine Cook", "Larry Halff", "Jesse Clark", "Jon Crosby", "Seth Fitzsimmons", "Matt Sanford"]
|
data/test/test_consumer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
require 'oauth/consumer'
|
3
3
|
require 'oauth/signature/rsa/sha1'
|
4
|
+
require 'stringio'
|
4
5
|
|
5
6
|
|
6
7
|
# This performs testing against Andy Smith's test server http://term.ie/oauth/example/
|
@@ -318,10 +319,43 @@ class ConsumerTest < Test::Unit::TestCase
|
|
318
319
|
debug)
|
319
320
|
end
|
320
321
|
|
322
|
+
def test_post_with_body_stream
|
323
|
+
@consumer=OAuth::Consumer.new(
|
324
|
+
"key",
|
325
|
+
"secret",
|
326
|
+
{
|
327
|
+
:site=>"http://term.ie",
|
328
|
+
:request_token_path=>"/oauth/example/request_token.php",
|
329
|
+
:access_token_path=>"/oauth/example/access_token.php",
|
330
|
+
:authorize_path=>"/oauth/example/authorize.php"
|
331
|
+
})
|
332
|
+
|
333
|
+
|
334
|
+
@request_token=@consumer.get_request_token
|
335
|
+
@access_token=@request_token.get_access_token
|
336
|
+
|
337
|
+
request_body_string = "Hello, hello, hello"
|
338
|
+
request_body_stream = StringIO.new( request_body_string )
|
339
|
+
|
340
|
+
@response=@access_token.post("/oauth/example/echo_api.php",request_body_stream)
|
341
|
+
assert_not_nil @response
|
342
|
+
assert_equal "200",@response.code
|
343
|
+
|
344
|
+
request_body_file = File.open(__FILE__)
|
345
|
+
|
346
|
+
@response=@access_token.post("/oauth/example/echo_api.php",request_body_file)
|
347
|
+
assert_not_nil @response
|
348
|
+
assert_equal "200",@response.code
|
349
|
+
|
350
|
+
# unfortunately I don't know of a way to test that the body data was received correctly since the test server at http://term.ie
|
351
|
+
# echos back any non-oauth parameters but not the body. However, this does test that the request is still correctly signed
|
352
|
+
# (including the Content-Length header) and that the server received Content-Length bytes of body since it won't process the
|
353
|
+
# request & respond until the full body length is received.
|
354
|
+
end
|
355
|
+
|
321
356
|
protected
|
322
357
|
|
323
358
|
def request_parameters_to_s
|
324
359
|
@request_parameters.map { |k,v| "#{k}=#{v}" }.join("&")
|
325
360
|
end
|
326
|
-
|
327
361
|
end
|