oauth 0.5.6 → 1.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +504 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/CONTRIBUTING.md +40 -0
- data/LICENSE +19 -17
- data/README.md +390 -0
- data/SECURITY.md +26 -0
- data/lib/oauth/client/action_controller_request.rb +23 -21
- data/lib/oauth/client/em_http.rb +99 -99
- data/lib/oauth/client/helper.rb +83 -82
- data/lib/oauth/client/net_http.rb +112 -105
- data/lib/oauth/client.rb +2 -0
- data/lib/oauth/consumer.rb +147 -133
- data/lib/oauth/errors/error.rb +2 -0
- data/lib/oauth/errors/problem.rb +3 -0
- data/lib/oauth/errors/unauthorized.rb +7 -1
- data/lib/oauth/errors.rb +5 -3
- data/lib/oauth/helper.rb +26 -18
- data/lib/oauth/oauth.rb +6 -4
- data/lib/oauth/oauth_test_helper.rb +6 -4
- data/lib/oauth/request_proxy/action_controller_request.rb +49 -71
- data/lib/oauth/request_proxy/action_dispatch_request.rb +8 -4
- data/lib/oauth/request_proxy/base.rb +136 -132
- data/lib/oauth/request_proxy/curb_request.rb +49 -43
- data/lib/oauth/request_proxy/em_http_request.rb +59 -49
- data/lib/oauth/request_proxy/jabber_request.rb +12 -9
- data/lib/oauth/request_proxy/mock_request.rb +5 -3
- data/lib/oauth/request_proxy/net_http.rb +61 -54
- data/lib/oauth/request_proxy/rack_request.rb +35 -31
- data/lib/oauth/request_proxy/rest_client_request.rb +54 -50
- data/lib/oauth/request_proxy/typhoeus_request.rb +51 -45
- data/lib/oauth/request_proxy.rb +7 -4
- data/lib/oauth/server.rb +14 -12
- data/lib/oauth/signature/base.rb +78 -71
- data/lib/oauth/signature/hmac/sha1.rb +16 -10
- data/lib/oauth/signature/hmac/sha256.rb +16 -10
- data/lib/oauth/signature/plaintext.rb +18 -20
- data/lib/oauth/signature/rsa/sha1.rb +46 -38
- data/lib/oauth/signature.rb +8 -5
- data/lib/oauth/token.rb +7 -5
- data/lib/oauth/tokens/access_token.rb +5 -3
- data/lib/oauth/tokens/consumer_token.rb +4 -2
- data/lib/oauth/tokens/request_token.rb +12 -10
- data/lib/oauth/tokens/server_token.rb +2 -1
- data/lib/oauth/tokens/token.rb +2 -0
- data/lib/oauth/version.rb +5 -1
- data/lib/oauth.rb +17 -9
- metadata +105 -98
- data/README.rdoc +0 -88
- data/bin/oauth +0 -11
- data/lib/oauth/cli/authorize_command.rb +0 -71
- data/lib/oauth/cli/base_command.rb +0 -208
- data/lib/oauth/cli/help_command.rb +0 -22
- data/lib/oauth/cli/query_command.rb +0 -25
- data/lib/oauth/cli/sign_command.rb +0 -81
- data/lib/oauth/cli/version_command.rb +0 -7
- data/lib/oauth/cli.rb +0 -56
data/lib/oauth/client.rb
CHANGED
data/lib/oauth/consumer.rb
CHANGED
@@ -1,23 +1,26 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "net/https"
|
5
|
+
require "oauth/oauth"
|
6
|
+
require "oauth/client/net_http"
|
7
|
+
require "oauth/errors"
|
8
|
+
require "cgi"
|
7
9
|
|
8
10
|
module OAuth
|
9
11
|
class Consumer
|
10
12
|
# determine the certificate authority path to verify SSL certs
|
11
|
-
if ENV[
|
12
|
-
if File.exist?(ENV[
|
13
|
-
CA_FILE = ENV[
|
13
|
+
if ENV["SSL_CERT_FILE"]
|
14
|
+
if File.exist?(ENV["SSL_CERT_FILE"])
|
15
|
+
CA_FILE = ENV["SSL_CERT_FILE"]
|
14
16
|
else
|
15
17
|
raise "The SSL CERT provided does not exist."
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
CA_FILES = %
|
21
|
+
unless defined?(CA_FILE)
|
22
|
+
CA_FILES = %w[/etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt
|
23
|
+
/usr/share/curl/curl-ca-bundle.crt].freeze
|
21
24
|
CA_FILES.each do |ca_file|
|
22
25
|
if File.exist?(ca_file)
|
23
26
|
CA_FILE = ca_file
|
@@ -27,42 +30,49 @@ module OAuth
|
|
27
30
|
end
|
28
31
|
CA_FILE = nil unless defined?(CA_FILE)
|
29
32
|
|
30
|
-
@@default_options =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
33
|
+
@@default_options = SnakyHash::SymbolKeyed.new(
|
34
|
+
{
|
35
|
+
# Signature method used by server. Defaults to HMAC-SHA1
|
36
|
+
signature_method: "HMAC-SHA1",
|
37
|
+
|
38
|
+
# default paths on site. These are the same as the defaults set up by the generators
|
39
|
+
request_token_path: "/oauth/request_token",
|
40
|
+
authenticate_path: "/oauth/authenticate",
|
41
|
+
authorize_path: "/oauth/authorize",
|
42
|
+
access_token_path: "/oauth/access_token",
|
43
|
+
|
44
|
+
proxy: nil,
|
45
|
+
# How do we send the oauth values to the server see
|
46
|
+
# https://oauth.net/core/1.0/#consumer_req_param for more info
|
47
|
+
#
|
48
|
+
# Possible values:
|
49
|
+
#
|
50
|
+
# :header - via the Authorize header (Default) ( option 1. in spec)
|
51
|
+
# :body - url form encoded in body of POST request ( option 2. in spec)
|
52
|
+
# :query_string - via the query part of the url ( option 3. in spec)
|
53
|
+
scheme: :header,
|
54
|
+
|
55
|
+
# Default http method used for OAuth Token Requests (defaults to :post)
|
56
|
+
http_method: :post,
|
57
|
+
|
58
|
+
# Add a custom ca_file for consumer
|
59
|
+
# :ca_file => '/etc/certs.pem'
|
60
|
+
|
61
|
+
# Possible values:
|
62
|
+
#
|
63
|
+
# nil, false - no debug output
|
64
|
+
# true - uses $stdout
|
65
|
+
# some_value - uses some_value
|
66
|
+
debug_output: nil,
|
67
|
+
|
68
|
+
# Defaults to producing a body_hash as part of the signature but
|
69
|
+
# can be disabled since it's not officially part of the OAuth 1.0
|
70
|
+
# spec. Possible values are true and false
|
71
|
+
body_hash_enabled: true,
|
72
|
+
|
73
|
+
oauth_version: "1.0"
|
74
|
+
}
|
75
|
+
)
|
66
76
|
|
67
77
|
attr_accessor :options, :key, :secret
|
68
78
|
attr_writer :site, :http
|
@@ -75,7 +85,8 @@ module OAuth
|
|
75
85
|
# :http_method => :post,
|
76
86
|
# :request_token_path => "/oauth/example/request_token.php",
|
77
87
|
# :access_token_path => "/oauth/example/access_token.php",
|
78
|
-
# :authorize_path => "/oauth/example/authorize.php"
|
88
|
+
# :authorize_path => "/oauth/example/authorize.php",
|
89
|
+
# :body_hash_enabled => false
|
79
90
|
# })
|
80
91
|
#
|
81
92
|
# Start the process by requesting a token
|
@@ -94,10 +105,8 @@ module OAuth
|
|
94
105
|
@secret = consumer_secret
|
95
106
|
|
96
107
|
# ensure that keys are symbols
|
97
|
-
|
98
|
-
|
99
|
-
opts
|
100
|
-
end)
|
108
|
+
snaky_options = SnakyHash::SymbolKeyed.new(options)
|
109
|
+
@options = @@default_options.merge(snaky_options)
|
101
110
|
end
|
102
111
|
|
103
112
|
# The default http method
|
@@ -106,15 +115,13 @@ module OAuth
|
|
106
115
|
end
|
107
116
|
|
108
117
|
def debug_output
|
109
|
-
@debug_output ||=
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
end
|
118
|
+
@debug_output ||= case @options[:debug_output]
|
119
|
+
when nil, false
|
120
|
+
when true
|
121
|
+
$stdout
|
122
|
+
else
|
123
|
+
@options[:debug_output]
|
124
|
+
end
|
118
125
|
end
|
119
126
|
|
120
127
|
# The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new
|
@@ -127,13 +134,14 @@ module OAuth
|
|
127
134
|
if custom_uri
|
128
135
|
@uri = custom_uri
|
129
136
|
@http = create_http # yike, oh well. less intrusive this way
|
130
|
-
else
|
137
|
+
else # if no custom passed, we use existing, which, if unset, is set to site uri
|
131
138
|
@uri ||= URI.parse(site)
|
132
139
|
end
|
133
140
|
end
|
134
141
|
|
135
142
|
def get_access_token(request_token, request_options = {}, *arguments, &block)
|
136
|
-
response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token,
|
143
|
+
response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token,
|
144
|
+
request_options, *arguments, &block)
|
137
145
|
OAuth::AccessToken.from_hash(self, response)
|
138
146
|
end
|
139
147
|
|
@@ -156,15 +164,19 @@ module OAuth
|
|
156
164
|
# will be exchanged out of band
|
157
165
|
request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND unless request_options[:exclude_callback]
|
158
166
|
|
159
|
-
if
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
167
|
+
response = if block
|
168
|
+
token_request(
|
169
|
+
http_method,
|
170
|
+
(request_token_url? ? request_token_url : request_token_path),
|
171
|
+
nil,
|
172
|
+
request_options,
|
173
|
+
*arguments,
|
174
|
+
&block
|
175
|
+
)
|
176
|
+
else
|
177
|
+
token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil,
|
178
|
+
request_options, *arguments)
|
179
|
+
end
|
168
180
|
OAuth::RequestToken.from_hash(self, response)
|
169
181
|
end
|
170
182
|
|
@@ -179,7 +191,7 @@ module OAuth
|
|
179
191
|
# @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
|
180
192
|
#
|
181
193
|
def request(http_method, path, token = nil, request_options = {}, *arguments)
|
182
|
-
|
194
|
+
unless %r{^/}.match?(path)
|
183
195
|
@http = create_http(path)
|
184
196
|
_uri = URI.parse(path)
|
185
197
|
path = "#{_uri.path}#{_uri.query ? "?#{_uri.query}" : ""}"
|
@@ -187,18 +199,19 @@ module OAuth
|
|
187
199
|
|
188
200
|
# override the request with your own, this is useful for file uploads which Net::HTTP does not do
|
189
201
|
req = create_signed_request(http_method, path, token, request_options, *arguments)
|
190
|
-
return nil if block_given?
|
202
|
+
return nil if block_given? && (yield(req) == :done)
|
203
|
+
|
191
204
|
rsp = http.request(req)
|
192
205
|
# check for an error reported by the Problem Reporting extension
|
193
|
-
# (
|
206
|
+
# (https://wiki.oauth.net/ProblemReporting)
|
194
207
|
# note: a 200 may actually be an error; check for an oauth_problem key to be sure
|
195
208
|
if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
|
196
|
-
|
197
|
-
|
209
|
+
(h = headers.grep(/^OAuth /)).any? &&
|
210
|
+
h.first.include?("oauth_problem")
|
198
211
|
|
199
212
|
# puts "Header: #{h.first}"
|
200
213
|
|
201
|
-
# TODO doesn't handle broken responses from api.login.yahoo.com
|
214
|
+
# TODO: doesn't handle broken responses from api.login.yahoo.com
|
202
215
|
# remove debug code when done
|
203
216
|
params = OAuth::Helper.parse_header(h.first)
|
204
217
|
|
@@ -232,24 +245,25 @@ module OAuth
|
|
232
245
|
# symbolize keys
|
233
246
|
# TODO this could be considered unexpected behavior; symbols or not?
|
234
247
|
# TODO this also drops subsequent values from multi-valued keys
|
235
|
-
CGI.parse(response.body).
|
248
|
+
CGI.parse(response.body).each_with_object({}) do |(k, v), h|
|
236
249
|
h[k.strip.to_sym] = v.first
|
237
250
|
h[k.strip] = v.first
|
238
|
-
h
|
239
251
|
end
|
240
252
|
end
|
241
253
|
when (300..399)
|
242
|
-
#
|
243
|
-
uri = URI.parse(response[
|
254
|
+
# Parse redirect to follow
|
255
|
+
uri = URI.parse(response["location"])
|
244
256
|
our_uri = URI.parse(site)
|
245
257
|
|
258
|
+
# Guard against infinite redirects
|
259
|
+
response.error! if uri.path == path && our_uri.host == uri.host
|
260
|
+
|
246
261
|
if uri.path == path && our_uri.host != uri.host
|
247
|
-
|
248
|
-
|
262
|
+
options[:site] = "#{uri.scheme}://#{uri.host}"
|
263
|
+
@http = create_http
|
249
264
|
end
|
250
265
|
|
251
|
-
|
252
|
-
self.token_request(http_method, uri.path, token, request_options, arguments)
|
266
|
+
token_request(http_method, uri.path, token, request_options, arguments)
|
253
267
|
when (400..499)
|
254
268
|
raise OAuth::Unauthorized, response
|
255
269
|
else
|
@@ -273,6 +287,7 @@ module OAuth
|
|
273
287
|
|
274
288
|
def request_endpoint
|
275
289
|
return nil if @options[:request_endpoint].nil?
|
290
|
+
|
276
291
|
@options[:request_endpoint].to_s
|
277
292
|
end
|
278
293
|
|
@@ -296,37 +311,37 @@ module OAuth
|
|
296
311
|
@options[:access_token_path]
|
297
312
|
end
|
298
313
|
|
299
|
-
# TODO this is ugly, rewrite
|
314
|
+
# TODO: this is ugly, rewrite
|
300
315
|
def request_token_url
|
301
|
-
@options[:request_token_url] || site + request_token_path
|
316
|
+
@options[:request_token_url] || (site + request_token_path)
|
302
317
|
end
|
303
318
|
|
304
319
|
def request_token_url?
|
305
|
-
@options.
|
320
|
+
@options.key?(:request_token_url)
|
306
321
|
end
|
307
322
|
|
308
323
|
def authenticate_url
|
309
|
-
@options[:authenticate_url] || site + authenticate_path
|
324
|
+
@options[:authenticate_url] || (site + authenticate_path)
|
310
325
|
end
|
311
326
|
|
312
327
|
def authenticate_url?
|
313
|
-
@options.
|
328
|
+
@options.key?(:authenticate_url)
|
314
329
|
end
|
315
330
|
|
316
331
|
def authorize_url
|
317
|
-
@options[:authorize_url] || site + authorize_path
|
332
|
+
@options[:authorize_url] || (site + authorize_path)
|
318
333
|
end
|
319
334
|
|
320
335
|
def authorize_url?
|
321
|
-
@options.
|
336
|
+
@options.key?(:authorize_url)
|
322
337
|
end
|
323
338
|
|
324
339
|
def access_token_url
|
325
|
-
@options[:access_token_url] || site + access_token_path
|
340
|
+
@options[:access_token_url] || (site + access_token_path)
|
326
341
|
end
|
327
342
|
|
328
343
|
def access_token_url?
|
329
|
-
@options.
|
344
|
+
@options.key?(:access_token_url)
|
330
345
|
end
|
331
346
|
|
332
347
|
def proxy
|
@@ -337,36 +352,36 @@ module OAuth
|
|
337
352
|
|
338
353
|
# Instantiates the http object
|
339
354
|
def create_http(_url = nil)
|
340
|
-
|
341
|
-
|
342
|
-
if
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
355
|
+
_url = request_endpoint unless request_endpoint.nil?
|
356
|
+
|
357
|
+
our_uri = if _url.nil? || _url[0] =~ %r{^/}
|
358
|
+
URI.parse(site)
|
359
|
+
else
|
360
|
+
your_uri = URI.parse(_url)
|
361
|
+
if your_uri.host.nil?
|
362
|
+
# If the _url is a path, missing the leading slash, then it won't have a host,
|
363
|
+
# and our_uri *must* have a host, so we parse site instead.
|
364
|
+
URI.parse(site)
|
365
|
+
else
|
366
|
+
your_uri
|
367
|
+
end
|
368
|
+
end
|
353
369
|
|
354
370
|
if proxy.nil?
|
355
371
|
http_object = Net::HTTP.new(our_uri.host, our_uri.port)
|
356
372
|
else
|
357
373
|
proxy_uri = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
|
358
|
-
http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user,
|
374
|
+
http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user,
|
375
|
+
proxy_uri.password)
|
359
376
|
end
|
360
377
|
|
361
|
-
http_object.use_ssl = (our_uri.scheme ==
|
378
|
+
http_object.use_ssl = (our_uri.scheme == "https")
|
362
379
|
|
363
380
|
if @options[:no_verify]
|
364
381
|
http_object.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
365
382
|
else
|
366
|
-
ca_file =
|
367
|
-
if ca_file
|
368
|
-
http_object.ca_file = ca_file
|
369
|
-
end
|
383
|
+
ca_file = @options[:ca_file] || CA_FILE
|
384
|
+
http_object.ca_file = ca_file if ca_file
|
370
385
|
http_object.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
371
386
|
http_object.verify_depth = 5
|
372
387
|
end
|
@@ -374,6 +389,8 @@ module OAuth
|
|
374
389
|
http_object.read_timeout = http_object.open_timeout = @options[:timeout] || 60
|
375
390
|
http_object.open_timeout = @options[:open_timeout] if @options[:open_timeout]
|
376
391
|
http_object.ssl_version = @options[:ssl_version] if @options[:ssl_version]
|
392
|
+
http_object.cert = @options[:ssl_client_cert] if @options[:ssl_client_cert]
|
393
|
+
http_object.key = @options[:ssl_client_key] if @options[:ssl_client_key]
|
377
394
|
http_object.set_debug_output(debug_output) if debug_output
|
378
395
|
|
379
396
|
http_object
|
@@ -383,41 +400,39 @@ module OAuth
|
|
383
400
|
def create_http_request(http_method, path, *arguments)
|
384
401
|
http_method = http_method.to_sym
|
385
402
|
|
386
|
-
if [
|
387
|
-
data = arguments.shift
|
388
|
-
end
|
403
|
+
data = arguments.shift if %i[post put patch].include?(http_method)
|
389
404
|
|
390
405
|
# if the base site contains a path, add it now
|
391
406
|
# only add if the site host matches the current http object's host
|
392
407
|
# (in case we've specified a full url for token requests)
|
393
|
-
uri
|
394
|
-
path = uri.path + path if uri.path && uri.path !=
|
408
|
+
uri = URI.parse(site)
|
409
|
+
path = uri.path + path if uri.path && uri.path != "/" && uri.host == http.address
|
395
410
|
|
396
411
|
headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
|
397
412
|
|
398
413
|
case http_method
|
399
414
|
when :post
|
400
|
-
request = Net::HTTP::Post.new(path,headers)
|
401
|
-
request["Content-Length"] =
|
415
|
+
request = Net::HTTP::Post.new(path, headers)
|
416
|
+
request["Content-Length"] = "0" # Default to 0
|
402
417
|
when :put
|
403
|
-
request = Net::HTTP::Put.new(path,headers)
|
404
|
-
request["Content-Length"] =
|
418
|
+
request = Net::HTTP::Put.new(path, headers)
|
419
|
+
request["Content-Length"] = "0" # Default to 0
|
405
420
|
when :patch
|
406
|
-
request = Net::HTTP::Patch.new(path,headers)
|
407
|
-
request["Content-Length"] =
|
421
|
+
request = Net::HTTP::Patch.new(path, headers)
|
422
|
+
request["Content-Length"] = "0" # Default to 0
|
408
423
|
when :get
|
409
|
-
request = Net::HTTP::Get.new(path,headers)
|
424
|
+
request = Net::HTTP::Get.new(path, headers)
|
410
425
|
when :delete
|
411
|
-
request =
|
426
|
+
request = Net::HTTP::Delete.new(path, headers)
|
412
427
|
when :head
|
413
|
-
request = Net::HTTP::Head.new(path,headers)
|
428
|
+
request = Net::HTTP::Head.new(path, headers)
|
414
429
|
else
|
415
|
-
raise ArgumentError, "Don't know how to handle http_method: :#{http_method
|
430
|
+
raise ArgumentError, "Don't know how to handle http_method: :#{http_method}"
|
416
431
|
end
|
417
432
|
|
418
433
|
if data.is_a?(Hash)
|
419
434
|
request.body = OAuth::Helper.normalize(data)
|
420
|
-
request.content_type =
|
435
|
+
request.content_type = "application/x-www-form-urlencoded"
|
421
436
|
elsif data
|
422
437
|
if data.respond_to?(:read)
|
423
438
|
request.body_stream = data
|
@@ -437,13 +452,12 @@ module OAuth
|
|
437
452
|
request
|
438
453
|
end
|
439
454
|
|
440
|
-
def marshal_dump(*
|
441
|
-
{:
|
455
|
+
def marshal_dump(*_args)
|
456
|
+
{ key: @key, secret: @secret, options: @options }
|
442
457
|
end
|
443
458
|
|
444
459
|
def marshal_load(data)
|
445
460
|
initialize(data[:key], data[:secret], data[:options])
|
446
461
|
end
|
447
|
-
|
448
462
|
end
|
449
463
|
end
|
data/lib/oauth/errors/error.rb
CHANGED
data/lib/oauth/errors/problem.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OAuth
|
2
4
|
class Unauthorized < OAuth::Error
|
3
5
|
attr_reader :request
|
6
|
+
|
4
7
|
def initialize(request = nil)
|
8
|
+
super()
|
5
9
|
@request = request
|
6
10
|
end
|
7
11
|
|
8
12
|
def to_s
|
9
|
-
|
13
|
+
return "401 Unauthorized" if request.nil?
|
14
|
+
|
15
|
+
"#{request.code} #{request.message}"
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
data/lib/oauth/errors.rb
CHANGED
data/lib/oauth/helper.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "time"
|
4
|
+
require "openssl"
|
5
|
+
require "base64"
|
3
6
|
|
4
7
|
module OAuth
|
5
8
|
module Helper
|
6
|
-
|
9
|
+
module_function
|
7
10
|
|
8
11
|
# Escape +value+ by URL encoding all non-reserved character.
|
9
12
|
#
|
@@ -19,18 +22,18 @@ module OAuth
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def unescape(value)
|
22
|
-
URI::DEFAULT_PARSER.unescape(value.gsub(
|
25
|
+
URI::DEFAULT_PARSER.unescape(value.gsub("+", "%2B"))
|
23
26
|
end
|
24
27
|
|
25
28
|
# Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
|
26
29
|
# characters removed.
|
27
|
-
def generate_key(size=32)
|
28
|
-
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,
|
30
|
+
def generate_key(size = 32)
|
31
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, "")
|
29
32
|
end
|
30
33
|
|
31
|
-
|
34
|
+
alias generate_nonce generate_key
|
32
35
|
|
33
|
-
def generate_timestamp
|
36
|
+
def generate_timestamp # :nodoc:
|
34
37
|
Time.now.to_i.to_s
|
35
38
|
end
|
36
39
|
|
@@ -43,22 +46,27 @@ module OAuth
|
|
43
46
|
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
44
47
|
def normalize(params)
|
45
48
|
params.sort.map do |k, values|
|
46
|
-
|
49
|
+
case values
|
50
|
+
when Array
|
47
51
|
# make sure the array has an element so we don't lose the key
|
48
52
|
values << nil if values.empty?
|
49
53
|
# multiple values were provided for a single key
|
50
|
-
values.
|
51
|
-
|
54
|
+
if values[0].is_a?(Hash)
|
55
|
+
normalize_nested_query(values, k)
|
56
|
+
else
|
57
|
+
values.sort.collect do |v|
|
58
|
+
[escape(k), escape(v)].join("=")
|
59
|
+
end
|
52
60
|
end
|
53
|
-
|
61
|
+
when Hash
|
54
62
|
normalize_nested_query(values, k)
|
55
63
|
else
|
56
|
-
[escape(k),escape(values)]
|
64
|
+
[escape(k), escape(values)].join("=")
|
57
65
|
end
|
58
66
|
end * "&"
|
59
67
|
end
|
60
68
|
|
61
|
-
#Returns a string representation of the Hash like in URL query string
|
69
|
+
# Returns a string representation of the Hash like in URL query string
|
62
70
|
# build_nested_query({:level_1 => {:level_2 => ['value_1','value_2']}}, 'prefix'))
|
63
71
|
# #=> ["prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_1", "prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_2"]
|
64
72
|
def normalize_nested_query(value, prefix = nil)
|
@@ -72,7 +80,7 @@ module OAuth
|
|
72
80
|
normalize_nested_query(v, prefix ? "#{prefix}[#{k}]" : k)
|
73
81
|
end.flatten.sort
|
74
82
|
else
|
75
|
-
[escape(prefix), escape(value)]
|
83
|
+
[escape(prefix), escape(value)].join("=")
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
@@ -86,16 +94,16 @@ module OAuth
|
|
86
94
|
#
|
87
95
|
def parse_header(header)
|
88
96
|
# decompose
|
89
|
-
params = header[6,header.length].split(/[,=&]/)
|
97
|
+
params = header[6, header.length].split(/[,=&]/)
|
90
98
|
|
91
99
|
# odd number of arguments - must be a malformed header.
|
92
|
-
raise OAuth::Problem
|
100
|
+
raise OAuth::Problem, "Invalid authorization header" if params.size.odd?
|
93
101
|
|
94
102
|
params.map! do |v|
|
95
103
|
# strip and unescape
|
96
104
|
val = unescape(v.strip)
|
97
105
|
# strip quotes
|
98
|
-
val.sub(
|
106
|
+
val.sub(/^"(.*)"$/, '\1')
|
99
107
|
end
|
100
108
|
|
101
109
|
# convert into a Hash
|
data/lib/oauth/oauth.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OAuth
|
2
4
|
# request tokens are passed between the consumer and the provider out of
|
3
5
|
# band (i.e. callbacks cannot be used), per section 6.1.1
|
4
6
|
OUT_OF_BAND = "oob"
|
5
7
|
|
6
8
|
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
7
|
-
PARAMETERS = %w
|
8
|
-
|
9
|
-
|
9
|
+
PARAMETERS = %w[oauth_callback oauth_consumer_key oauth_token
|
10
|
+
oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier
|
11
|
+
oauth_version oauth_signature oauth_body_hash].freeze
|
10
12
|
|
11
13
|
# reserved character regexp, per section 5.1
|
12
|
-
RESERVED_CHARACTERS = /[^a-zA-Z0-9
|
14
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-._~]/.freeze
|
13
15
|
end
|