oauthenticator 0.1.4 → 1.0.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/.simplecov +1 -0
- data/README.md +118 -35
- data/Rakefile.rb +11 -0
- data/lib/oauthenticator.rb +5 -6
- data/lib/oauthenticator/config_methods.rb +62 -21
- data/lib/oauthenticator/faraday_signer.rb +66 -0
- data/lib/oauthenticator/parse_authorization.rb +81 -0
- data/lib/oauthenticator/{middleware.rb → rack_authenticator.rb} +37 -9
- data/lib/oauthenticator/signable_request.rb +340 -0
- data/lib/oauthenticator/signed_request.rb +123 -112
- data/lib/oauthenticator/version.rb +3 -1
- data/test/config_methods_test.rb +10 -7
- data/test/faraday_signer_test.rb +65 -0
- data/test/helper.rb +15 -3
- data/test/parse_authorization_test.rb +86 -0
- data/test/{oauthenticator_test.rb → rack_authenticator_test.rb} +264 -136
- data/test/signable_request_test.rb +653 -0
- data/test/signed_request_test.rb +12 -0
- data/test/test_config_methods.rb +67 -0
- metadata +26 -11
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe 'OAuthenticator.parse_authorization' do
|
6
|
+
let :spec_authorization do
|
7
|
+
%q(OAuth realm="Example",
|
8
|
+
oauth_consumer_key="9djdj82h48djs9d2",
|
9
|
+
oauth_token="kkk9d7dh3k39sjv7",
|
10
|
+
oauth_signature_method="HMAC-SHA1",
|
11
|
+
oauth_timestamp="137131201",
|
12
|
+
oauth_nonce="7d8f3e4a",
|
13
|
+
oauth_signature="r6%2FTJjbCOr97%2F%2BUU0NsvSne7s5g%3D"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
let :spec_authorization_hash do
|
17
|
+
{
|
18
|
+
'realm' => "Example",
|
19
|
+
'oauth_consumer_key' => "9djdj82h48djs9d2",
|
20
|
+
'oauth_token' => "kkk9d7dh3k39sjv7",
|
21
|
+
'oauth_signature_method' => "HMAC-SHA1",
|
22
|
+
'oauth_timestamp' => "137131201",
|
23
|
+
'oauth_nonce' => "7d8f3e4a",
|
24
|
+
'oauth_signature' => "r6/TJjbCOr97/+UU0NsvSne7s5g=",
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'parses the example in the spec' do
|
29
|
+
assert_equal(spec_authorization_hash, OAuthenticator.parse_authorization(spec_authorization))
|
30
|
+
end
|
31
|
+
it 'parses the authorization SignableRequest calculates' do
|
32
|
+
request = OAuthenticator::SignableRequest.new({
|
33
|
+
:request_method => 'POST',
|
34
|
+
:uri => 'http://example.com/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b',
|
35
|
+
:media_type => 'application/x-www-form-urlencoded',
|
36
|
+
:body => 'c2&a3=2+q',
|
37
|
+
:authorization => spec_authorization_hash,
|
38
|
+
:consumer_secret => 'j49sk3j29djd',
|
39
|
+
:token_secret => 'dh893hdasih9',
|
40
|
+
})
|
41
|
+
assert_equal(spec_authorization_hash, OAuthenticator.parse_authorization(request.authorization))
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'optional linear white space' do
|
45
|
+
{ :space => %q(OAuth a="b", c="d", e="f"),
|
46
|
+
:spaces => %q(OAuth a="b", c="d", e="f" ),
|
47
|
+
:tab => %q(OAuth a="b", c="d", e="f"),
|
48
|
+
:tabs => %q(OAuth a="b", c="d", e="f"),
|
49
|
+
:tabs_and_spaces => %q(OAuth a="b", c="d", e="f"),
|
50
|
+
:none => %q(OAuth a="b",c="d",e="f"),
|
51
|
+
}.map do |name, authorization|
|
52
|
+
it "parses with #{name}" do
|
53
|
+
assert_equal({'a' => 'b', 'c' => 'd', 'e' => 'f'}, OAuthenticator.parse_authorization(authorization))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "handles commas inside quoted values" do
|
59
|
+
# note that this is invalid according to the spec; commas should be %-encoded, but this is accepted in
|
60
|
+
# the interests of robustness and consistency (other characters are accepted when they should really be
|
61
|
+
# escaped).
|
62
|
+
header_with_commas = 'OAuth oauth_consumer_key="a,bcd", oauth_nonce="o,LKtec51GQy", oauth_signature="efgh%2Cmnop"'
|
63
|
+
assert_equal({'oauth_consumer_key' => "a,bcd", 'oauth_nonce' => "o,LKtec51GQy", 'oauth_signature' => "efgh,mnop"},
|
64
|
+
OAuthenticator.parse_authorization(header_with_commas))
|
65
|
+
end
|
66
|
+
|
67
|
+
it "raises ParseError on input without a comma between key/value pairs" do
|
68
|
+
assert_raises(OAuthenticator::ParseError) do
|
69
|
+
OAuthenticator.parse_authorization(%q(OAuth oauth_consumer_key="k" oauth_nonce="n"))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises ParseError on malformed input" do
|
74
|
+
assert_raises(OAuthenticator::ParseError) { OAuthenticator.parse_authorization(%q(OAuth huh=/)) }
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises ParseError when the header does not start with 'OAuth '" do
|
78
|
+
assert_raises(OAuthenticator::ParseError) { OAuthenticator.parse_authorization(%q(FooAuth foo="baz")) }
|
79
|
+
end
|
80
|
+
|
81
|
+
it "raises DuplicatedParameter when the header contains duplicated parameters" do
|
82
|
+
assert_raises(OAuthenticator::DuplicatedParameters) do
|
83
|
+
OAuthenticator.parse_authorization(%q(OAuth oauth_nonce="a", oauth_nonce="b"))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -2,77 +2,13 @@
|
|
2
2
|
proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
|
3
3
|
require 'helper'
|
4
4
|
|
5
|
-
|
6
|
-
module OAuthenticatorTestConfigMethods
|
7
|
-
class << self
|
8
|
-
# a set of nonces
|
9
|
-
define_method(:nonces) { @nonces ||= Set.new }
|
10
|
-
# a Hash keyed by consumer keys with values of consumer secrets
|
11
|
-
define_method(:consumer_secrets) { @consumer_secrets ||= {} }
|
12
|
-
# a Hash keyed by access tokens with values of access token secrets
|
13
|
-
define_method(:access_token_secrets) { @access_token_secrets ||= {} }
|
14
|
-
# a Hash keyed by access tokens with values of consumer keys
|
15
|
-
define_method(:access_token_consumers) { @access_token_consumers ||= {} }
|
16
|
-
end
|
17
|
-
|
18
|
-
def nonce_used?
|
19
|
-
OAuthenticatorTestConfigMethods.nonces.include?(oauth_header_params[:nonce])
|
20
|
-
end
|
21
|
-
|
22
|
-
def use_nonce!
|
23
|
-
OAuthenticatorTestConfigMethods.nonces << oauth_header_params[:nonce]
|
24
|
-
end
|
25
|
-
|
26
|
-
def timestamp_valid_period
|
27
|
-
10
|
28
|
-
end
|
29
|
-
|
30
|
-
def allowed_signature_methods
|
31
|
-
%w(HMAC-SHA1 RSA-SHA1 PLAINTEXT)
|
32
|
-
end
|
33
|
-
|
34
|
-
def consumer_secret
|
35
|
-
OAuthenticatorTestConfigMethods.consumer_secrets[oauth_header_params[:consumer_key]]
|
36
|
-
end
|
37
|
-
|
38
|
-
def access_token_secret
|
39
|
-
OAuthenticatorTestConfigMethods.access_token_secrets[oauth_header_params[:token]]
|
40
|
-
end
|
41
|
-
|
42
|
-
def access_token_belongs_to_consumer?
|
43
|
-
OAuthenticatorTestConfigMethods.access_token_consumers[oauth_header_params[:token]] == oauth_header_params[:consumer_key]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe OAuthenticator::Middleware do
|
5
|
+
describe OAuthenticator::RackAuthenticator do
|
48
6
|
# act like a database cleaner
|
49
7
|
after do
|
50
|
-
[:nonces, :consumer_secrets, :
|
8
|
+
[:nonces, :consumer_secrets, :token_secrets, :token_consumers].each do |db|
|
51
9
|
OAuthenticatorTestConfigMethods.send(db).clear
|
52
10
|
end
|
53
|
-
|
54
|
-
Timecop.return
|
55
|
-
end
|
56
|
-
|
57
|
-
let(:simpleapp) { proc { |env| [200, {}, ['☺']] } }
|
58
|
-
let(:oapp) { OAuthenticator::Middleware.new(simpleapp, :config_methods => OAuthenticatorTestConfigMethods) }
|
59
|
-
|
60
|
-
let(:consumer) do
|
61
|
-
{:key => "test_client_app_key", :secret => "test_client_app_secret"}.tap do |consumer|
|
62
|
-
OAuthenticatorTestConfigMethods.consumer_secrets[consumer[:key]] = consumer[:secret]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
let(:consumer_key) { consumer[:key] }
|
66
|
-
let(:consumer_secret) { consumer[:secret] }
|
67
|
-
|
68
|
-
let(:access_token_hash) do
|
69
|
-
{:token => 'test_access_token', :secret => 'test_access_token_secret', :consumer_key => consumer_key}.tap do |hash|
|
70
|
-
OAuthenticatorTestConfigMethods.access_token_secrets[hash[:token]] = hash[:secret]
|
71
|
-
OAuthenticatorTestConfigMethods.access_token_consumers[hash[:token]] = hash[:consumer_key]
|
72
|
-
end
|
73
11
|
end
|
74
|
-
let(:access_token) { access_token_hash[:token] }
|
75
|
-
let(:access_token_secret) { access_token_hash[:secret] }
|
76
12
|
|
77
13
|
def assert_response(expected_status, expected_body, actual_status, actual_headers, actual_body)
|
78
14
|
actual_body_s = actual_body.to_enum.to_a.join
|
@@ -83,27 +19,31 @@ describe OAuthenticator::Middleware do
|
|
83
19
|
|
84
20
|
it 'makes a valid two-legged signed request (generated)' do
|
85
21
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
86
|
-
request.env['HTTP_AUTHORIZATION'] =
|
87
|
-
request.request_method,
|
88
|
-
request.url,
|
89
|
-
|
90
|
-
|
91
|
-
|
22
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
23
|
+
:request_method => request.request_method,
|
24
|
+
:uri => request.url,
|
25
|
+
:media_type => request.media_type,
|
26
|
+
:body => request.body,
|
27
|
+
:signature_method => 'HMAC-SHA1',
|
28
|
+
:consumer_key => consumer_key,
|
29
|
+
:consumer_secret => consumer_secret,
|
30
|
+
}).authorization
|
92
31
|
assert_response(200, '☺', *oapp.call(request.env))
|
93
32
|
end
|
94
33
|
|
95
|
-
it 'makes a valid two-legged signed request with a blank
|
34
|
+
it 'makes a valid two-legged signed request with a blank token (generated)' do
|
96
35
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
97
|
-
request.env['HTTP_AUTHORIZATION'] =
|
98
|
-
request.request_method,
|
99
|
-
request.url,
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
36
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
37
|
+
:request_method => request.request_method,
|
38
|
+
:uri => request.url,
|
39
|
+
:media_type => request.media_type,
|
40
|
+
:body => request.body,
|
41
|
+
:signature_method => 'HMAC-SHA1',
|
42
|
+
:consumer_key => consumer_key,
|
43
|
+
:consumer_secret => consumer_secret,
|
44
|
+
:token => '',
|
45
|
+
:token_secret => '',
|
46
|
+
}).authorization
|
107
47
|
assert_response(200, '☺', *oapp.call(request.env))
|
108
48
|
end
|
109
49
|
|
@@ -113,27 +53,31 @@ describe OAuthenticator::Middleware do
|
|
113
53
|
:input => 'a=b&a=c',
|
114
54
|
'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=UTF8',
|
115
55
|
))
|
116
|
-
request.env['HTTP_AUTHORIZATION'] =
|
117
|
-
request.request_method,
|
118
|
-
request.url,
|
119
|
-
|
120
|
-
|
121
|
-
|
56
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
57
|
+
:request_method => request.request_method,
|
58
|
+
:uri => request.url,
|
59
|
+
:media_type => request.media_type,
|
60
|
+
:body => request.body,
|
61
|
+
:signature_method => 'HMAC-SHA1',
|
62
|
+
:consumer_key => consumer_key,
|
63
|
+
:consumer_secret => consumer_secret
|
64
|
+
}).authorization
|
122
65
|
assert_response(200, '☺', *oapp.call(request.env))
|
123
66
|
end
|
124
67
|
|
125
68
|
it 'makes a valid three-legged signed request (generated)' do
|
126
69
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
127
|
-
request.env['HTTP_AUTHORIZATION'] =
|
128
|
-
request.request_method,
|
129
|
-
request.url,
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
70
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
71
|
+
:request_method => request.request_method,
|
72
|
+
:uri => request.url,
|
73
|
+
:media_type => request.media_type,
|
74
|
+
:body => request.body,
|
75
|
+
:signature_method => 'HMAC-SHA1',
|
76
|
+
:consumer_key => consumer_key,
|
77
|
+
:consumer_secret => consumer_secret,
|
78
|
+
:token => token,
|
79
|
+
:token_secret => token_secret,
|
80
|
+
}).authorization
|
137
81
|
assert_response(200, '☺', *oapp.call(request.env))
|
138
82
|
end
|
139
83
|
|
@@ -156,15 +100,15 @@ describe OAuthenticator::Middleware do
|
|
156
100
|
it "makes a valid signed three-legged request (static #{i})" do
|
157
101
|
Timecop.travel Time.at 1391021695
|
158
102
|
consumer # cause this to be created
|
159
|
-
|
103
|
+
token_hash # cause this to be created
|
160
104
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
161
105
|
request.env['HTTP_AUTHORIZATION'] = %q(OAuth ) +
|
162
106
|
%q(oauth_consumer_key="test_client_app_key", ) +
|
163
107
|
%q(oauth_nonce="6320851a8f4e18b2ac223497b0477f2e", ) +
|
164
|
-
%q(oauth_signature="
|
108
|
+
%q(oauth_signature="MyfcvCJfiOHCdkdwFOKtfwoOPqE%3D", ) +
|
165
109
|
%q(oauth_signature_method="HMAC-SHA1", ) +
|
166
110
|
%q(oauth_timestamp="1391021695", ) +
|
167
|
-
%q(oauth_token="
|
111
|
+
%q(oauth_token="test_token", ) +
|
168
112
|
%q(oauth_version="1.0")
|
169
113
|
assert_response(200, '☺', *oapp.call(request.env))
|
170
114
|
end
|
@@ -183,17 +127,16 @@ describe OAuthenticator::Middleware do
|
|
183
127
|
end
|
184
128
|
|
185
129
|
describe 'invalid Authorization header' do
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
end
|
130
|
+
it 'has duplicate params' do
|
131
|
+
assert_response(
|
132
|
+
401,
|
133
|
+
/Received multiple instances of Authorization parameter oauth_version/,
|
134
|
+
*oapp.call({'HTTP_AUTHORIZATION' => %q(OAuth oauth_version="1.0", oauth_version="1.1")})
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'has something unparseable' do
|
139
|
+
assert_response(401, /Could not parse Authorization header/, *oapp.call({'HTTP_AUTHORIZATION' => %q(OAuth <client-app-key>test_client_app_key</client-app-key>)}))
|
197
140
|
end
|
198
141
|
end
|
199
142
|
|
@@ -209,6 +152,18 @@ describe OAuthenticator::Middleware do
|
|
209
152
|
%q(oauth_version="1.0")
|
210
153
|
assert_response(401, /Authorization oauth_timestamp.*is missing/m, *oapp.call(request.env))
|
211
154
|
end
|
155
|
+
it 'omits timestamp with PLAINTEXT' do
|
156
|
+
Timecop.travel Time.at 1391021695
|
157
|
+
consumer # cause this to be created
|
158
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
159
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
160
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
161
|
+
%q(oauth_signature="test_client_app_secret%26", ) +
|
162
|
+
%q(oauth_signature_method="PLAINTEXT", ) +
|
163
|
+
#%q(oauth_timestamp="1391021695", ) +
|
164
|
+
%q(oauth_version="1.0")
|
165
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
166
|
+
end
|
212
167
|
it 'has a non-integer timestamp' do
|
213
168
|
Timecop.travel Time.at 1391021695
|
214
169
|
consumer # cause this to be created
|
@@ -293,25 +248,25 @@ describe OAuthenticator::Middleware do
|
|
293
248
|
%q(oauth_version="1.0")
|
294
249
|
assert_response(401, /Authorization oauth_consumer_key.*is invalid/m, *oapp.call(request.env))
|
295
250
|
end
|
296
|
-
it 'has an invalid
|
251
|
+
it 'has an invalid token' do
|
297
252
|
Timecop.travel Time.at 1391021695
|
298
253
|
consumer # cause this to be created
|
299
|
-
|
254
|
+
token_hash # cause this to be created
|
300
255
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
301
256
|
request.env['HTTP_AUTHORIZATION'] = %q(OAuth ) +
|
302
257
|
%q(oauth_consumer_key="test_client_app_key", ) +
|
303
258
|
%q(oauth_nonce="6320851a8f4e18b2ac223497b0477f2e", ) +
|
304
|
-
%q(oauth_signature="
|
259
|
+
%q(oauth_signature="MyfcvCJfiOHCdkdwFOKtfwoOPqE%3D", ) +
|
305
260
|
%q(oauth_signature_method="HMAC-SHA1", ) +
|
306
261
|
%q(oauth_timestamp="1391021695", ) +
|
307
|
-
%q(oauth_token="
|
262
|
+
%q(oauth_token="nonexistent_token", ) +
|
308
263
|
%q(oauth_version="1.0")
|
309
264
|
assert_response(401, /Authorization oauth_token.*is invalid/m, *oapp.call(request.env))
|
310
265
|
end
|
311
|
-
it 'has
|
266
|
+
it 'has a token belonging to a different consumer key' do
|
312
267
|
Timecop.travel Time.at 1391021695
|
313
268
|
consumer # cause this to be created
|
314
|
-
|
269
|
+
token_hash # cause this to be created
|
315
270
|
|
316
271
|
OAuthenticatorTestConfigMethods.consumer_secrets["different_client_app_key"] = "different_client_app_secret"
|
317
272
|
|
@@ -322,7 +277,7 @@ describe OAuthenticator::Middleware do
|
|
322
277
|
%q(oauth_signature="PVscPDg%2B%2FjAXRiahIggkeBpN5zI%3D", ) +
|
323
278
|
%q(oauth_signature_method="HMAC-SHA1", ) +
|
324
279
|
%q(oauth_timestamp="1391021695", ) +
|
325
|
-
%q(oauth_token="
|
280
|
+
%q(oauth_token="test_token", ) +
|
326
281
|
%q(oauth_version="1.0")
|
327
282
|
assert_response(401, /Authorization oauth_token.*does not belong to the specified consumer/m, *oapp.call(request.env))
|
328
283
|
end
|
@@ -338,6 +293,18 @@ describe OAuthenticator::Middleware do
|
|
338
293
|
%q(oauth_version="1.0")
|
339
294
|
assert_response(401, /Authorization oauth_nonce.*is missing/m, *oapp.call(request.env))
|
340
295
|
end
|
296
|
+
it 'omits nonce with PLAINTEXT' do
|
297
|
+
Timecop.travel Time.at 1391021695
|
298
|
+
consumer # cause this to be created
|
299
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
300
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
301
|
+
#%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
302
|
+
%q(oauth_signature="test_client_app_secret%26", ) +
|
303
|
+
%q(oauth_signature_method="PLAINTEXT", ) +
|
304
|
+
%q(oauth_timestamp="1391021695", ) +
|
305
|
+
%q(oauth_version="1.0")
|
306
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
307
|
+
end
|
341
308
|
it 'has an already-used nonce' do
|
342
309
|
Timecop.travel Time.at 1391021695
|
343
310
|
consumer # cause this to be created
|
@@ -400,29 +367,152 @@ describe OAuthenticator::Middleware do
|
|
400
367
|
assert_response(401, /Authorization oauth_signature.*is invalid/m, *oapp.call(request.env))
|
401
368
|
end
|
402
369
|
|
370
|
+
describe 'oauth_body_hash' do
|
371
|
+
it 'has a valid body hash' do
|
372
|
+
Timecop.travel Time.at 1391021695
|
373
|
+
consumer # cause this to be created
|
374
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'text/plain'))
|
375
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
376
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
377
|
+
%q(oauth_signature="RkmgdKV4zUPAlY1%2BkjwPSuCSr%2F8%3D", ) +
|
378
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
379
|
+
%q(oauth_timestamp="1391021695", ) +
|
380
|
+
%q(oauth_version="1.0", ) +
|
381
|
+
%q(oauth_body_hash="qvTGHdzF6KLavt4PO0gs2a6pQ00%3D")
|
382
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'has an incorrect body hash' do
|
386
|
+
Timecop.travel Time.at 1391021695
|
387
|
+
consumer # cause this to be created
|
388
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'text/plain'))
|
389
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
390
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
391
|
+
%q(oauth_signature="RkmgdKV4zUPAlY1%2BkjwPSuCSr%2F8%3D", ) +
|
392
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
393
|
+
%q(oauth_timestamp="1391021695", ) +
|
394
|
+
%q(oauth_version="1.0", ) +
|
395
|
+
%q(oauth_body_hash="yes this is authentic")
|
396
|
+
assert_response(401, /Authorization oauth_body_hash.*is invalid/m, *oapp.call(request.env))
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'has a body hash when one is not allowed (even if it is correct)' do
|
400
|
+
Timecop.travel Time.at 1391021695
|
401
|
+
consumer # cause this to be created
|
402
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'application/x-www-form-urlencoded'))
|
403
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
404
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
405
|
+
%q(oauth_signature="DG9qcuXaMPMx0fOcVFiUEPdYQnY%3D", ) +
|
406
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
407
|
+
%q(oauth_timestamp="1391021695", ) +
|
408
|
+
%q(oauth_version="1.0", ) +
|
409
|
+
%q(oauth_body_hash="qvTGHdzF6KLavt4PO0gs2a6pQ00%3D")
|
410
|
+
assert_response(401, /Authorization oauth_body_hash.*must not be included with form-encoded requests/m, *oapp.call(request.env))
|
411
|
+
end
|
412
|
+
|
413
|
+
it 'has a body hash with PLAINTEXT' do
|
414
|
+
Timecop.travel Time.at 1391021695
|
415
|
+
consumer # cause this to be created
|
416
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'text/plain'))
|
417
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
418
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
419
|
+
%q(oauth_signature="test_client_app_secret%26", ) +
|
420
|
+
%q(oauth_signature_method="PLAINTEXT", ) +
|
421
|
+
%q(oauth_timestamp="1391021695", ) +
|
422
|
+
%q(oauth_version="1.0", ) +
|
423
|
+
%q(oauth_body_hash="qvTGHdzF6KLavt4PO0gs2a6pQ00%3D")
|
424
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
425
|
+
end
|
426
|
+
|
427
|
+
describe 'body hash is required' do
|
428
|
+
let(:hashrequiredapp) do
|
429
|
+
hash_required_config = Module.new do
|
430
|
+
include OAuthenticatorTestConfigMethods
|
431
|
+
define_method(:body_hash_required?) { true }
|
432
|
+
end
|
433
|
+
OAuthenticator::RackAuthenticator.new(simpleapp, :config_methods => hash_required_config)
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'is missing a body hash, one is not allowed' do
|
437
|
+
Timecop.travel Time.at 1391021695
|
438
|
+
consumer # cause this to be created
|
439
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'application/x-www-form-urlencoded'))
|
440
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
441
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
442
|
+
%q(oauth_signature="DG9qcuXaMPMx0fOcVFiUEPdYQnY%3D", ) +
|
443
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
444
|
+
%q(oauth_timestamp="1391021695", ) +
|
445
|
+
%q(oauth_version="1.0")
|
446
|
+
assert_response(200, '☺', *hashrequiredapp.call(request.env))
|
447
|
+
end
|
448
|
+
it 'is missing a body hash, one is allowed' do
|
449
|
+
Timecop.travel Time.at 1391021695
|
450
|
+
consumer # cause this to be created
|
451
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'text/plain'))
|
452
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
453
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
454
|
+
%q(oauth_signature="czC%2F9Z8tE1H4AJaT8lOKLokrWRE%3D", ) +
|
455
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
456
|
+
%q(oauth_timestamp="1391021695", ) +
|
457
|
+
%q(oauth_version="1.0")
|
458
|
+
assert_response(401, /Authorization oauth_body_hash.*is required \(on non-form-encoded requests\)/m, *hashrequiredapp.call(request.env))
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
describe 'body hash not required' do
|
463
|
+
it 'is missing a body hash, one is not allowed' do
|
464
|
+
Timecop.travel Time.at 1391021695
|
465
|
+
consumer # cause this to be created
|
466
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'application/x-www-form-urlencoded'))
|
467
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
468
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
469
|
+
%q(oauth_signature="DG9qcuXaMPMx0fOcVFiUEPdYQnY%3D", ) +
|
470
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
471
|
+
%q(oauth_timestamp="1391021695", ) +
|
472
|
+
%q(oauth_version="1.0")
|
473
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
474
|
+
end
|
475
|
+
it 'is missing a body hash, one is allowed' do
|
476
|
+
Timecop.travel Time.at 1391021695
|
477
|
+
consumer # cause this to be created
|
478
|
+
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'PUT', :input => 'hello', 'CONTENT_TYPE' => 'text/plain'))
|
479
|
+
request.env['HTTP_AUTHORIZATION'] = %q(OAuth oauth_consumer_key="test_client_app_key", ) +
|
480
|
+
%q(oauth_nonce="c1c2bd8676d44e48691c8dceffa66a96", ) +
|
481
|
+
%q(oauth_signature="czC%2F9Z8tE1H4AJaT8lOKLokrWRE%3D", ) +
|
482
|
+
%q(oauth_signature_method="HMAC-SHA1", ) +
|
483
|
+
%q(oauth_timestamp="1391021695", ) +
|
484
|
+
%q(oauth_version="1.0")
|
485
|
+
assert_response(200, '☺', *oapp.call(request.env))
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
403
490
|
describe :bypass do
|
404
491
|
it 'bypasses with invalid request' do
|
405
|
-
oapp = OAuthenticator::
|
492
|
+
oapp = OAuthenticator::RackAuthenticator.new(simpleapp, :bypass => proc { true }, :config_methods => OAuthenticatorTestConfigMethods)
|
406
493
|
env = Rack::MockRequest.env_for('/', :method => 'GET').merge({'HTTP_AUTHORIZATION' => 'oauth ?'})
|
407
494
|
assert_response(200, '☺', *oapp.call(env))
|
408
495
|
end
|
409
496
|
|
410
497
|
it 'does not bypass with invalid request' do
|
411
|
-
oapp = OAuthenticator::
|
498
|
+
oapp = OAuthenticator::RackAuthenticator.new(simpleapp, :bypass => proc { false }, :config_methods => OAuthenticatorTestConfigMethods)
|
412
499
|
assert_equal(401, oapp.call({}).first)
|
413
500
|
end
|
414
501
|
|
415
502
|
it 'bypasses with valid request' do
|
416
503
|
was_authenticated = nil
|
417
504
|
bapp = proc { |env| was_authenticated = env['oauth.authenticated']; [200, {}, ['☺']] }
|
418
|
-
boapp = OAuthenticator::
|
505
|
+
boapp = OAuthenticator::RackAuthenticator.new(bapp, :bypass => proc { true }, :config_methods => OAuthenticatorTestConfigMethods)
|
419
506
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
420
|
-
request.env['HTTP_AUTHORIZATION'] =
|
421
|
-
request.request_method,
|
422
|
-
request.url,
|
423
|
-
|
424
|
-
|
425
|
-
|
507
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
508
|
+
:request_method => request.request_method,
|
509
|
+
:uri => request.url,
|
510
|
+
:media_type => request.media_type,
|
511
|
+
:body => request.body,
|
512
|
+
:signature_method => 'HMAC-SHA1',
|
513
|
+
:consumer_key => consumer_key,
|
514
|
+
:consumer_secret => consumer_secret
|
515
|
+
}).authorization
|
426
516
|
assert_response(200, '☺', *boapp.call(request.env))
|
427
517
|
assert(was_authenticated == false)
|
428
518
|
end
|
@@ -430,16 +520,54 @@ describe OAuthenticator::Middleware do
|
|
430
520
|
it 'does not bypass with valid request' do
|
431
521
|
was_authenticated = nil
|
432
522
|
bapp = proc { |env| was_authenticated = env['oauth.authenticated']; [200, {}, ['☺']] }
|
433
|
-
boapp = OAuthenticator::
|
523
|
+
boapp = OAuthenticator::RackAuthenticator.new(bapp, :bypass => proc { false }, :config_methods => OAuthenticatorTestConfigMethods)
|
434
524
|
request = Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET'))
|
435
|
-
request.env['HTTP_AUTHORIZATION'] =
|
436
|
-
request.request_method,
|
437
|
-
request.url,
|
438
|
-
|
439
|
-
|
440
|
-
|
525
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
526
|
+
:request_method => request.request_method,
|
527
|
+
:uri => request.url,
|
528
|
+
:media_type => request.media_type,
|
529
|
+
:body => request.body,
|
530
|
+
:signature_method => 'HMAC-SHA1',
|
531
|
+
:consumer_key => consumer_key,
|
532
|
+
:consumer_secret => consumer_secret
|
533
|
+
}).authorization
|
441
534
|
assert_response(200, '☺', *boapp.call(request.env))
|
442
535
|
assert(was_authenticated == true)
|
443
536
|
end
|
444
537
|
end
|
538
|
+
|
539
|
+
describe 'rack env variables' do
|
540
|
+
let :request do
|
541
|
+
Rack::Request.new(Rack::MockRequest.env_for('/', :method => 'GET')).tap do |request|
|
542
|
+
request.env['HTTP_AUTHORIZATION'] = OAuthenticator::SignableRequest.new({
|
543
|
+
:request_method => request.request_method,
|
544
|
+
:uri => request.url,
|
545
|
+
:media_type => request.media_type,
|
546
|
+
:body => request.body,
|
547
|
+
:signature_method => 'HMAC-SHA1',
|
548
|
+
:consumer_key => consumer_key,
|
549
|
+
:consumer_secret => consumer_secret,
|
550
|
+
:token => token,
|
551
|
+
:token_secret => token_secret,
|
552
|
+
}).authorization
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'sets oauth.authenticated, oauth.token, oauth.consumer_key' do
|
557
|
+
oauth_authenticated = nil
|
558
|
+
oauth_token = nil
|
559
|
+
oauth_consumer_key = nil
|
560
|
+
testapp = proc do |env|
|
561
|
+
oauth_authenticated = env['oauth.authenticated']
|
562
|
+
oauth_token = env['oauth.token']
|
563
|
+
oauth_consumer_key = env['oauth.consumer_key']
|
564
|
+
[200, {}, ['☺']]
|
565
|
+
end
|
566
|
+
otestapp = OAuthenticator::RackAuthenticator.new(testapp, :config_methods => OAuthenticatorTestConfigMethods)
|
567
|
+
assert_response(200, '☺', *otestapp.call(request.env))
|
568
|
+
assert_equal(token, oauth_token)
|
569
|
+
assert_equal(consumer_key, oauth_consumer_key)
|
570
|
+
assert_equal(true, oauth_authenticated)
|
571
|
+
end
|
572
|
+
end
|
445
573
|
end
|