escher 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/spec/escher_spec.rb DELETED
@@ -1,358 +0,0 @@
1
- require 'spec_helper'
2
-
3
- test_suites = {
4
- # 'get-header-key-duplicate',
5
- # 'get-header-value-order',
6
- aws4: %w(
7
- get-header-value-trim
8
- get-relative
9
- get-relative-relative
10
- get-slash
11
- get-slash-dot-slash
12
- get-slash-pointless-dot
13
- get-slashes
14
- get-space
15
- get-unreserved
16
- get-utf8
17
- get-vanilla
18
- get-vanilla-empty-query-key
19
- get-vanilla-query
20
- get-vanilla-query-order-key
21
- get-vanilla-query-order-key-case
22
- get-vanilla-query-order-value
23
- get-vanilla-query-unreserved
24
- get-vanilla-ut8-query
25
- post-header-key-case
26
- post-header-key-sort
27
- post-header-value-case
28
- post-vanilla
29
- post-vanilla-empty-query-value
30
- post-vanilla-query
31
- post-vanilla-query-nonunreserved
32
- post-vanilla-query-space
33
- post-x-www-form-urlencoded
34
- post-x-www-form-urlencoded-parameters
35
- ),
36
- emarsys: %w(
37
- get-header-key-duplicate
38
- post-header-key-order
39
- post-header-value-spaces
40
- post-header-value-spaces-within-quotes
41
- )
42
- }
43
-
44
- ESCHER_AWS4_OPTIONS = {
45
- algo_prefix: 'AWS4', vendor_key: 'AWS4', hash_algo: 'SHA256', auth_header_name: 'Authorization', date_header_name: 'Date'
46
- }
47
-
48
- ESCHER_MIXED_OPTIONS = {
49
- algo_prefix: 'EMS', vendor_key: 'EMS', hash_algo: 'SHA256', auth_header_name: 'Authorization', date_header_name: 'Date', clock_skew: 10
50
- }
51
-
52
- ESCHER_EMARSYS_OPTIONS = ESCHER_MIXED_OPTIONS.merge(auth_header_name: 'X-Ems-Auth', date_header_name: 'X-Ems-Date')
53
-
54
- GOOD_AUTH_HEADER = 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'
55
-
56
- # noinspection RubyStringKeysInHashInspection
57
- def key_db
58
- {
59
- 'AKIDEXAMPLE' => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
60
- 'th3K3y' => 'very_secure',
61
- }
62
- end
63
-
64
- def credential_scope
65
- %w(us-east-1 host aws4_request)
66
- end
67
-
68
- def client
69
- {:api_key_id => 'AKIDEXAMPLE', :api_secret => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'}
70
- end
71
-
72
- describe 'Escher' do
73
- test_suites.each do |suite, tests|
74
- tests.each do |test|
75
- it "should calculate canonicalized request for #{test} in #{suite}" do
76
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_AWS4_OPTIONS)
77
- method, request_uri, body, headers = read_request(suite, test)
78
- headers_to_sign = headers.map {|k| k[0].downcase }
79
- path, query_parts = escher.parse_uri(request_uri)
80
- canonicalized_request = escher.canonicalize(method, path, query_parts, body, headers, headers_to_sign)
81
- check_canonicalized_request(canonicalized_request, suite, test)
82
- end
83
- end
84
- end
85
-
86
- test_suites.each do |suite, tests|
87
- tests.each do |test|
88
- it "should calculate string to sign for #{test} in #{suite}" do
89
- method, request_uri, body, headers, date = read_request(suite, test)
90
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_AWS4_OPTIONS.merge(current_time: Time.parse(date)))
91
- headers_to_sign = headers.map {|k| k[0].downcase }
92
- path, query_parts = escher.parse_uri(request_uri)
93
- canonicalized_request = escher.canonicalize(method, path, query_parts, body, headers, headers_to_sign)
94
- string_to_sign = escher.get_string_to_sign(canonicalized_request)
95
- expect(string_to_sign).to eq(fixture(suite, test, 'sts'))
96
- end
97
- end
98
- end
99
-
100
- test_suites.each do |suite, tests|
101
- tests.each do |test|
102
- it "should calculate auth header for #{test} in #{suite}" do
103
- method, request_uri, body, headers, date = read_request(suite, test)
104
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_AWS4_OPTIONS.merge(current_time: Time.parse(date)))
105
- headers_to_sign = headers.map {|k| k[0].downcase }
106
- auth_header = escher.generate_auth_header(client, method, request_uri, body, headers, headers_to_sign)
107
- expect(auth_header).to eq(fixture(suite, test, 'authz'))
108
- end
109
- end
110
- end
111
-
112
- it 'should sign request' do
113
- escher = Escher.new('us-east-1/iam/aws4_request', ESCHER_EMARSYS_OPTIONS.merge(current_time: Time.parse('20110909T233600Z')))
114
- client = { :api_key_id => 'AKIDEXAMPLE', :api_secret => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' }
115
-
116
- input_headers = {
117
- 'content-type' => 'application/x-www-form-urlencoded; charset=utf-8'
118
- }
119
-
120
- expected_headers = {
121
- 'content-type' => 'application/x-www-form-urlencoded; charset=utf-8',
122
- 'host' => 'iam.amazonaws.com',
123
- 'x-ems-date' => '20110909T233600Z',
124
- 'x-ems-auth' => 'EMS-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-ems-date, Signature=f36c21c6e16a71a6e8dc56673ad6354aeef49c577a22fd58a190b5fcf8891dbd',
125
- }
126
- headers_to_sign = %w(content-type)
127
-
128
- request = {
129
- method: 'POST',
130
- uri: 'http://iam.amazonaws.com/',
131
- body: 'Action=ListUsers&Version=2010-05-08',
132
- headers: input_headers,
133
- }
134
-
135
- downcase = escher.sign!(request, client, headers_to_sign)[:headers].map { |k, v| { k.downcase => v } }.reduce({}, &:merge)
136
- expect(downcase).to eq expected_headers
137
- end
138
-
139
- it 'should generate presigned url' do
140
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/11 12:00:00 UTC')))
141
- expected_url =
142
- 'http://example.com/something?foo=bar&' + 'baz=barbaz&' +
143
- 'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
144
- 'X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&' +
145
- 'X-EMS-Date=20110511T120000Z&' +
146
- 'X-EMS-Expires=123456&' +
147
- 'X-EMS-SignedHeaders=host&' +
148
- 'X-EMS-Signature=fbc9dbb91670e84d04ad2ae7505f4f52ab3ff9e192b8233feeae57e9022c2b67'
149
-
150
- client = {:api_key_id => 'th3K3y', :api_secret => 'very_secure'}
151
- expect(escher.generate_signed_url('http://example.com/something?foo=bar&baz=barbaz', client, 123456)).to eq expected_url
152
- end
153
-
154
- it 'should validate presigned url' do
155
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/12 21:59:00 UTC')))
156
- presigned_uri =
157
- '/something?foo=bar&' + 'baz=barbaz&' +
158
- 'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
159
- 'X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&' +
160
- 'X-EMS-Date=20110511T120000Z&' +
161
- 'X-EMS-Expires=123456&' +
162
- 'X-EMS-SignedHeaders=host&' +
163
- 'X-EMS-Signature=fbc9dbb91670e84d04ad2ae7505f4f52ab3ff9e192b8233feeae57e9022c2b67'
164
-
165
- client = {:api_key_id => 'th3K3y', :api_secret => 'very_secure'}
166
- expect { escher.authenticate({
167
- :method => 'GET',
168
- :headers => [%w(host example.com)],
169
- :uri => presigned_uri,
170
- :body => 'IRRELEVANT'
171
- }, key_db) }.not_to raise_error
172
- end
173
-
174
- it 'should validate expiration' do
175
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/12 22:20:00 UTC')))
176
- presigned_uri =
177
- '/something?foo=bar&' + 'baz=barbaz&' +
178
- 'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
179
- 'X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&' +
180
- 'X-EMS-Date=20110511T120000Z&' +
181
- 'X-EMS-Expires=123456&' +
182
- 'X-EMS-SignedHeaders=host&' +
183
- 'X-EMS-Signature=fbc9dbb91670e84d04ad2ae7505f4f52ab3ff9e192b8233feeae57e9022c2b67'
184
-
185
- client = {:api_key_id => 'th3K3y', :api_secret => 'very_secure'}
186
- expect { escher.authenticate({
187
- :method => 'GET',
188
- :headers => [%w(host example.com)],
189
- :uri => presigned_uri,
190
- :body => 'IRRELEVANT'
191
- }, key_db) }.to raise_error(EscherError, 'The request date is not within the accepted time range')
192
- end
193
-
194
- it 'should validate request' do
195
- headers = [
196
- %w(Host host.foo.com),
197
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
198
- ['Authorization', GOOD_AUTH_HEADER],
199
- ]
200
- expect { call_validate(headers) }.not_to raise_error
201
- end
202
-
203
- it 'should authenticate' do
204
- headers = [
205
- %w(Host host.foo.com),
206
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
207
- ['Authorization', GOOD_AUTH_HEADER],
208
- ]
209
- expect(call_validate(headers)).to eq 'AKIDEXAMPLE'
210
- end
211
-
212
- it 'should detect if signatures do not match' do
213
- headers = [
214
- %w(Host host.foo.com),
215
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
216
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
217
- ]
218
- expect { call_validate(headers) }.to raise_error(EscherError, 'The signatures do not match')
219
- end
220
-
221
- it 'should detect if dates are not on the same day' do
222
- yesterday = '08'
223
- headers = [
224
- %w(Host host.foo.com),
225
- ['Date', "Mon, #{yesterday} Sep 2011 23:36:00 GMT"],
226
- ['Authorization', GOOD_AUTH_HEADER],
227
- ]
228
- expect { call_validate(headers) }.to raise_error(EscherError, 'Invalid request date')
229
- end
230
-
231
- it 'should detect if date is not within the 15 minutes range' do
232
- long_ago = '00'
233
- headers = [
234
- %w(Host host.foo.com),
235
- ['Date', "Mon, 09 Sep 2011 23:#{long_ago}:00 GMT"],
236
- ['Authorization', GOOD_AUTH_HEADER],
237
- ]
238
- expect { call_validate(headers) }.to raise_error(EscherError, 'The request date is not within the accepted time range')
239
- end
240
-
241
- it 'should detect missing host header' do
242
- headers = [
243
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
244
- ['Authorization', GOOD_AUTH_HEADER],
245
- ]
246
- expect { call_validate(headers) }.to raise_error(EscherError, 'Missing header: Host')
247
- end
248
-
249
- it 'should detect missing date header' do
250
- headers = [
251
- %w(Host host.foo.com),
252
- ['Authorization', GOOD_AUTH_HEADER],
253
- ]
254
- expect { call_validate(headers) }.to raise_error(EscherError, 'Missing header: Date')
255
- end
256
-
257
- it 'should detect missing auth header' do
258
- headers = [
259
- %w(Host host.foo.com),
260
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
261
- ]
262
- expect { call_validate(headers) }.to raise_error(EscherError, 'Missing header: Authorization')
263
- end
264
-
265
- it 'should detect malformed auth header' do
266
- headers = [
267
- %w(Host host.foo.com),
268
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
269
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=UNPARSABLE'],
270
- ]
271
- expect { call_validate(headers) }.to raise_error(EscherError, 'Malformed authorization header')
272
- end
273
-
274
- it 'should detect malformed credential scope' do
275
- headers = [
276
- %w(Host host.foo.com),
277
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
278
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=BAD-CREDENTIAL-SCOPE, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'],
279
- ]
280
- expect { call_validate(headers) }.to raise_error(EscherError, 'Malformed authorization header')
281
- end
282
-
283
- it 'should check mandatory signed headers: host' do
284
- headers = [
285
- %w(Host host.foo.com),
286
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
287
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'],
288
- ]
289
- expect { call_validate(headers) }.to raise_error(EscherError, 'Host header is not signed')
290
- end
291
-
292
- it 'should check mandatory signed headers: date' do
293
- headers = [
294
- %w(Host host.foo.com),
295
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
296
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'],
297
- ]
298
- expect { call_validate(headers) }.to raise_error(EscherError, 'Date header is not signed')
299
- end
300
-
301
- it 'should check algorithm' do
302
- headers = [
303
- %w(Host host.foo.com),
304
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
305
- ['Authorization', 'AWS4-HMAC-INVALID Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'],
306
- ]
307
- expect { call_validate(headers) }.to raise_error(EscherError, 'Only SHA256 and SHA512 hash algorithms are allowed')
308
- end
309
-
310
- it 'should check credential scope' do
311
- headers = [
312
- %w(Host host.foo.com),
313
- ['Date', 'Mon, 09 Sep 2011 23:36:00 GMT'],
314
- ['Authorization', 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/INVALID/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'],
315
- ]
316
- expect { call_validate(headers) }.to raise_error(EscherError, 'Invalid credentials')
317
- end
318
-
319
- it 'should convert dates' do
320
- date_str = 'Fri, 09 Sep 2011 23:36:00 GMT'
321
- expect(Escher.new('irrelevant', date_header_name: 'date', current_time: Time.parse(date_str)).format_date_for_header).to eq date_str
322
- end
323
-
324
- def call_validate(headers)
325
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_AWS4_OPTIONS.merge(current_time: Time.parse('Mon, 09 Sep 2011 23:40:00 GMT')))
326
- escher.authenticate({
327
- :method => 'GET',
328
- :headers => headers,
329
- :uri => '/',
330
- :body => '',
331
- }, key_db)
332
- end
333
-
334
- end
335
-
336
- def fixture(suite, test, extension)
337
- open("spec/#{suite}_testsuite/#{test}.#{extension}").read
338
- end
339
-
340
- def get_host(headers)
341
- headers.detect {|header| header[0].downcase == 'host'}[1]
342
- end
343
-
344
- def get_date(headers)
345
- headers.detect {|header| header[0].downcase == 'date'}[1]
346
- end
347
-
348
- def read_request(suite, test, extension = 'req')
349
- lines = (fixture(suite, test, extension) + "\n").lines.map(&:chomp)
350
- method, request_uri = lines[0].split ' '
351
- headers = lines[1..-3].map { |header| k, v = header.split(':', 2); [k, v] }
352
- request_body = lines[-1]
353
- [method, request_uri, request_body, headers, get_date(headers), get_host(headers)]
354
- end
355
-
356
- def check_canonicalized_request(creq, suite, test)
357
- expect(creq).to eq(fixture(suite, test, 'creq'))
358
- end