api-auth 2.5.1 → 2.6.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/.github/workflows/main.yml +9 -5
- data/.rubocop.yml +5 -1
- data/.rubocop_todo.yml +11 -30
- data/Appraisals +6 -6
- data/CHANGELOG.md +18 -0
- data/README.md +24 -15
- data/VERSION +1 -1
- data/api_auth.gemspec +9 -8
- data/gemfiles/{rails_52.gemfile → rails_70.gemfile} +3 -3
- data/lib/api_auth/base.rb +4 -4
- data/lib/api_auth/headers.rb +6 -4
- data/lib/api_auth/helpers.rb +4 -0
- data/lib/api_auth/railtie.rb +7 -7
- data/lib/api_auth/request_drivers/action_controller.rb +9 -4
- data/lib/api_auth/request_drivers/faraday_env.rb +102 -0
- data/lib/api_auth.rb +1 -0
- data/lib/faraday/api_auth/middleware.rb +35 -0
- data/lib/faraday/api_auth.rb +8 -0
- data/spec/api_auth_spec.rb +3 -3
- data/spec/faraday_middleware_spec.rb +17 -0
- data/spec/headers_spec.rb +8 -8
- data/spec/railtie_spec.rb +2 -1
- data/spec/request_drivers/action_dispatch_spec.rb +91 -6
- data/spec/request_drivers/faraday_env_spec.rb +188 -0
- data/spec/request_drivers/http_spec.rb +1 -1
- data/spec/request_drivers/httpi_spec.rb +2 -2
- data/spec/request_drivers/rest_client_spec.rb +19 -19
- data/spec/spec_helper.rb +6 -2
- metadata +64 -70
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'faraday/api_auth'
|
3
|
+
|
4
|
+
describe Faraday::ApiAuth::Middleware do
|
5
|
+
it 'adds the Authorization headers' do
|
6
|
+
conn = Faraday.new('http://localhost/') do |f|
|
7
|
+
f.request :api_auth, 'foo', 'secret', digest: 'sha256'
|
8
|
+
f.adapter :test do |stub|
|
9
|
+
stub.get('http://localhost/test') do |env|
|
10
|
+
[200, {}, env.request_headers['Authorization']]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
response = conn.get('test', nil, { 'Date' => 'Tue, 02 Aug 2022 09:29:24 GMT' })
|
15
|
+
expect(response.body).to eq 'APIAuth-HMAC-SHA256 foo:Tn/lIZ9kphcO32DwG4wFHenqBt37miDEIkA5ykLgGiQ='
|
16
|
+
end
|
17
|
+
end
|
data/spec/headers_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe ApiAuth::Headers do
|
|
8
8
|
let(:uri) { '' }
|
9
9
|
|
10
10
|
context 'uri with just host without /' do
|
11
|
-
let(:uri) { '
|
11
|
+
let(:uri) { 'https://google.com'.freeze }
|
12
12
|
|
13
13
|
it 'return / as canonical string path' do
|
14
14
|
expect(subject.canonical_string).to eq('GET,,,/,')
|
@@ -20,7 +20,7 @@ describe ApiAuth::Headers do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'uri with host and /' do
|
23
|
-
let(:uri) { '
|
23
|
+
let(:uri) { 'https://google.com/'.freeze }
|
24
24
|
|
25
25
|
it 'return / as canonical string path' do
|
26
26
|
expect(subject.canonical_string).to eq('GET,,,/,')
|
@@ -31,8 +31,8 @@ describe ApiAuth::Headers do
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
context 'uri has a string matching
|
35
|
-
let(:uri) { '
|
34
|
+
context 'uri has a string matching https:// in it' do
|
35
|
+
let(:uri) { 'https://google.com/?redirect_to=https://www.example.com'.freeze }
|
36
36
|
|
37
37
|
it 'return /?redirect_to=https://www.example.com as canonical string path' do
|
38
38
|
expect(subject.canonical_string).to eq('GET,,,/?redirect_to=https://www.example.com,')
|
@@ -46,7 +46,7 @@ describe ApiAuth::Headers do
|
|
46
46
|
|
47
47
|
context 'string construction' do
|
48
48
|
context 'with a driver that supplies http_method' do
|
49
|
-
let(:request) { RestClient::Request.new(url: '
|
49
|
+
let(:request) { RestClient::Request.new(url: 'https://google.com', method: :get) }
|
50
50
|
subject(:headers) { described_class.new(request) }
|
51
51
|
let(:driver) { headers.instance_variable_get('@request') }
|
52
52
|
|
@@ -161,7 +161,7 @@ describe ApiAuth::Headers do
|
|
161
161
|
context 'no content hash already calculated' do
|
162
162
|
let(:request) do
|
163
163
|
RestClient::Request.new(
|
164
|
-
url: '
|
164
|
+
url: 'https://google.com',
|
165
165
|
method: :post,
|
166
166
|
payload: "hello\nworld"
|
167
167
|
)
|
@@ -176,7 +176,7 @@ describe ApiAuth::Headers do
|
|
176
176
|
context 'hash already calculated' do
|
177
177
|
let(:request) do
|
178
178
|
RestClient::Request.new(
|
179
|
-
url: '
|
179
|
+
url: 'https://google.com',
|
180
180
|
method: :post,
|
181
181
|
payload: "hello\nworld",
|
182
182
|
headers: { 'X-Authorization-Content-SHA256' => 'abcd' }
|
@@ -191,7 +191,7 @@ describe ApiAuth::Headers do
|
|
191
191
|
end
|
192
192
|
|
193
193
|
describe '#content_hash_mismatch?' do
|
194
|
-
let(:request) { RestClient::Request.new(url: '
|
194
|
+
let(:request) { RestClient::Request.new(url: 'https://google.com', method: :get) }
|
195
195
|
subject(:headers) { described_class.new(request) }
|
196
196
|
let(:driver) { headers.instance_variable_get('@request') }
|
197
197
|
|
data/spec/railtie_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'action_controller/test_case'
|
2
3
|
|
3
4
|
describe 'Rails integration' do
|
4
5
|
API_KEY_STORE = { '1044' => 'l16imAXie1sRMcJODpOG7UwC1VyoqvO13jejkfpKWX4Z09W8DC9IrU23DvCwMry7pgSFW6c5S1GIfV0OY6F/vUA==' }.freeze
|
@@ -116,7 +117,7 @@ describe 'Rails integration' do
|
|
116
117
|
describe 'Rails ActiveResource integration' do
|
117
118
|
class TestResource < ActiveResource::Base
|
118
119
|
with_api_auth '1044', API_KEY_STORE['1044']
|
119
|
-
self.site = '
|
120
|
+
self.site = 'https://localhost/'
|
120
121
|
self.format = :xml
|
121
122
|
end
|
122
123
|
|
@@ -5,6 +5,7 @@ if defined?(ActionDispatch::Request)
|
|
5
5
|
describe ApiAuth::RequestDrivers::ActionDispatchRequest do
|
6
6
|
let(:timestamp) { Time.now.utc.httpdate }
|
7
7
|
let(:content_sha256) { '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' }
|
8
|
+
let(:content_md5) { '+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' }
|
8
9
|
|
9
10
|
let(:request) do
|
10
11
|
ActionDispatch::Request.new(
|
@@ -48,7 +49,26 @@ if defined?(ActionDispatch::Request)
|
|
48
49
|
)
|
49
50
|
end
|
50
51
|
|
52
|
+
let(:request_md5) do
|
53
|
+
ActionDispatch::Request.new(
|
54
|
+
'AUTHORIZATION' => 'APIAuth 1044:12345',
|
55
|
+
'PATH_INFO' => '/resource.xml',
|
56
|
+
'QUERY_STRING' => 'foo=bar&bar=foo',
|
57
|
+
'REQUEST_METHOD' => 'PUT',
|
58
|
+
'CONTENT_MD5' => content_md5,
|
59
|
+
'CONTENT_TYPE' => 'text/plain',
|
60
|
+
'CONTENT_LENGTH' => '11',
|
61
|
+
'HTTP_DATE' => timestamp,
|
62
|
+
'rack.input' => StringIO.new("hello\nworld")
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
51
66
|
subject(:driven_request) { ApiAuth::RequestDrivers::ActionDispatchRequest.new(request) }
|
67
|
+
subject(:driven_request_md5) do
|
68
|
+
ApiAuth::RequestDrivers::ActionDispatchRequest.new(request_md5,
|
69
|
+
authorize_md5: true)
|
70
|
+
end
|
71
|
+
subject(:driven_request_sha2_with_md5) { ApiAuth::RequestDrivers::ActionDispatchRequest.new(request, authorize_md5: true) }
|
52
72
|
|
53
73
|
describe 'getting headers correctly' do
|
54
74
|
it 'gets the content_type' do
|
@@ -69,6 +89,11 @@ if defined?(ActionDispatch::Request)
|
|
69
89
|
expect(example_request.content_hash).to eq(content_sha256)
|
70
90
|
end
|
71
91
|
|
92
|
+
it 'gets the content_hash for request_md5' do
|
93
|
+
example_request = ApiAuth::RequestDrivers::ActionDispatchRequest.new(request_md5, authorize_md5: true)
|
94
|
+
expect(example_request.content_hash).to eq(content_md5)
|
95
|
+
end
|
96
|
+
|
72
97
|
it 'gets the request_uri' do
|
73
98
|
expect(driven_request.request_uri).to eq('/resource.xml?foo=bar&bar=foo')
|
74
99
|
end
|
@@ -83,13 +108,17 @@ if defined?(ActionDispatch::Request)
|
|
83
108
|
|
84
109
|
describe '#calculated_hash' do
|
85
110
|
it 'calculates hash from the body' do
|
86
|
-
expect(driven_request.calculated_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
111
|
+
expect(driven_request.calculated_hash).to eq(['JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='])
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'calculates hashes from the body with md5 compatibility option' do
|
115
|
+
expect(driven_request_md5.calculated_hash).to eq(%w[JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g= kZXQvrKoieG+Be1rsZVINw==])
|
87
116
|
end
|
88
117
|
|
89
118
|
it 'treats no body as empty string' do
|
90
119
|
request.env['rack.input'] = StringIO.new
|
91
120
|
request.env['CONTENT_LENGTH'] = 0
|
92
|
-
expect(driven_request.calculated_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
|
121
|
+
expect(driven_request.calculated_hash).to eq(['47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='])
|
93
122
|
end
|
94
123
|
end
|
95
124
|
|
@@ -141,12 +170,12 @@ if defined?(ActionDispatch::Request)
|
|
141
170
|
it 'populates content hash' do
|
142
171
|
request.env['REQUEST_METHOD'] = 'POST'
|
143
172
|
driven_request.populate_content_hash
|
144
|
-
expect(request.env['X-AUTHORIZATION-CONTENT-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
173
|
+
expect(request.env['X-AUTHORIZATION-CONTENT-SHA256']).to eq(['JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='])
|
145
174
|
end
|
146
175
|
|
147
176
|
it 'refreshes the cached headers' do
|
148
177
|
driven_request.populate_content_hash
|
149
|
-
expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
178
|
+
expect(driven_request.content_hash).to eq(['JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='])
|
150
179
|
end
|
151
180
|
end
|
152
181
|
|
@@ -154,12 +183,12 @@ if defined?(ActionDispatch::Request)
|
|
154
183
|
it 'populates content hash' do
|
155
184
|
request.env['REQUEST_METHOD'] = 'PUT'
|
156
185
|
driven_request.populate_content_hash
|
157
|
-
expect(request.env['X-AUTHORIZATION-CONTENT-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
186
|
+
expect(request.env['X-AUTHORIZATION-CONTENT-SHA256']).to eq(['JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='])
|
158
187
|
end
|
159
188
|
|
160
189
|
it 'refreshes the cached headers' do
|
161
190
|
driven_request.populate_content_hash
|
162
|
-
expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
191
|
+
expect(driven_request.content_hash).to eq(['JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='])
|
163
192
|
end
|
164
193
|
end
|
165
194
|
|
@@ -200,73 +229,129 @@ if defined?(ActionDispatch::Request)
|
|
200
229
|
context 'when getting' do
|
201
230
|
before do
|
202
231
|
request.env['REQUEST_METHOD'] = 'GET'
|
232
|
+
request_md5.env['REQUEST_METHOD'] = 'GET'
|
203
233
|
end
|
204
234
|
|
205
235
|
it 'is false' do
|
206
236
|
expect(driven_request.content_hash_mismatch?).to be false
|
207
237
|
end
|
238
|
+
|
239
|
+
it 'is false with md5' do
|
240
|
+
expect(driven_request_md5.content_hash_mismatch?).to be false
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'is false with sha2 and md5 compatibility on' do
|
244
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be false
|
245
|
+
end
|
208
246
|
end
|
209
247
|
|
210
248
|
context 'when posting' do
|
211
249
|
before do
|
212
250
|
request.env['REQUEST_METHOD'] = 'POST'
|
251
|
+
request_md5.env['REQUEST_METHOD'] = 'POST'
|
213
252
|
end
|
214
253
|
|
215
254
|
context 'when calculated matches sent' do
|
216
255
|
before do
|
217
256
|
request.env['X-AUTHORIZATION-CONTENT-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
|
257
|
+
request_md5.env['CONTENT_MD5'] = 'kZXQvrKoieG+Be1rsZVINw=='
|
218
258
|
end
|
219
259
|
|
220
260
|
it 'is false' do
|
221
261
|
expect(driven_request.content_hash_mismatch?).to be false
|
222
262
|
end
|
263
|
+
|
264
|
+
it 'is false with md5' do
|
265
|
+
expect(driven_request_md5.content_hash_mismatch?).to be false
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'is false with sha2 and md5 compatibility on' do
|
269
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be false
|
270
|
+
end
|
223
271
|
end
|
224
272
|
|
225
273
|
context "when calculated doesn't match sent" do
|
226
274
|
before do
|
227
275
|
request.env['X-AUTHORIZATION-CONTENT-SHA256'] = '3'
|
276
|
+
request_md5.env['CONTENT_MD5'] = '3'
|
228
277
|
end
|
229
278
|
|
230
279
|
it 'is true' do
|
231
280
|
expect(driven_request.content_hash_mismatch?).to be true
|
232
281
|
end
|
282
|
+
|
283
|
+
it 'is true with md5' do
|
284
|
+
expect(driven_request.content_hash_mismatch?).to be true
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'is true with sha2 and md5 compatibility on' do
|
288
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be true
|
289
|
+
end
|
233
290
|
end
|
234
291
|
end
|
235
292
|
|
236
293
|
context 'when putting' do
|
237
294
|
before do
|
238
295
|
request.env['REQUEST_METHOD'] = 'PUT'
|
296
|
+
request_md5.env['REQUEST_METHOD'] = 'PUT'
|
239
297
|
end
|
240
298
|
|
241
299
|
context 'when calculated matches sent' do
|
242
300
|
before do
|
243
301
|
request.env['X-AUTHORIZATION-CONTENT-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
|
302
|
+
request_md5.env['CONTENT_MD5'] = 'kZXQvrKoieG+Be1rsZVINw=='
|
244
303
|
end
|
245
304
|
|
246
305
|
it 'is false' do
|
247
306
|
expect(driven_request.content_hash_mismatch?).to be false
|
248
307
|
end
|
308
|
+
|
309
|
+
it 'is false with md5' do
|
310
|
+
expect(driven_request_md5.content_hash_mismatch?).to be false
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'is false with sha2 and md5 compatibility on' do
|
314
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be false
|
315
|
+
end
|
249
316
|
end
|
250
317
|
|
251
318
|
context "when calculated doesn't match sent" do
|
252
319
|
before do
|
253
320
|
request.env['X-AUTHORIZATION-CONTENT-SHA256'] = '3'
|
321
|
+
request_md5.env['CONTENT_MD5'] = '3'
|
254
322
|
end
|
255
323
|
|
256
324
|
it 'is true' do
|
257
325
|
expect(driven_request.content_hash_mismatch?).to be true
|
258
326
|
end
|
327
|
+
|
328
|
+
it 'is true with md5' do
|
329
|
+
expect(driven_request_md5.content_hash_mismatch?).to be true
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'is true with sha2 and md5 compatibility on' do
|
333
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be true
|
334
|
+
end
|
259
335
|
end
|
260
336
|
end
|
261
337
|
|
262
338
|
context 'when deleting' do
|
263
339
|
before do
|
264
340
|
request.env['REQUEST_METHOD'] = 'DELETE'
|
341
|
+
request_md5.env['REQUEST_METHOD'] = 'DELETE'
|
265
342
|
end
|
266
343
|
|
267
344
|
it 'is false' do
|
268
345
|
expect(driven_request.content_hash_mismatch?).to be false
|
269
346
|
end
|
347
|
+
|
348
|
+
it 'is false with md5' do
|
349
|
+
expect(driven_request_md5.content_hash_mismatch?).to be false
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'is false with sha2 and md5 compatibility on' do
|
353
|
+
expect(driven_request_sha2_with_md5.content_hash_mismatch?).to be false
|
354
|
+
end
|
270
355
|
end
|
271
356
|
end
|
272
357
|
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApiAuth::RequestDrivers::FaradayEnv do
|
4
|
+
let(:timestamp) { Time.now.utc.httpdate }
|
5
|
+
|
6
|
+
let(:request) do
|
7
|
+
Faraday::Env.new(verb, body, URI(uri), {}, Faraday::Utils::Headers.new(headers))
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:verb) { :put }
|
11
|
+
let(:uri) { 'https://localhost/resource.xml?foo=bar&bar=foo' }
|
12
|
+
let(:body) { "hello\nworld" }
|
13
|
+
|
14
|
+
let(:headers) do
|
15
|
+
{
|
16
|
+
'Authorization' => 'APIAuth 1044:12345',
|
17
|
+
'X-Authorization-Content-SHA256' => '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
|
18
|
+
'content-type' => 'text/plain',
|
19
|
+
'date' => timestamp
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
subject(:driven_request) { described_class.new(request) }
|
24
|
+
|
25
|
+
describe 'getting headers correctly' do
|
26
|
+
it 'gets the content_type' do
|
27
|
+
expect(driven_request.content_type).to eq('text/plain')
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'without Content-Type' do
|
31
|
+
let(:headers) { {} }
|
32
|
+
|
33
|
+
it 'defaults to url-encoded' do
|
34
|
+
expect(driven_request.content_type).to eq 'application/x-www-form-urlencoded'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'gets the content_hash' do
|
39
|
+
expect(driven_request.content_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'gets the request_uri' do
|
43
|
+
expect(driven_request.request_uri).to eq('/resource.xml?foo=bar&bar=foo')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'gets the timestamp' do
|
47
|
+
expect(driven_request.timestamp).to eq(timestamp)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'gets the authorization_header' do
|
51
|
+
expect(driven_request.authorization_header).to eq('APIAuth 1044:12345')
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#calculated_hash' do
|
55
|
+
it 'calculates hash from the body' do
|
56
|
+
expect(driven_request.calculated_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
57
|
+
expect(driven_request.body.bytesize).to eq(11)
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'no body' do
|
61
|
+
let(:body) { nil }
|
62
|
+
|
63
|
+
it 'treats no body as empty string' do
|
64
|
+
expect(driven_request.calculated_hash).to eq('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=')
|
65
|
+
expect(driven_request.body.bytesize).to eq(0)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'multipart content' do
|
70
|
+
let(:body) { File.new('spec/fixtures/upload.png') }
|
71
|
+
|
72
|
+
it 'calculates correctly for multipart content' do
|
73
|
+
expect(driven_request.calculated_hash).to eq('AlKDe7kjMQhuKgKuNG8I7GA93MasHcaVJkJLaUT7+dY=')
|
74
|
+
expect(driven_request.body.bytesize).to eq(5112)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'http_method' do
|
80
|
+
context 'when put request' do
|
81
|
+
let(:verb) { :put }
|
82
|
+
|
83
|
+
it 'returns upcased put' do
|
84
|
+
expect(driven_request.http_method).to eq('PUT')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when get request' do
|
89
|
+
let(:verb) { :get }
|
90
|
+
|
91
|
+
it 'returns upcased get' do
|
92
|
+
expect(driven_request.http_method).to eq('GET')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'setting headers correctly' do
|
99
|
+
let(:headers) do
|
100
|
+
{
|
101
|
+
'content-type' => 'text/plain'
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#populate_content_hash' do
|
106
|
+
context 'when request type has no body' do
|
107
|
+
let(:verb) { :get }
|
108
|
+
|
109
|
+
it "doesn't populate content hash" do
|
110
|
+
driven_request.populate_content_hash
|
111
|
+
expect(request.request_headers['X-Authorization-Content-SHA256']).to be_nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when request type has a body' do
|
116
|
+
let(:verb) { :put }
|
117
|
+
|
118
|
+
it 'populates content hash' do
|
119
|
+
driven_request.populate_content_hash
|
120
|
+
expect(request.request_headers['X-Authorization-Content-SHA256']).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'refreshes the cached headers' do
|
124
|
+
driven_request.populate_content_hash
|
125
|
+
expect(driven_request.content_hash).to eq('JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g=')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#set_date' do
|
131
|
+
before do
|
132
|
+
allow(Time).to receive_message_chain(:now, :utc, :httpdate).and_return(timestamp)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'sets the date header of the request' do
|
136
|
+
driven_request.set_date
|
137
|
+
expect(request.request_headers['DATE']).to eq(timestamp)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#set_auth_header' do
|
142
|
+
it 'sets the auth header' do
|
143
|
+
driven_request.set_auth_header('APIAuth 1044:54321')
|
144
|
+
expect(request.request_headers['Authorization']).to eq('APIAuth 1044:54321')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe 'content_hash_mismatch?' do
|
150
|
+
context 'when request type has no body' do
|
151
|
+
let(:verb) { :get }
|
152
|
+
|
153
|
+
it 'is false' do
|
154
|
+
expect(driven_request.content_hash_mismatch?).to be false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when request type has a body' do
|
159
|
+
let(:verb) { :put }
|
160
|
+
|
161
|
+
context 'when calculated matches sent' do
|
162
|
+
before do
|
163
|
+
request.request_headers['X-Authorization-Content-SHA256'] = 'JsYKYdAdtYNspw/v1EpqAWYgQTyO9fJZpsVhLU9507g='
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'is false' do
|
167
|
+
expect(driven_request.content_hash_mismatch?).to be false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when calculated doesn't match sent" do
|
172
|
+
before do
|
173
|
+
request['X-Authorization-Content-SHA256'] = '3'
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'is true' do
|
177
|
+
expect(driven_request.content_hash_mismatch?).to be true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'fetch_headers' do
|
184
|
+
it 'returns request headers' do
|
185
|
+
expect(driven_request.fetch_headers).to include('CONTENT-TYPE' => 'text/plain')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -13,7 +13,7 @@ describe ApiAuth::RequestDrivers::HttpRequest do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
let(:verb) { :put }
|
16
|
-
let(:uri) { '
|
16
|
+
let(:uri) { 'https://localhost/resource.xml?foo=bar&bar=foo' }
|
17
17
|
let(:body) { "hello\nworld" }
|
18
18
|
|
19
19
|
let(:headers) do
|
@@ -4,7 +4,7 @@ describe ApiAuth::RequestDrivers::HttpiRequest do
|
|
4
4
|
let(:timestamp) { Time.now.utc.httpdate }
|
5
5
|
|
6
6
|
let(:request) do
|
7
|
-
httpi_request = HTTPI::Request.new('
|
7
|
+
httpi_request = HTTPI::Request.new('https://localhost/resource.xml?foo=bar&bar=foo')
|
8
8
|
httpi_request.headers.merge!('Authorization' => 'APIAuth 1044:12345',
|
9
9
|
'X-Authorization-Content-SHA256' => '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=',
|
10
10
|
'content-type' => 'text/plain',
|
@@ -56,7 +56,7 @@ describe ApiAuth::RequestDrivers::HttpiRequest do
|
|
56
56
|
|
57
57
|
describe 'setting headers correctly' do
|
58
58
|
let(:request) do
|
59
|
-
httpi_request = HTTPI::Request.new('
|
59
|
+
httpi_request = HTTPI::Request.new('https://localhost/resource.xml?foo=bar&bar=foo')
|
60
60
|
httpi_request.headers['content-type'] = 'text/plain'
|
61
61
|
httpi_request
|
62
62
|
end
|