api-auth 1.3.2 → 1.4.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.
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