oauth 0.5.6 → 1.1.5
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
- checksums.yaml.gz.sig +4 -0
- data/CHANGELOG.md +848 -0
- data/CITATION.cff +20 -0
- data/CODE_OF_CONDUCT.md +134 -0
- data/CONTRIBUTING.md +218 -0
- data/FUNDING.md +77 -0
- data/LICENSE.txt +22 -0
- data/README.md +662 -0
- data/REEK +2 -0
- data/RUBOCOP.md +71 -0
- data/SECURITY.md +24 -0
- data/lib/oauth/auth_sanitizer.rb +36 -0
- data/lib/oauth/client/action_controller_request.rb +33 -22
- data/lib/oauth/client/em_http.rb +110 -103
- data/lib/oauth/client/helper.rb +87 -82
- data/lib/oauth/client/net_http.rb +140 -107
- data/lib/oauth/client.rb +2 -0
- data/lib/oauth/consumer.rb +222 -141
- data/lib/oauth/errors/error.rb +2 -0
- data/lib/oauth/errors/problem.rb +4 -1
- data/lib/oauth/errors/unauthorized.rb +7 -1
- data/lib/oauth/errors.rb +5 -3
- data/lib/oauth/helper.rb +48 -18
- data/lib/oauth/oauth.rb +31 -7
- data/lib/oauth/oauth_test_helper.rb +6 -4
- data/lib/oauth/optional.rb +20 -0
- data/lib/oauth/request_proxy/action_controller_request.rb +53 -71
- data/lib/oauth/request_proxy/action_dispatch_request.rb +42 -4
- data/lib/oauth/request_proxy/base.rb +146 -131
- data/lib/oauth/request_proxy/curb_request.rb +49 -43
- data/lib/oauth/request_proxy/em_http_request.rb +60 -49
- data/lib/oauth/request_proxy/jabber_request.rb +19 -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 +31 -31
- data/lib/oauth/request_proxy/rest_client_request.rb +55 -50
- data/lib/oauth/request_proxy/typhoeus_request.rb +51 -45
- data/lib/oauth/request_proxy.rb +21 -14
- data/lib/oauth/server.rb +18 -12
- data/lib/oauth/signature/base.rb +88 -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 +53 -38
- data/lib/oauth/signature.rb +41 -34
- data/lib/oauth/token.rb +7 -5
- data/lib/oauth/tokens/access_token.rb +6 -4
- data/lib/oauth/tokens/consumer_token.rb +11 -7
- data/lib/oauth/tokens/request_token.rb +17 -10
- data/lib/oauth/tokens/server_token.rb +2 -1
- data/lib/oauth/tokens/token.rb +15 -1
- data/lib/oauth/version.rb +6 -1
- data/lib/oauth.rb +18 -9
- data/sig/oauth/consumer.rbs +9 -0
- data/sig/oauth/signature/base.rbs +12 -0
- data/sig/oauth/tokens/token.rbs +8 -0
- data.tar.gz.sig +3 -0
- metadata +301 -82
- metadata.gz.sig +2 -0
- data/LICENSE +0 -20
- data/README.rdoc +0 -88
- data/TODO +0 -32
- 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/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
|
#
|
|
@@ -15,22 +18,44 @@ module OAuth
|
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
def _escape(string)
|
|
18
|
-
|
|
21
|
+
# Percent-encode per RFC 3986 (unreserved: A-Z a-z 0-9 - . _ ~)
|
|
22
|
+
# Encode by byte to ensure stable behavior across Ruby versions and encodings.
|
|
23
|
+
bytes = string.to_s.b.bytes
|
|
24
|
+
bytes.map do |b|
|
|
25
|
+
ch = b.chr
|
|
26
|
+
if ch =~ OAuth::RESERVED_CHARACTERS
|
|
27
|
+
"%%%02X" % b
|
|
28
|
+
else
|
|
29
|
+
ch
|
|
30
|
+
end
|
|
31
|
+
end.join
|
|
19
32
|
end
|
|
20
33
|
|
|
21
34
|
def unescape(value)
|
|
22
|
-
|
|
35
|
+
# Do NOT treat "+" as space; OAuth treats '+' as a literal plus unless percent-encoded.
|
|
36
|
+
str = value.to_s.gsub("+", "%2B")
|
|
37
|
+
# Decode %HH sequences; leave malformed sequences intact.
|
|
38
|
+
decoded = str.gsub(/%([0-9A-Fa-f]{2})/) { Regexp.last_match(1).to_i(16).chr }
|
|
39
|
+
# Prefer UTF-8 when the decoded bytes form valid UTF-8; otherwise, return as binary.
|
|
40
|
+
begin
|
|
41
|
+
utf8 = decoded.dup
|
|
42
|
+
utf8.force_encoding(Encoding::UTF_8)
|
|
43
|
+
decoded = utf8 if utf8.valid_encoding?
|
|
44
|
+
rescue NameError
|
|
45
|
+
# Older Rubies without Encoding constants: keep original encoding.
|
|
46
|
+
end
|
|
47
|
+
decoded
|
|
23
48
|
end
|
|
24
49
|
|
|
25
50
|
# Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
|
|
26
51
|
# characters removed.
|
|
27
|
-
def generate_key(size=32)
|
|
28
|
-
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,
|
|
52
|
+
def generate_key(size = 32)
|
|
53
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, "")
|
|
29
54
|
end
|
|
30
55
|
|
|
31
56
|
alias_method :generate_nonce, :generate_key
|
|
32
57
|
|
|
33
|
-
def generate_timestamp
|
|
58
|
+
def generate_timestamp # :nodoc:
|
|
34
59
|
Time.now.to_i.to_s
|
|
35
60
|
end
|
|
36
61
|
|
|
@@ -43,22 +68,27 @@ module OAuth
|
|
|
43
68
|
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
|
44
69
|
def normalize(params)
|
|
45
70
|
params.sort.map do |k, values|
|
|
46
|
-
|
|
71
|
+
case values
|
|
72
|
+
when Array
|
|
47
73
|
# make sure the array has an element so we don't lose the key
|
|
48
74
|
values << nil if values.empty?
|
|
49
75
|
# multiple values were provided for a single key
|
|
50
|
-
values.
|
|
51
|
-
|
|
76
|
+
if values[0].is_a?(Hash)
|
|
77
|
+
normalize_nested_query(values, k)
|
|
78
|
+
else
|
|
79
|
+
values.sort.collect do |v|
|
|
80
|
+
[escape(k), escape(v)].join("=")
|
|
81
|
+
end
|
|
52
82
|
end
|
|
53
|
-
|
|
83
|
+
when Hash
|
|
54
84
|
normalize_nested_query(values, k)
|
|
55
85
|
else
|
|
56
|
-
[escape(k),escape(values)]
|
|
86
|
+
[escape(k), escape(values)].join("=")
|
|
57
87
|
end
|
|
58
88
|
end * "&"
|
|
59
89
|
end
|
|
60
90
|
|
|
61
|
-
#Returns a string representation of the Hash like in URL query string
|
|
91
|
+
# Returns a string representation of the Hash like in URL query string
|
|
62
92
|
# build_nested_query({:level_1 => {:level_2 => ['value_1','value_2']}}, 'prefix'))
|
|
63
93
|
# #=> ["prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_1", "prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_2"]
|
|
64
94
|
def normalize_nested_query(value, prefix = nil)
|
|
@@ -72,7 +102,7 @@ module OAuth
|
|
|
72
102
|
normalize_nested_query(v, prefix ? "#{prefix}[#{k}]" : k)
|
|
73
103
|
end.flatten.sort
|
|
74
104
|
else
|
|
75
|
-
[escape(prefix), escape(value)]
|
|
105
|
+
[escape(prefix), escape(value)].join("=")
|
|
76
106
|
end
|
|
77
107
|
end
|
|
78
108
|
|
|
@@ -86,16 +116,16 @@ module OAuth
|
|
|
86
116
|
#
|
|
87
117
|
def parse_header(header)
|
|
88
118
|
# decompose
|
|
89
|
-
params = header[6,header.length].split(/[,=&]/)
|
|
119
|
+
params = header[6, header.length].split(/[,=&]/)
|
|
90
120
|
|
|
91
121
|
# odd number of arguments - must be a malformed header.
|
|
92
|
-
raise OAuth::Problem
|
|
122
|
+
raise OAuth::Problem, "Invalid authorization header" if params.size.odd?
|
|
93
123
|
|
|
94
124
|
params.map! do |v|
|
|
95
125
|
# strip and unescape
|
|
96
126
|
val = unescape(v.strip)
|
|
97
127
|
# strip quotes
|
|
98
|
-
val.sub(
|
|
128
|
+
val.sub(/^"(.*)"$/, '\1')
|
|
99
129
|
end
|
|
100
130
|
|
|
101
131
|
# convert into a Hash
|
data/lib/oauth/oauth.rb
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module OAuth
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
+
# Out-Of-Band callback token value.
|
|
5
|
+
# OAuth 1.0 and 1.0a both support out-of-band flows, where callbacks cannot be used.
|
|
6
|
+
# See RFC 5849 (OAuth 1.0), Section 6.1.1: Obtaining an Unauthorized Request Token
|
|
7
|
+
# and the 1.0a errata. Providers treating "oob" as the callback URL indicate that
|
|
8
|
+
# the verifier (for 1.0a) will be communicated out of band to the Consumer.
|
|
4
9
|
OUT_OF_BAND = "oob"
|
|
5
10
|
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
# OAuth parameter keys this library recognizes when normalizing/signing requests.
|
|
12
|
+
# Notes on 1.0 vs 1.0a:
|
|
13
|
+
# - oauth_verifier: Introduced by OAuth 1.0a. Returned to the Consumer after user
|
|
14
|
+
# authorization and required when exchanging a Request Token for an Access Token
|
|
15
|
+
# (Section 6.3.1 in RFC 5849 / 1.0a change).
|
|
16
|
+
# - oauth_callback: Present in 1.0; 1.0a clarified that the Consumer MUST send it when
|
|
17
|
+
# obtaining a Request Token (or use "oob") and that the Service Provider MUST return
|
|
18
|
+
# oauth_callback_confirmed=true with the Request Token response to prevent session
|
|
19
|
+
# fixation attacks. Note that oauth_callback_confirmed is a response parameter, not
|
|
20
|
+
# a request signing parameter, and thus is not listed here.
|
|
21
|
+
# Other keys are common to both 1.0 and 1.0a.
|
|
22
|
+
PARAMETERS = %w[
|
|
23
|
+
oauth_callback
|
|
24
|
+
oauth_consumer_key
|
|
25
|
+
oauth_token
|
|
26
|
+
oauth_signature_method
|
|
27
|
+
oauth_timestamp
|
|
28
|
+
oauth_nonce
|
|
29
|
+
oauth_verifier
|
|
30
|
+
oauth_version
|
|
31
|
+
oauth_signature
|
|
32
|
+
oauth_body_hash
|
|
33
|
+
].freeze
|
|
10
34
|
|
|
11
35
|
# reserved character regexp, per section 5.1
|
|
12
|
-
RESERVED_CHARACTERS = /[^a-zA-Z0-9
|
|
36
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-._~]/.freeze
|
|
13
37
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_controller"
|
|
4
|
+
require "action_controller/test_process"
|
|
3
5
|
|
|
4
6
|
module OAuth
|
|
5
7
|
module OAuthTestHelper
|
|
@@ -8,7 +10,7 @@ module OAuth
|
|
|
8
10
|
incoming.request_uri = request.path
|
|
9
11
|
incoming.host = request.uri.host
|
|
10
12
|
incoming.env["SERVER_PORT"] = request.uri.port
|
|
11
|
-
incoming.env[
|
|
13
|
+
incoming.env["REQUEST_METHOD"] = request.http_method
|
|
12
14
|
incoming
|
|
13
15
|
end
|
|
14
16
|
|
|
@@ -18,7 +20,7 @@ module OAuth
|
|
|
18
20
|
incoming.host = request.uri.host
|
|
19
21
|
incoming.env["HTTP_AUTHORIZATION"] = request.to_auth_string
|
|
20
22
|
incoming.env["SERVER_PORT"] = request.uri.port
|
|
21
|
-
incoming.env[
|
|
23
|
+
incoming.env["REQUEST_METHOD"] = request.http_method
|
|
22
24
|
incoming
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OAuth
|
|
4
|
+
# Helpers for optional, lazily loaded integrations.
|
|
5
|
+
module Optional
|
|
6
|
+
class << self
|
|
7
|
+
# Try to load EventMachine HTTP client support provided by em-http-request.
|
|
8
|
+
#
|
|
9
|
+
# Returns true if available, false if the dependency is not installed.
|
|
10
|
+
# Never raises LoadError.
|
|
11
|
+
def em_http_available?
|
|
12
|
+
# em-http-request provides "em-http" entrypoint
|
|
13
|
+
require "em-http"
|
|
14
|
+
true
|
|
15
|
+
rescue LoadError
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,90 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
require "active_support/version"
|
|
3
|
-
require 'action_controller'
|
|
4
|
-
require 'uri'
|
|
1
|
+
# frozen_string_literal: true
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
require 'action_controller/request'
|
|
10
|
-
unless ActionController::Request::HTTP_METHODS.include?("patch")
|
|
11
|
-
ActionController::Request::HTTP_METHODS << "patch"
|
|
12
|
-
ActionController::Request::HTTP_METHOD_LOOKUP["PATCH"] = :patch
|
|
13
|
-
ActionController::Request::HTTP_METHOD_LOOKUP["patch"] = :patch
|
|
14
|
-
end
|
|
3
|
+
require "active_support"
|
|
4
|
+
require "action_controller"
|
|
5
|
+
require "uri"
|
|
15
6
|
|
|
16
|
-
|
|
17
|
-
Gem::Version.new(ActiveSupport::VERSION::STRING) < Gem::Version.new("4")
|
|
18
|
-
then # rails 3.x
|
|
19
|
-
require 'action_dispatch/http/request'
|
|
20
|
-
unless ActionDispatch::Request::HTTP_METHODS.include?("patch")
|
|
21
|
-
ActionDispatch::Request::HTTP_METHODS << "patch"
|
|
22
|
-
ActionDispatch::Request::HTTP_METHOD_LOOKUP["PATCH"] = :patch
|
|
23
|
-
ActionDispatch::Request::HTTP_METHOD_LOOKUP["patch"] = :patch
|
|
24
|
-
end
|
|
7
|
+
require "action_dispatch/http/request"
|
|
25
8
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
9
|
+
module OAuth
|
|
10
|
+
module RequestProxy
|
|
11
|
+
class ActionControllerRequest < OAuth::RequestProxy::Base
|
|
12
|
+
proxies(::ActionDispatch::Request)
|
|
29
13
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def method
|
|
35
|
-
request.method.to_s.upcase
|
|
36
|
-
end
|
|
14
|
+
def method
|
|
15
|
+
request.method.to_s.upcase
|
|
16
|
+
end
|
|
37
17
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
18
|
+
def uri
|
|
19
|
+
options[:uri] || request.url
|
|
20
|
+
end
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
22
|
+
def parameters
|
|
23
|
+
if options[:clobber_request]
|
|
24
|
+
options[:parameters] || {}
|
|
25
|
+
else
|
|
26
|
+
# Rails proxies should expose array-style values for params to align with
|
|
27
|
+
# historical oauth gem behavior / specs. Header params remain scalars.
|
|
28
|
+
rq = wrap_values(request_params)
|
|
29
|
+
qq = wrap_values(query_params)
|
|
30
|
+
params = rq.merge(qq).merge(header_params)
|
|
31
|
+
params.stringify_keys! if params.respond_to?(:stringify_keys!)
|
|
32
|
+
params.merge(options[:parameters] || {})
|
|
33
|
+
end
|
|
49
34
|
end
|
|
50
|
-
end
|
|
51
35
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
36
|
+
# Override from OAuth::RequestProxy::Base to avoid round-trip
|
|
37
|
+
# conversion to Hash or Array and thus preserve the original
|
|
38
|
+
# parameter names
|
|
39
|
+
def parameters_for_signature
|
|
40
|
+
params = []
|
|
41
|
+
params << options[:parameters].to_query if options[:parameters]
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
unless options[:clobber_request]
|
|
44
|
+
params << header_params.to_query
|
|
45
|
+
params << request.query_string unless query_string_blank?
|
|
62
46
|
|
|
63
|
-
|
|
64
|
-
params << request.raw_post
|
|
47
|
+
params << request.raw_post if raw_post_signature?
|
|
65
48
|
end
|
|
66
|
-
end
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
50
|
+
params
|
|
51
|
+
.join("&").split("&")
|
|
52
|
+
.reject { |s| s.match(/\A\s*\z/) }
|
|
53
|
+
.map { |p| p.split("=").map { |esc| CGI.unescape(esc) } }
|
|
54
|
+
.reject { |kv| kv[0] == "oauth_signature" }
|
|
55
|
+
end
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
57
|
+
def raw_post_signature?
|
|
58
|
+
(request.post? || request.put?) && request.content_type.to_s.downcase.start_with?("application/x-www-form-urlencoded")
|
|
59
|
+
end
|
|
78
60
|
|
|
79
|
-
|
|
61
|
+
protected
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
def query_params
|
|
64
|
+
request.query_parameters
|
|
65
|
+
end
|
|
84
66
|
|
|
85
|
-
|
|
86
|
-
|
|
67
|
+
def request_params
|
|
68
|
+
request.request_parameters
|
|
69
|
+
end
|
|
87
70
|
end
|
|
88
|
-
|
|
89
71
|
end
|
|
90
72
|
end
|
|
@@ -1,7 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
require "oauth/request_proxy/rack_request"
|
|
4
|
+
|
|
5
|
+
module OAuth
|
|
6
|
+
module RequestProxy
|
|
7
|
+
class ActionDispatchRequest < OAuth::RequestProxy::RackRequest
|
|
8
|
+
proxies ::ActionDispatch::Request
|
|
9
|
+
|
|
10
|
+
# Prefer the explicitly provided URI, which carries scheme/host info
|
|
11
|
+
# when ActionDispatch env may be minimal in tests.
|
|
12
|
+
def uri
|
|
13
|
+
options[:uri] || super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Rails' ActionDispatch proxy should expose array-style parameters
|
|
17
|
+
# for request/query params to align with legacy oauth gem expectations.
|
|
18
|
+
def parameters
|
|
19
|
+
if options[:clobber_request]
|
|
20
|
+
options[:parameters] || {}
|
|
21
|
+
else
|
|
22
|
+
rq = wrap_values(request_params)
|
|
23
|
+
qq = wrap_values(query_params)
|
|
24
|
+
params = rq.merge(qq).merge(header_params)
|
|
25
|
+
params.merge(options[:parameters] || {})
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
def query_params
|
|
32
|
+
# ActionDispatch::Request responds to GET
|
|
33
|
+
request.GET
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def request_params
|
|
37
|
+
if request.content_type && request.content_type.to_s.downcase.start_with?("application/x-www-form-urlencoded")
|
|
38
|
+
request.POST
|
|
39
|
+
else
|
|
40
|
+
{}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
6
44
|
end
|
|
7
45
|
end
|