oauth 0.5.10 → 0.6.0

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 +17 -2
  3. data/README.md +60 -55
  4. data/SECURITY.md +7 -9
  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 +50 -32
  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 +8 -2
  46. metadata +45 -30
@@ -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
@@ -1,97 +1,105 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "oauth/signature"
2
4
  require "oauth/helper"
3
5
  require "oauth/request_proxy/base"
4
6
  require "base64"
5
7
 
6
- module OAuth::Signature
7
- class Base
8
- include OAuth::Helper
8
+ module OAuth
9
+ module Signature
10
+ class Base
11
+ include OAuth::Helper
9
12
 
10
- attr_accessor :options
11
- attr_reader :token_secret, :consumer_secret, :request
13
+ attr_accessor :options
14
+ attr_reader :token_secret, :consumer_secret, :request
12
15
 
13
- def self.implements(signature_method = nil)
14
- return @implements if signature_method.nil?
15
- @implements = signature_method
16
- OAuth::Signature.available_methods[@implements] = self
17
- end
16
+ def self.implements(signature_method = nil)
17
+ return @implements if signature_method.nil?
18
18
 
19
- def initialize(request, options = {}, &block)
20
- raise TypeError unless request.is_a?(OAuth::RequestProxy::Base)
21
- @request = request
22
- @options = options
19
+ @implements = signature_method
20
+ OAuth::Signature.available_methods[@implements] = self
21
+ end
23
22
 
24
- ## consumer secret was determined beforehand
23
+ def initialize(request, options = {}, &block)
24
+ raise TypeError unless request.is_a?(OAuth::RequestProxy::Base)
25
25
 
26
- @consumer_secret = options[:consumer].secret if options[:consumer]
26
+ @request = request
27
+ @options = options
27
28
 
28
- # presence of :consumer_secret option will override any Consumer that's provided
29
- @consumer_secret = options[:consumer_secret] if options[:consumer_secret]
29
+ ## consumer secret was determined beforehand
30
30
 
31
- ## token secret was determined beforehand
31
+ @consumer_secret = options[:consumer].secret if options[:consumer]
32
32
 
33
- @token_secret = options[:token].secret if options[:token]
33
+ # presence of :consumer_secret option will override any Consumer that's provided
34
+ if options[:consumer_secret]
35
+ @consumer_secret = options[:consumer_secret]
36
+ end
34
37
 
35
- # presence of :token_secret option will override any Token that's provided
36
- @token_secret = options[:token_secret] if options[:token_secret]
38
+ ## token secret was determined beforehand
37
39
 
38
- # override secrets based on the values returned from the block (if any)
39
- if block_given?
40
- # consumer secret and token secret need to be looked up based on pieces of the request
41
- secrets = yield block.arity == 1 ? request : [token, consumer_key, nonce, request.timestamp]
42
- if secrets.is_a?(Array) && secrets.size == 2
43
- @token_secret = secrets[0]
44
- @consumer_secret = secrets[1]
40
+ @token_secret = options[:token].secret if options[:token]
41
+
42
+ # presence of :token_secret option will override any Token that's provided
43
+ @token_secret = options[:token_secret] if options[:token_secret]
44
+
45
+ # override secrets based on the values returned from the block (if any)
46
+ if block
47
+ # consumer secret and token secret need to be looked up based on pieces of the request
48
+ secrets = yield block.arity == 1 ? request : [token, consumer_key, nonce, request.timestamp]
49
+ if secrets.is_a?(Array) && secrets.size == 2
50
+ @token_secret = secrets[0]
51
+ @consumer_secret = secrets[1]
52
+ end
45
53
  end
46
54
  end
47
- end
48
55
 
49
- def signature
50
- Base64.encode64(digest).chomp.delete("\n")
51
- end
56
+ def signature
57
+ Base64.encode64(digest).chomp.delete("\n")
58
+ end
52
59
 
53
- def ==(cmp_signature)
54
- check = signature.bytesize ^ cmp_signature.bytesize
55
- signature.bytes.zip(cmp_signature.bytes) { |x, y| check |= x ^ y.to_i }
56
- check.zero?
57
- end
60
+ def ==(other)
61
+ check = signature.bytesize ^ other.bytesize
62
+ signature.bytes.zip(other.bytes) { |x, y| check |= x ^ y.to_i }
63
+ check.zero?
64
+ end
58
65
 
59
- def verify
60
- self == request.signature
61
- end
66
+ def verify
67
+ self == request.signature
68
+ end
62
69
 
63
- def signature_base_string
64
- request.signature_base_string
65
- end
70
+ def signature_base_string
71
+ request.signature_base_string
72
+ end
66
73
 
67
- def body_hash
68
- raise_instantiation_error
69
- end
74
+ def body_hash
75
+ raise_instantiation_error
76
+ end
70
77
 
71
- private
78
+ private
72
79
 
73
- def token
74
- request.token
75
- end
80
+ def token
81
+ request.token
82
+ end
76
83
 
77
- def consumer_key
78
- request.consumer_key
79
- end
84
+ def consumer_key
85
+ request.consumer_key
86
+ end
80
87
 
81
- def nonce
82
- request.nonce
83
- end
88
+ def nonce
89
+ request.nonce
90
+ end
84
91
 
85
- def secret
86
- "#{escape(consumer_secret)}&#{escape(token_secret)}"
87
- end
92
+ def secret
93
+ "#{escape(consumer_secret)}&#{escape(token_secret)}"
94
+ end
88
95
 
89
- def digest
90
- raise_instantiation_error
91
- end
96
+ def digest
97
+ raise_instantiation_error
98
+ end
92
99
 
93
- def raise_instantiation_error
94
- raise NotImplementedError, "Cannot instantiate #{self.class.name} class directly."
100
+ def raise_instantiation_error
101
+ raise NotImplementedError, "Cannot instantiate #{self.class.name} class directly."
102
+ end
95
103
  end
96
104
  end
97
105
  end
@@ -1,17 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "oauth/signature/base"
2
4
 
3
- module OAuth::Signature::HMAC
4
- class SHA1 < OAuth::Signature::Base
5
- implements "hmac-sha1"
5
+ module OAuth
6
+ module Signature
7
+ module HMAC
8
+ class SHA1 < OAuth::Signature::Base
9
+ implements "hmac-sha1"
6
10
 
7
- def body_hash
8
- Base64.encode64(OpenSSL::Digest::SHA1.digest(request.body || "")).chomp.delete("\n")
9
- end
11
+ def body_hash
12
+ Base64.encode64(OpenSSL::Digest.digest("SHA1", request.body || "")).chomp.delete("\n")
13
+ end
10
14
 
11
- private
15
+ private
12
16
 
13
- def digest
14
- OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha1"), secret, signature_base_string)
17
+ def digest
18
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha1"), secret, signature_base_string)
19
+ end
20
+ end
15
21
  end
16
22
  end
17
23
  end
@@ -1,17 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "oauth/signature/base"
2
4
 
3
- module OAuth::Signature::HMAC
4
- class SHA256 < OAuth::Signature::Base
5
- implements "hmac-sha256"
5
+ module OAuth
6
+ module Signature
7
+ module HMAC
8
+ class SHA256 < OAuth::Signature::Base
9
+ implements "hmac-sha256"
6
10
 
7
- def body_hash
8
- Base64.encode64(OpenSSL::Digest::SHA256.digest(request.body || "")).chomp.delete("\n")
9
- end
11
+ def body_hash
12
+ Base64.encode64(OpenSSL::Digest.digest("SHA256", request.body || "")).chomp.delete("\n")
13
+ end
10
14
 
11
- private
15
+ private
12
16
 
13
- def digest
14
- OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), secret, signature_base_string)
17
+ def digest
18
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), secret, signature_base_string)
19
+ end
20
+ end
15
21
  end
16
22
  end
17
23
  end
@@ -1,29 +1,27 @@
1
- require "oauth/signature/base"
1
+ # frozen_string_literal: true
2
2
 
3
- module OAuth::Signature
4
- class PLAINTEXT < Base
5
- implements "plaintext"
3
+ require "oauth/signature/base"
6
4
 
7
- def signature
8
- signature_base_string
9
- end
5
+ module OAuth
6
+ module Signature
7
+ class PLAINTEXT < Base
8
+ implements "plaintext"
10
9
 
11
- def ==(cmp_signature)
12
- signature.to_s == cmp_signature.to_s
13
- end
10
+ def signature
11
+ signature_base_string
12
+ end
14
13
 
15
- def signature_base_string
16
- secret
17
- end
18
-
19
- def body_hash
20
- nil
21
- end
14
+ def ==(other)
15
+ signature.to_s == other.to_s
16
+ end
22
17
 
23
- private
18
+ def signature_base_string
19
+ secret
20
+ end
24
21
 
25
- def secret
26
- super
22
+ def body_hash
23
+ nil
24
+ end
27
25
  end
28
26
  end
29
27
  end
@@ -1,50 +1,58 @@
1
- require "oauth/signature/base"
1
+ # frozen_string_literal: true
2
2
 
3
- module OAuth::Signature::RSA
4
- class SHA1 < OAuth::Signature::Base
5
- implements "rsa-sha1"
3
+ require "oauth/signature/base"
6
4
 
7
- def ==(cmp_signature)
8
- public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(cmp_signature.is_a?(Array) ? cmp_signature.first : cmp_signature), signature_base_string)
9
- end
5
+ module OAuth
6
+ module Signature
7
+ module RSA
8
+ class SHA1 < OAuth::Signature::Base
9
+ implements "rsa-sha1"
10
10
 
11
- def public_key
12
- if consumer_secret.is_a?(String)
13
- decode_public_key
14
- elsif consumer_secret.is_a?(OpenSSL::X509::Certificate)
15
- consumer_secret.public_key
16
- else
17
- consumer_secret
18
- end
19
- end
11
+ def ==(other)
12
+ public_key.verify(OpenSSL::Digest.new("SHA1"),
13
+ Base64.decode64(other.is_a?(Array) ? other.first : other), signature_base_string)
14
+ end
20
15
 
21
- def body_hash
22
- Base64.encode64(OpenSSL::Digest::SHA1.digest(request.body || "")).chomp.delete("\n")
23
- end
16
+ def public_key
17
+ case consumer_secret
18
+ when String
19
+ decode_public_key
20
+ when OpenSSL::X509::Certificate
21
+ consumer_secret.public_key
22
+ else
23
+ consumer_secret
24
+ end
25
+ end
24
26
 
25
- private
27
+ def body_hash
28
+ Base64.encode64(OpenSSL::Digest.digest("SHA1", request.body || "")).chomp.delete("\n")
29
+ end
26
30
 
27
- def decode_public_key
28
- case consumer_secret
29
- when /-----BEGIN CERTIFICATE-----/
30
- OpenSSL::X509::Certificate.new(consumer_secret).public_key
31
- else
32
- OpenSSL::PKey::RSA.new(consumer_secret)
33
- end
34
- end
31
+ private
35
32
 
36
- def digest
37
- private_key = OpenSSL::PKey::RSA.new(
38
- if options[:private_key_file]
39
- IO.read(options[:private_key_file])
40
- elsif options[:private_key]
41
- options[:private_key]
42
- else
43
- consumer_secret
33
+ def decode_public_key
34
+ case consumer_secret
35
+ when /-----BEGIN CERTIFICATE-----/
36
+ OpenSSL::X509::Certificate.new(consumer_secret).public_key
37
+ else
38
+ OpenSSL::PKey::RSA.new(consumer_secret)
39
+ end
44
40
  end
45
- )
46
41
 
47
- private_key.sign(OpenSSL::Digest::SHA1.new, signature_base_string)
42
+ def digest
43
+ private_key = OpenSSL::PKey::RSA.new(
44
+ if options[:private_key_file]
45
+ File.read(options[:private_key_file])
46
+ elsif options[:private_key]
47
+ options[:private_key]
48
+ else
49
+ consumer_secret
50
+ end
51
+ )
52
+
53
+ private_key.sign(OpenSSL::Digest.new("SHA1"), signature_base_string)
54
+ end
55
+ end
48
56
  end
49
57
  end
50
58
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  module Signature
3
5
  # Returns a list of available signature methods
@@ -15,6 +17,7 @@ module OAuth
15
17
  ((c = request.options[:consumer]) && c.options[:signature_method]) ||
16
18
  "").downcase]
17
19
  raise UnknownSignatureMethod, request.signature_method unless klass
20
+
18
21
  klass.new(request, options, &block)
19
22
  end
20
23
 
data/lib/oauth/token.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # this exists for backwards-compatibility
2
4
 
3
5
  require "oauth/tokens/token"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  # The Access Token is used for the actual "real" web service calls that you perform against the server
3
5
  class AccessToken < ConsumerToken
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OAuth
2
4
  # Superclass for tokens used by OAuth Clients
3
5
  class ConsumerToken < Token