api-auth 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -2
  3. data/.travis.yml +4 -0
  4. data/Appraisals +6 -0
  5. data/CHANGELOG.md +36 -0
  6. data/Gemfile.lock +77 -44
  7. data/README.md +15 -8
  8. data/VERSION +1 -1
  9. data/api_auth.gemspec +4 -4
  10. data/gemfiles/rails_23.gemfile +1 -1
  11. data/gemfiles/rails_23.gemfile.lock +19 -11
  12. data/gemfiles/rails_30.gemfile +1 -1
  13. data/gemfiles/rails_30.gemfile.lock +19 -11
  14. data/gemfiles/rails_31.gemfile +1 -1
  15. data/gemfiles/rails_31.gemfile.lock +19 -11
  16. data/gemfiles/rails_32.gemfile +1 -1
  17. data/gemfiles/rails_32.gemfile.lock +19 -11
  18. data/gemfiles/rails_4.gemfile +1 -1
  19. data/gemfiles/rails_4.gemfile.lock +19 -11
  20. data/gemfiles/rails_41.gemfile +1 -1
  21. data/gemfiles/rails_41.gemfile.lock +19 -11
  22. data/gemfiles/rails_42.gemfile +9 -0
  23. data/gemfiles/rails_42.gemfile.lock +115 -0
  24. data/lib/api_auth/base.rb +37 -23
  25. data/lib/api_auth/headers.rb +23 -3
  26. data/lib/api_auth/request_drivers/action_controller.rb +4 -0
  27. data/lib/api_auth/request_drivers/curb.rb +4 -0
  28. data/lib/api_auth/request_drivers/faraday.rb +4 -0
  29. data/lib/api_auth/request_drivers/httpi.rb +5 -1
  30. data/lib/api_auth/request_drivers/net_http.rb +4 -0
  31. data/lib/api_auth/request_drivers/rack.rb +5 -1
  32. data/lib/api_auth/request_drivers/rest_client.rb +4 -0
  33. data/spec/api_auth_spec.rb +112 -628
  34. data/spec/headers_spec.rb +132 -289
  35. data/spec/helpers_spec.rb +2 -2
  36. data/spec/railtie_spec.rb +13 -8
  37. data/spec/request_drivers/action_controller_spec.rb +218 -0
  38. data/spec/request_drivers/action_dispatch_spec.rb +219 -0
  39. data/spec/request_drivers/curb_spec.rb +89 -0
  40. data/spec/request_drivers/faraday_spec.rb +243 -0
  41. data/spec/request_drivers/httpi_spec.rb +147 -0
  42. data/spec/request_drivers/net_http_spec.rb +185 -0
  43. data/spec/request_drivers/rack_spec.rb +288 -0
  44. data/spec/request_drivers/rest_client_spec.rb +311 -0
  45. metadata +44 -19
  46. data/spec/application_helper.rb +0 -2
  47. data/spec/test_helper.rb +0 -2
@@ -2,337 +2,180 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe ApiAuth::Headers do
4
4
 
5
- CANONICAL_STRING = "text/plain,e59ff97941044f85df5297e1c302d260,/resource.xml?foo=bar&bar=foo,Mon, 23 Jan 1984 03:29:56 GMT"
6
-
7
- describe "with Net::HTTP::Put::Multipart" do
8
-
9
- before(:each) do
10
- request = Net::HTTP::Put::Multipart.new("/resource.xml?foo=bar&bar=foo",
11
- 'file' => UploadIO.new(File.new('spec/fixtures/upload.png'), 'image/png', 'upload.png'))
12
- ApiAuth.sign!(request, "some access id", "some secret key")
13
- @headers = ApiAuth::Headers.new(request)
14
- end
15
-
16
- it "should set the content-type" do
17
- @headers.canonical_string.split(',')[0].should match 'multipart/form-data; boundary='
18
- end
19
-
20
- it "should generate the proper content-md5" do
21
- @headers.canonical_string.split(',')[1].should match 'zap0d6zuh6wRBSrsvO2bcw=='
22
- end
23
-
24
- end
25
-
26
- describe "with Net::HTTP" do
27
-
28
- before(:each) do
29
- @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
30
- 'content-type' => 'text/plain',
31
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260',
32
- 'date' => "Mon, 23 Jan 1984 03:29:56 GMT")
33
- @headers = ApiAuth::Headers.new(@request)
34
- end
5
+ describe '#canonical_string' do
6
+ context "uri edge cases" do
7
+ let(:request) { RestClient::Request.new(:url => uri, :method => :get) }
8
+ subject(:headers) { described_class.new(request) }
9
+ let(:uri) { '' }
35
10
 
36
- it "should generate the proper canonical string" do
37
- @headers.canonical_string.should == CANONICAL_STRING
38
- end
11
+ context 'empty uri' do
12
+ let(:uri) { ''.freeze }
39
13
 
40
- it "should set the authorization header" do
41
- @headers.sign_header("alpha")
42
- @headers.authorization_header.should == "alpha"
43
- end
14
+ it 'adds / to canonical string' do
15
+ expect(subject.canonical_string).to eq(',,/,')
16
+ end
17
+ end
44
18
 
45
- it "should set the DATE header if one is not already present" do
46
- @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
47
- 'content-type' => 'text/plain',
48
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
49
- ApiAuth.sign!(@request, "some access id", "some secret key")
50
- @request['DATE'].should_not be_nil
51
- end
19
+ context 'uri with just host without /' do
20
+ let(:uri) { 'http://google.com'.freeze }
52
21
 
53
- it "should not set the DATE header just by asking for the canonical_string" do
54
- request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
55
- 'content-type' => 'text/plain',
56
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
57
- headers = ApiAuth::Headers.new(request)
58
- headers.canonical_string
59
- request['DATE'].should be_nil
60
- end
22
+ it 'return / as canonical string path' do
23
+ expect(subject.canonical_string).to eq(',,/,')
24
+ end
61
25
 
62
- context "md5_mismatch?" do
63
- it "is false if no md5 header is present" do
64
- request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
65
- 'content-type' => 'text/plain')
66
- headers = ApiAuth::Headers.new(request)
67
- headers.md5_mismatch?.should be_false
26
+ it 'does not change request url (by removing host)' do
27
+ expect(request.url).to eq(uri)
28
+ end
68
29
  end
69
- end
70
- end
71
30
 
72
- describe "with RestClient" do
73
-
74
- before(:each) do
75
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
76
- 'Content-Type' => "text/plain",
77
- 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
78
- @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
79
- :headers => headers,
80
- :method => :put)
81
- @headers = ApiAuth::Headers.new(@request)
82
- end
83
-
84
- it "should generate the proper canonical string" do
85
- @headers.canonical_string.should == CANONICAL_STRING
86
- end
31
+ context 'uri with host and /' do
32
+ let(:uri) { 'http://google.com/'.freeze }
87
33
 
88
- it "should set the authorization header" do
89
- @headers.sign_header("alpha")
90
- @headers.authorization_header.should == "alpha"
91
- end
34
+ it 'return / as canonical string path' do
35
+ expect(subject.canonical_string).to eq(',,/,')
36
+ end
92
37
 
93
- it "should set the DATE header if one is not already present" do
94
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
95
- 'Content-Type' => "text/plain" }
96
- @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
97
- :headers => headers,
98
- :method => :put)
99
- ApiAuth.sign!(@request, "some access id", "some secret key")
100
- @request.headers['DATE'].should_not be_nil
38
+ it 'does not change request url (by removing host)' do
39
+ expect(request.url).to eq(uri)
40
+ end
41
+ end
101
42
  end
102
43
 
103
- it "should not set the DATE header just by asking for the canonical_string" do
104
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
105
- 'Content-Type' => "text/plain" }
106
- request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
107
- :headers => headers,
108
- :method => :put)
109
- headers = ApiAuth::Headers.new(request)
110
- headers.canonical_string
111
- request.headers['DATE'].should be_nil
112
- end
44
+ context "string construction" do
45
+ let(:request){ RestClient::Request.new(:url => "http://google.com", :method => :get) }
46
+ subject(:headers) { described_class.new(request) }
47
+ let(:driver){ headers.instance_variable_get("@request")}
113
48
 
114
- it "doesn't mess up symbol based headers" do
115
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
116
- :content_type => "text/plain",
117
- 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
118
- @request = RestClient::Request.new(:url => "/resource.xml?foo=bar&bar=foo",
119
- :headers => headers,
120
- :method => :put)
121
- @headers = ApiAuth::Headers.new(@request)
122
- ApiAuth.sign!(@request, "some access id", "some secret key")
123
- @request.processed_headers.should have_key('Content-Type')
49
+ it "puts the canonical string together correctly" do
50
+ allow(driver).to receive(:content_type).and_return "text/html"
51
+ allow(driver).to receive(:content_md5).and_return "12345"
52
+ allow(driver).to receive(:request_uri).and_return "/foo"
53
+ allow(driver).to receive(:timestamp).and_return "Mon, 23 Jan 1984 03:29:56 GMT"
54
+ expect(headers.canonical_string).to eq "text/html,12345,/foo,Mon, 23 Jan 1984 03:29:56 GMT"
55
+ end
124
56
  end
125
57
  end
126
58
 
127
- describe "with Curb" do
128
-
129
- before(:each) do
130
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
131
- 'Content-Type' => "text/plain",
132
- 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT" }
133
- @request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
134
- curl.headers = headers
59
+ describe "#canonical_string_with_http_method" do
60
+ context "with a driver that supplies http_method" do
61
+ let(:request){ RestClient::Request.new(:url => "http://google.com", :method => :get) }
62
+ subject(:headers) { described_class.new(request) }
63
+ let(:driver){ headers.instance_variable_get("@request")}
64
+
65
+ before do
66
+ allow(driver).to receive(:http_method).and_return "GET"
67
+ allow(driver).to receive(:content_type).and_return "text/html"
68
+ allow(driver).to receive(:content_md5).and_return "12345"
69
+ allow(driver).to receive(:request_uri).and_return "/foo"
70
+ allow(driver).to receive(:timestamp).and_return "Mon, 23 Jan 1984 03:29:56 GMT"
135
71
  end
136
- @headers = ApiAuth::Headers.new(@request)
137
- end
138
-
139
- it "should generate the proper canonical string" do
140
- @headers.canonical_string.should == CANONICAL_STRING
141
- end
142
72
 
143
- it "should set the authorization header" do
144
- @headers.sign_header("alpha")
145
- @headers.authorization_header.should == "alpha"
146
- end
147
-
148
- it "should set the DATE header if one is not already present" do
149
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
150
- 'Content-Type' => "text/plain" }
151
- @request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
152
- curl.headers = headers
73
+ context "when not passed an override" do
74
+ it "constructs the canonical_string with the driver's http method" do
75
+ expect(headers.canonical_string_with_http_method).to eq "GET,text/html,12345,/foo,Mon, 23 Jan 1984 03:29:56 GMT"
76
+ end
153
77
  end
154
- ApiAuth.sign!(@request, "some access id", "some secret key")
155
- @request.headers['DATE'].should_not be_nil
156
- end
157
78
 
158
- it "should not set the DATE header just by asking for the canonical_string" do
159
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
160
- 'Content-Type' => "text/plain" }
161
- request = Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
162
- curl.headers = headers
79
+ context "when passed an override" do
80
+ it "constructs the canonical_string with the overridden http method" do
81
+ expect(headers.canonical_string_with_http_method("put")).to eq "PUT,text/html,12345,/foo,Mon, 23 Jan 1984 03:29:56 GMT"
82
+ end
163
83
  end
164
- headers = ApiAuth::Headers.new(request)
165
- headers.canonical_string
166
- request.headers['DATE'].should be_nil
167
- end
168
- end
169
-
170
- describe "with ActionController" do
171
-
172
- let(:request_klass){ ActionDispatch::Request rescue ActionController::Request }
173
-
174
- before(:each) do
175
- @request = request_klass.new(
176
- 'PATH_INFO' => '/resource.xml',
177
- 'QUERY_STRING' => 'foo=bar&bar=foo',
178
- 'REQUEST_METHOD' => 'PUT',
179
- 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
180
- 'CONTENT_TYPE' => 'text/plain',
181
- 'HTTP_DATE' => 'Mon, 23 Jan 1984 03:29:56 GMT')
182
- @headers = ApiAuth::Headers.new(@request)
183
84
  end
184
85
 
185
- it "should generate the proper canonical string" do
186
- @headers.canonical_string.should == CANONICAL_STRING
187
- end
188
-
189
- it "should set the authorization header" do
190
- @headers.sign_header("alpha")
191
- @headers.authorization_header.should == "alpha"
192
- end
86
+ context "when a driver that doesn't supply http_method" do
87
+ let(:request) do
88
+ Curl::Easy.new("/resource.xml?foo=bar&bar=foo") do |curl|
89
+ curl.headers = { 'Content-Type' => "text/plain" }
90
+ end
91
+ end
92
+ subject(:headers) { described_class.new(request) }
93
+ let(:driver){ headers.instance_variable_get("@request")}
94
+
95
+ before do
96
+ allow(driver).to receive(:http_method).and_return nil
97
+ allow(driver).to receive(:content_type).and_return "text/html"
98
+ allow(driver).to receive(:content_md5).and_return "12345"
99
+ allow(driver).to receive(:request_uri).and_return "/foo"
100
+ allow(driver).to receive(:timestamp).and_return "Mon, 23 Jan 1984 03:29:56 GMT"
101
+ end
193
102
 
194
- it "should set the DATE header if one is not already present" do
195
- @request = request_klass.new(
196
- 'PATH_INFO' => '/resource.xml',
197
- 'QUERY_STRING' => 'foo=bar&bar=foo',
198
- 'REQUEST_METHOD' => 'PUT',
199
- 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
200
- 'CONTENT_TYPE' => 'text/plain')
201
- ApiAuth.sign!(@request, "some access id", "some secret key")
202
- @request.headers['DATE'].should_not be_nil
203
- end
103
+ context "when not passed an override" do
104
+ it "raises an error" do
105
+ expect{ headers.canonical_string_with_http_method }.to raise_error(ArgumentError)
106
+ end
107
+ end
204
108
 
205
- it "should not set the DATE header just by asking for the canonical_string" do
206
- request = request_klass.new(
207
- 'PATH_INFO' => '/resource.xml',
208
- 'QUERY_STRING' => 'foo=bar&bar=foo',
209
- 'REQUEST_METHOD' => 'PUT',
210
- 'CONTENT_MD5' => 'e59ff97941044f85df5297e1c302d260',
211
- 'CONTENT_TYPE' => 'text/plain')
212
- headers = ApiAuth::Headers.new(request)
213
- headers.canonical_string
214
- request.headers['DATE'].should be_nil
109
+ context "when passed an override" do
110
+ it "constructs the canonical_string with the overridden http method" do
111
+ expect(headers.canonical_string_with_http_method("put")).to eq "PUT,text/html,12345,/foo,Mon, 23 Jan 1984 03:29:56 GMT"
112
+ end
113
+ end
215
114
  end
216
115
  end
217
116
 
218
- describe "with Rack::Request" do
219
-
220
- before(:each) do
221
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
222
- 'Content-Type' => "text/plain",
223
- 'Date' => "Mon, 23 Jan 1984 03:29:56 GMT"
224
- }
225
- @request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
226
- @headers = ApiAuth::Headers.new(@request)
227
- end
228
-
229
- it "should generate the proper canonical string" do
230
- @headers.canonical_string.should == CANONICAL_STRING
231
- end
232
-
233
- it "should set the authorization header" do
234
- @headers.sign_header("alpha")
235
- @headers.authorization_header.should == "alpha"
117
+ describe '#calculate_md5' do
118
+ subject(:headers){ described_class.new(request) }
119
+ let(:driver){ headers.instance_variable_get("@request")}
120
+
121
+ context "no md5 already calculated" do
122
+ let(:request) {
123
+ RestClient::Request.new(
124
+ :url => 'http://google.com',
125
+ :method => :post,
126
+ :payload => "hello\nworld"
127
+ )
128
+ }
129
+
130
+ it "populates the md5 header" do
131
+ expect(driver).to receive(:populate_content_md5)
132
+ headers.calculate_md5
133
+ end
236
134
  end
237
135
 
238
- it "should set the DATE header if one is not already present" do
239
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
240
- 'Content-Type' => "text/plain" }
241
- @request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
242
- ApiAuth.sign!(@request, "some access id", "some secret key")
243
- @request.env['DATE'].should_not be_nil
244
- end
136
+ context "md5 already calculated" do
137
+ let(:request) {
138
+ RestClient::Request.new(
139
+ :url => 'http://google.com',
140
+ :method => :post,
141
+ :payload => "hello\nworld",
142
+ :headers => {:content_md5 => "abcd"}
143
+ )
144
+ }
245
145
 
246
- it "should not set the DATE header just by asking for the canonical_string" do
247
- headers = { 'Content-MD5' => "e59ff97941044f85df5297e1c302d260",
248
- 'Content-Type' => "text/plain" }
249
- request = Rack::Request.new(Rack::MockRequest.env_for("/resource.xml?foo=bar&bar=foo", :method => :put).merge!(headers))
250
- headers = ApiAuth::Headers.new(request)
251
- headers.canonical_string
252
- request.env['DATE'].should be_nil
146
+ it "doesn't populate the md5 header" do
147
+ expect(driver).not_to receive(:populate_content_md5)
148
+ headers.calculate_md5
149
+ end
253
150
  end
254
151
  end
255
152
 
256
- describe "with HTTPI" do
257
- before(:each) do
258
- @request = HTTPI::Request.new("http://localhost/resource.xml?foo=bar&bar=foo")
259
- @request.headers.merge!({
260
- 'content-type' => 'text/plain',
261
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260',
262
- 'date' => "Mon, 23 Jan 1984 03:29:56 GMT"
263
- })
264
- @headers = ApiAuth::Headers.new(@request)
265
- end
266
-
267
- it "should generate the proper canonical string" do
268
- @headers.canonical_string.should == CANONICAL_STRING
269
- end
270
-
271
- it "should set the authorization header" do
272
- @headers.sign_header("alpha")
273
- @headers.authorization_header.should == "alpha"
274
- end
275
-
276
- it "should set the DATE header if one is not already present" do
277
- @request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
278
- 'content-type' => 'text/plain',
279
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
280
- ApiAuth.sign!(@request, "some access id", "some secret key")
281
- @request['DATE'].should_not be_nil
282
- end
283
-
284
- it "should not set the DATE header just by asking for the canonical_string" do
285
- request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
286
- 'content-type' => 'text/plain',
287
- 'content-md5' => 'e59ff97941044f85df5297e1c302d260')
288
- headers = ApiAuth::Headers.new(request)
289
- headers.canonical_string
290
- request['DATE'].should be_nil
291
- end
292
-
293
- context "md5_mismatch?" do
294
- it "is false if no md5 header is present" do
295
- request = Net::HTTP::Put.new("/resource.xml?foo=bar&bar=foo",
296
- 'content-type' => 'text/plain')
297
- headers = ApiAuth::Headers.new(request)
298
- headers.md5_mismatch?.should be_false
299
- end
300
- end
301
- end
153
+ describe "#md5_mismatch?" do
154
+ let(:request){ RestClient::Request.new(:url => "http://google.com", :method => :get) }
155
+ subject(:headers){ described_class.new(request) }
156
+ let(:driver){ headers.instance_variable_get("@request") }
302
157
 
303
- describe '#canonical_string' do
304
- let(:request) { RestClient::Request.new(:url => uri, :method => :get) }
305
- subject { described_class.new(request) }
306
-
307
- context 'empty uri' do
308
- let(:uri) { ''.freeze }
158
+ context "when request has md5 header" do
159
+ it "asks the driver" do
160
+ allow(driver).to receive(:content_md5).and_return "1234"
309
161
 
310
- it 'adds / to canonical string' do
311
- subject.canonical_string.should eq(',,/,')
162
+ expect(driver).to receive(:md5_mismatch?).and_call_original
163
+ headers.md5_mismatch?
312
164
  end
313
165
  end
314
166
 
315
- context 'uri with just host without /' do
316
- let(:uri) { 'http://google.com'.freeze }
167
+ context "when request has no md5" do
168
+ it "doesn't ask the driver" do
169
+ allow(driver).to receive(:content_md5).and_return ""
317
170
 
318
- it 'return / as canonical string path' do
319
- subject.canonical_string.should eq(',,/,')
171
+ expect(driver).not_to receive(:md5_mismatch?).and_call_original
172
+ headers.md5_mismatch?
320
173
  end
321
174
 
322
- it 'does not change request url (by removing host)' do
323
- request.url.should eq(uri)
324
- end
325
- end
326
-
327
- context 'uri with host and /' do
328
- let(:uri) { 'http://google.com/'.freeze }
329
-
330
- it 'return / as canonical string path' do
331
- subject.canonical_string.should eq(',,/,')
332
- end
175
+ it "returns false" do
176
+ allow(driver).to receive(:content_md5).and_return ""
333
177
 
334
- it 'does not change request url (by removing host)' do
335
- request.url.should eq(uri)
178
+ expect(headers.md5_mismatch?).to be false
336
179
  end
337
180
  end
338
181
  end