oauth 0.5.14 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -3
  3. data/README.md +56 -46
  4. data/SECURITY.md +0 -2
  5. data/bin/oauth +8 -4
  6. data/lib/oauth/cli/authorize_command.rb +58 -54
  7. data/lib/oauth/cli/base_command.rb +163 -159
  8. data/lib/oauth/cli/help_command.rb +9 -5
  9. data/lib/oauth/cli/query_command.rb +26 -17
  10. data/lib/oauth/cli/sign_command.rb +58 -52
  11. data/lib/oauth/cli/version_command.rb +8 -4
  12. data/lib/oauth/cli.rb +2 -0
  13. data/lib/oauth/client/action_controller_request.rb +4 -1
  14. data/lib/oauth/client/em_http.rb +3 -1
  15. data/lib/oauth/client/helper.rb +76 -72
  16. data/lib/oauth/client/net_http.rb +111 -104
  17. data/lib/oauth/client.rb +2 -0
  18. data/lib/oauth/consumer.rb +89 -68
  19. data/lib/oauth/errors/error.rb +2 -0
  20. data/lib/oauth/errors/problem.rb +3 -0
  21. data/lib/oauth/errors/unauthorized.rb +4 -0
  22. data/lib/oauth/errors.rb +2 -0
  23. data/lib/oauth/helper.rb +9 -5
  24. data/lib/oauth/oauth.rb +4 -2
  25. data/lib/oauth/oauth_test_helper.rb +2 -0
  26. data/lib/oauth/request_proxy/base.rb +4 -4
  27. data/lib/oauth/request_proxy/mock_request.rb +1 -1
  28. data/lib/oauth/request_proxy/net_http.rb +8 -8
  29. data/lib/oauth/request_proxy/rest_client_request.rb +4 -3
  30. data/lib/oauth/request_proxy.rb +4 -1
  31. data/lib/oauth/server.rb +8 -4
  32. data/lib/oauth/signature/base.rb +73 -65
  33. data/lib/oauth/signature/hmac/sha1.rb +15 -9
  34. data/lib/oauth/signature/hmac/sha256.rb +15 -9
  35. data/lib/oauth/signature/plaintext.rb +18 -20
  36. data/lib/oauth/signature/rsa/sha1.rb +46 -38
  37. data/lib/oauth/signature.rb +3 -0
  38. data/lib/oauth/token.rb +2 -0
  39. data/lib/oauth/tokens/access_token.rb +2 -0
  40. data/lib/oauth/tokens/consumer_token.rb +2 -0
  41. data/lib/oauth/tokens/request_token.rb +5 -2
  42. data/lib/oauth/tokens/server_token.rb +2 -0
  43. data/lib/oauth/tokens/token.rb +2 -0
  44. data/lib/oauth/version.rb +5 -1
  45. data/lib/oauth.rb +9 -2
  46. metadata +43 -32
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "net/http"
2
4
  require "net/https"
3
5
  require "oauth/oauth"
@@ -17,7 +19,8 @@ module OAuth
17
19
  end
18
20
 
19
21
  unless defined?(CA_FILE)
20
- CA_FILES = %w[/etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt /usr/share/curl/curl-ca-bundle.crt].freeze
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
- # Signature method used by server. Defaults to HMAC-SHA1
32
- signature_method: "HMAC-SHA1",
33
-
34
- # default paths on site. These are the same as the defaults set up by the generators
35
- request_token_path: "/oauth/request_token",
36
- authenticate_path: "/oauth/authenticate",
37
- authorize_path: "/oauth/authorize",
38
- access_token_path: "/oauth/access_token",
39
-
40
- proxy: nil,
41
- # How do we send the oauth values to the server see
42
- # https://oauth.net/core/1.0/#consumer_req_param for more info
43
- #
44
- # Possible values:
45
- #
46
- # :header - via the Authorize header (Default) ( option 1. in spec)
47
- # :body - url form encoded in body of POST request ( option 2. in spec)
48
- # :query_string - via the query part of the url ( option 3. in spec)
49
- scheme: :header,
50
-
51
- # Default http method used for OAuth Token Requests (defaults to :post)
52
- http_method: :post,
53
-
54
- # Add a custom ca_file for consumer
55
- # :ca_file => '/etc/certs.pem'
56
-
57
- # Possible values:
58
- #
59
- # nil, false - no debug output
60
- # true - uses $stdout
61
- # some_value - uses some_value
62
- debug_output: nil,
63
-
64
- oauth_version: "1.0"
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,9 +105,8 @@ module OAuth
94
105
  @secret = consumer_secret
95
106
 
96
107
  # ensure that keys are symbols
97
- @options = @@default_options.merge(options.each_with_object({}) do |(key, value), opts|
98
- opts[key.to_sym] = value
99
- end)
108
+ snaky_options = SnakyHash::SymbolKeyed.new(options)
109
+ @options = @@default_options.merge(snaky_options)
100
110
  end
101
111
 
102
112
  # The default http method
@@ -105,15 +115,13 @@ module OAuth
105
115
  end
106
116
 
107
117
  def debug_output
108
- @debug_output ||= begin
109
- case @options[:debug_output]
110
- when nil, false
111
- when true
112
- $stdout
113
- else
114
- @options[:debug_output]
115
- end
116
- 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
117
125
  end
118
126
 
119
127
  # The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new
@@ -132,7 +140,8 @@ module OAuth
132
140
  end
133
141
 
134
142
  def get_access_token(request_token, request_options = {}, *arguments, &block)
135
- response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token, request_options, *arguments, &block)
143
+ response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token,
144
+ request_options, *arguments, &block)
136
145
  OAuth::AccessToken.from_hash(self, response)
137
146
  end
138
147
 
@@ -153,9 +162,11 @@ module OAuth
153
162
  def get_request_token(request_options = {}, *arguments, &block)
154
163
  # if oauth_callback wasn't provided, it is assumed that oauth_verifiers
155
164
  # will be exchanged out of band
156
- request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND unless request_options[:exclude_callback]
165
+ unless request_options[:exclude_callback]
166
+ request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND
167
+ end
157
168
 
158
- response = if block_given?
169
+ response = if block
159
170
  token_request(
160
171
  http_method,
161
172
  (request_token_url? ? request_token_url : request_token_path),
@@ -165,7 +176,8 @@ module OAuth
165
176
  &block
166
177
  )
167
178
  else
168
- token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil, request_options, *arguments)
179
+ token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil,
180
+ request_options, *arguments)
169
181
  end
170
182
  OAuth::RequestToken.from_hash(self, response)
171
183
  end
@@ -181,7 +193,7 @@ module OAuth
181
193
  # @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
182
194
  #
183
195
  def request(http_method, path, token = nil, request_options = {}, *arguments)
184
- if path !~ /^\//
196
+ unless %r{^/}.match?(path)
185
197
  @http = create_http(path)
186
198
  _uri = URI.parse(path)
187
199
  path = "#{_uri.path}#{_uri.query ? "?#{_uri.query}" : ""}"
@@ -190,13 +202,14 @@ module OAuth
190
202
  # override the request with your own, this is useful for file uploads which Net::HTTP does not do
191
203
  req = create_signed_request(http_method, path, token, request_options, *arguments)
192
204
  return nil if block_given? && (yield(req) == :done)
205
+
193
206
  rsp = http.request(req)
194
207
  # check for an error reported by the Problem Reporting extension
195
208
  # (https://wiki.oauth.net/ProblemReporting)
196
209
  # note: a 200 may actually be an error; check for an oauth_problem key to be sure
197
210
  if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
198
- (h = headers.select { |hdr| hdr =~ /^OAuth / }).any? &&
199
- h.first =~ /oauth_problem/
211
+ (h = headers.grep(/^OAuth /)).any? &&
212
+ h.first.include?("oauth_problem")
200
213
 
201
214
  # puts "Header: #{h.first}"
202
215
 
@@ -276,6 +289,7 @@ module OAuth
276
289
 
277
290
  def request_endpoint
278
291
  return nil if @options[:request_endpoint].nil?
292
+
279
293
  @options[:request_endpoint].to_s
280
294
  end
281
295
 
@@ -301,7 +315,7 @@ module OAuth
301
315
 
302
316
  # TODO: this is ugly, rewrite
303
317
  def request_token_url
304
- @options[:request_token_url] || site + request_token_path
318
+ @options[:request_token_url] || (site + request_token_path)
305
319
  end
306
320
 
307
321
  def request_token_url?
@@ -309,7 +323,7 @@ module OAuth
309
323
  end
310
324
 
311
325
  def authenticate_url
312
- @options[:authenticate_url] || site + authenticate_path
326
+ @options[:authenticate_url] || (site + authenticate_path)
313
327
  end
314
328
 
315
329
  def authenticate_url?
@@ -317,7 +331,7 @@ module OAuth
317
331
  end
318
332
 
319
333
  def authorize_url
320
- @options[:authorize_url] || site + authorize_path
334
+ @options[:authorize_url] || (site + authorize_path)
321
335
  end
322
336
 
323
337
  def authorize_url?
@@ -325,7 +339,7 @@ module OAuth
325
339
  end
326
340
 
327
341
  def access_token_url
328
- @options[:access_token_url] || site + access_token_path
342
+ @options[:access_token_url] || (site + access_token_path)
329
343
  end
330
344
 
331
345
  def access_token_url?
@@ -342,7 +356,7 @@ module OAuth
342
356
  def create_http(_url = nil)
343
357
  _url = request_endpoint unless request_endpoint.nil?
344
358
 
345
- our_uri = if _url.nil? || _url[0] =~ /^\//
359
+ our_uri = if _url.nil? || _url[0] =~ %r{^/}
346
360
  URI.parse(site)
347
361
  else
348
362
  your_uri = URI.parse(_url)
@@ -359,7 +373,8 @@ module OAuth
359
373
  http_object = Net::HTTP.new(our_uri.host, our_uri.port)
360
374
  else
361
375
  proxy_uri = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
362
- http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
376
+ http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user,
377
+ proxy_uri.password)
363
378
  end
364
379
 
365
380
  http_object.use_ssl = (our_uri.scheme == "https")
@@ -374,10 +389,14 @@ module OAuth
374
389
  end
375
390
 
376
391
  http_object.read_timeout = http_object.open_timeout = @options[:timeout] || 60
377
- http_object.open_timeout = @options[:open_timeout] if @options[:open_timeout]
392
+ if @options[:open_timeout]
393
+ http_object.open_timeout = @options[:open_timeout]
394
+ end
378
395
  http_object.ssl_version = @options[:ssl_version] if @options[:ssl_version]
379
- http_object.cert = @options[:ssl_client_cert] if @options[:ssl_client_cert]
380
- http_object.key = @options[:ssl_client_key] if @options[:ssl_client_key]
396
+ if @options[:ssl_client_cert]
397
+ http_object.cert = @options[:ssl_client_cert]
398
+ end
399
+ http_object.key = @options[:ssl_client_key] if @options[:ssl_client_key]
381
400
  http_object.set_debug_output(debug_output) if debug_output
382
401
 
383
402
  http_object
@@ -392,8 +411,10 @@ module OAuth
392
411
  # if the base site contains a path, add it now
393
412
  # only add if the site host matches the current http object's host
394
413
  # (in case we've specified a full url for token requests)
395
- uri = URI.parse(site)
396
- path = uri.path + path if uri.path && uri.path != "/" && uri.host == http.address
414
+ uri = URI.parse(site)
415
+ if uri.path && uri.path != "/" && uri.host == http.address
416
+ path = uri.path + path
417
+ end
397
418
 
398
419
  headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
399
420
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  class Error < StandardError
3
5
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  class Problem < OAuth::Unauthorized
3
5
  attr_reader :problem, :params
6
+
4
7
  def initialize(problem, request = nil, params = {})
5
8
  super(request)
6
9
  @problem = problem
@@ -1,7 +1,11 @@
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
 
data/lib/oauth/errors.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "oauth/errors/error"
2
4
  require "oauth/errors/unauthorized"
3
5
  require "oauth/errors/problem"
data/lib/oauth/helper.rb CHANGED
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
1
4
  require "openssl"
2
5
  require "base64"
3
6
 
4
7
  module OAuth
5
8
  module Helper
6
- extend self
9
+ module_function
7
10
 
8
11
  # Escape +value+ by URL encoding all non-reserved character.
9
12
  #
@@ -30,7 +33,7 @@ module OAuth
30
33
 
31
34
  alias generate_nonce generate_key
32
35
 
33
- def generate_timestamp #:nodoc:
36
+ def generate_timestamp # :nodoc:
34
37
  Time.now.to_i.to_s
35
38
  end
36
39
 
@@ -43,7 +46,8 @@ 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
- if values.is_a?(Array)
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
@@ -54,7 +58,7 @@ module OAuth
54
58
  [escape(k), escape(v)].join("=")
55
59
  end
56
60
  end
57
- elsif values.is_a?(Hash)
61
+ when Hash
58
62
  normalize_nested_query(values, k)
59
63
  else
60
64
  [escape(k), escape(values)].join("=")
@@ -99,7 +103,7 @@ module OAuth
99
103
  # strip and unescape
100
104
  val = unescape(v.strip)
101
105
  # strip quotes
102
- val.sub(/^\"(.*)\"$/, '\1')
106
+ val.sub(/^"(.*)"$/, '\1')
103
107
  end
104
108
 
105
109
  # convert into a Hash
data/lib/oauth/oauth.rb CHANGED
@@ -1,7 +1,9 @@
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
- OUT_OF_BAND = "oob".freeze
6
+ OUT_OF_BAND = "oob"
5
7
 
6
8
  # required parameters, per sections 6.1.1, 6.3.1, and 7
7
9
  PARAMETERS = %w[oauth_callback oauth_consumer_key oauth_token
@@ -9,5 +11,5 @@ module OAuth
9
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_controller"
2
4
  require "action_controller/test_process"
3
5
 
@@ -79,15 +79,15 @@ module OAuth
79
79
  end
80
80
 
81
81
  def parameters_for_signature
82
- parameters.reject { |k, _v| signature_and_unsigned_parameters.include?(k) }
82
+ parameters.select { |k, _v| !signature_and_unsigned_parameters.include?(k) }
83
83
  end
84
84
 
85
85
  def oauth_parameters
86
- parameters.select { |k, _v| OAuth::PARAMETERS.include?(k) }.reject { |_k, v| v == "" }
86
+ parameters.select { |k, v| OAuth::PARAMETERS.include?(k) && !v.nil? && v != "" }
87
87
  end
88
88
 
89
89
  def non_oauth_parameters
90
- parameters.reject { |k, _v| OAuth::PARAMETERS.include?(k) }
90
+ parameters.select { |k, _v| !OAuth::PARAMETERS.include?(k) }
91
91
  end
92
92
 
93
93
  def signature_and_unsigned_parameters
@@ -127,7 +127,7 @@ module OAuth
127
127
  end
128
128
 
129
129
  # URI, including OAuth parameters
130
- def signed_uri(with_oauth = true)
130
+ def signed_uri(with_oauth: true)
131
131
  if signed?
132
132
  params = if with_oauth
133
133
  parameters
@@ -32,7 +32,7 @@ module OAuth
32
32
 
33
33
  def normalized_uri
34
34
  super
35
- rescue
35
+ rescue StandardError
36
36
  # if this is a non-standard URI, it may not parse properly
37
37
  # in that case, assume that it's already been normalized
38
38
  uri
@@ -38,13 +38,11 @@ module OAuth
38
38
  request_params = CGI.parse(query_string)
39
39
  # request_params.each{|k,v| request_params[k] = [nil] if v == []}
40
40
 
41
- if options[:parameters]
42
- options[:parameters].each do |k, v|
43
- if request_params.key?(k) && v
44
- request_params[k] << v
45
- else
46
- request_params[k] = [v]
47
- end
41
+ options[:parameters]&.each do |k, v|
42
+ if request_params.key?(k) && v
43
+ request_params[k] << v
44
+ else
45
+ request_params[k] = [v]
48
46
  end
49
47
  end
50
48
  request_params
@@ -71,7 +69,9 @@ module OAuth
71
69
  end
72
70
 
73
71
  def auth_header_params
74
- return nil unless request["Authorization"] && request["Authorization"][0, 5] == "OAuth"
72
+ unless request["Authorization"] && request["Authorization"][0, 5] == "OAuth"
73
+ return nil
74
+ end
75
75
 
76
76
  request["Authorization"]
77
77
  end
@@ -38,7 +38,8 @@ module OAuth
38
38
 
39
39
  def post_parameters
40
40
  # Post params are only used if posting form data
41
- if method == "POST" || method == "PUT"
41
+ is_form_data = request.payload && request.payload.headers["Content-Type"] == "application/x-www-form-urlencoded"
42
+ if is_form_data && (method == "POST" || method == "PUT")
42
43
  OAuth::Helper.stringify_keys(query_string_to_hash(request.payload.to_s) || {})
43
44
  else
44
45
  {}
@@ -51,9 +52,9 @@ module OAuth
51
52
  query.split("&").inject({}) do |result, q|
52
53
  k, v = q.split("=")
53
54
  if !v.nil?
54
- result.merge(k => v)
55
+ result.merge({ k => v })
55
56
  elsif !result.key?(k)
56
- result.merge(k => true)
57
+ result.merge({ k => true })
57
58
  else
58
59
  result
59
60
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  module RequestProxy
3
- def self.available_proxies #:nodoc:
5
+ def self.available_proxies # :nodoc:
4
6
  @available_proxies ||= {}
5
7
  end
6
8
 
@@ -16,6 +18,7 @@ module OAuth
16
18
  end
17
19
 
18
20
  raise UnknownRequestType, request.class.to_s unless klass
21
+
19
22
  klass.new(request, options)
20
23
  end
21
24
 
data/lib/oauth/server.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "oauth/helper"
2
4
  require "oauth/consumer"
3
5
 
@@ -31,10 +33,12 @@ module OAuth
31
33
  def create_consumer
32
34
  creds = generate_credentials
33
35
  Consumer.new(creds[0], creds[1],
34
- site: base_url,
35
- request_token_path: request_token_path,
36
- authorize_path: authorize_path,
37
- access_token_path: access_token_path)
36
+ {
37
+ site: base_url,
38
+ request_token_path: request_token_path,
39
+ authorize_path: authorize_path,
40
+ access_token_path: access_token_path
41
+ })
38
42
  end
39
43
 
40
44
  def request_token_path