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.
- checksums.yaml +4 -4
- data/.rspec +2 -2
- data/.travis.yml +4 -0
- data/Appraisals +6 -0
- data/CHANGELOG.md +36 -0
- data/Gemfile.lock +77 -44
- data/README.md +15 -8
- data/VERSION +1 -1
- data/api_auth.gemspec +4 -4
- data/gemfiles/rails_23.gemfile +1 -1
- data/gemfiles/rails_23.gemfile.lock +19 -11
- data/gemfiles/rails_30.gemfile +1 -1
- data/gemfiles/rails_30.gemfile.lock +19 -11
- data/gemfiles/rails_31.gemfile +1 -1
- data/gemfiles/rails_31.gemfile.lock +19 -11
- data/gemfiles/rails_32.gemfile +1 -1
- data/gemfiles/rails_32.gemfile.lock +19 -11
- data/gemfiles/rails_4.gemfile +1 -1
- data/gemfiles/rails_4.gemfile.lock +19 -11
- data/gemfiles/rails_41.gemfile +1 -1
- data/gemfiles/rails_41.gemfile.lock +19 -11
- data/gemfiles/rails_42.gemfile +9 -0
- data/gemfiles/rails_42.gemfile.lock +115 -0
- data/lib/api_auth/base.rb +37 -23
- data/lib/api_auth/headers.rb +23 -3
- data/lib/api_auth/request_drivers/action_controller.rb +4 -0
- data/lib/api_auth/request_drivers/curb.rb +4 -0
- data/lib/api_auth/request_drivers/faraday.rb +4 -0
- data/lib/api_auth/request_drivers/httpi.rb +5 -1
- data/lib/api_auth/request_drivers/net_http.rb +4 -0
- data/lib/api_auth/request_drivers/rack.rb +5 -1
- data/lib/api_auth/request_drivers/rest_client.rb +4 -0
- data/spec/api_auth_spec.rb +112 -628
- data/spec/headers_spec.rb +132 -289
- data/spec/helpers_spec.rb +2 -2
- data/spec/railtie_spec.rb +13 -8
- data/spec/request_drivers/action_controller_spec.rb +218 -0
- data/spec/request_drivers/action_dispatch_spec.rb +219 -0
- data/spec/request_drivers/curb_spec.rb +89 -0
- data/spec/request_drivers/faraday_spec.rb +243 -0
- data/spec/request_drivers/httpi_spec.rb +147 -0
- data/spec/request_drivers/net_http_spec.rb +185 -0
- data/spec/request_drivers/rack_spec.rb +288 -0
- data/spec/request_drivers/rest_client_spec.rb +311 -0
- metadata +44 -19
- data/spec/application_helper.rb +0 -2
- data/spec/test_helper.rb +0 -2
data/spec/headers_spec.rb
CHANGED
@@ -2,337 +2,180 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe ApiAuth::Headers do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
37
|
-
|
38
|
-
end
|
11
|
+
context 'empty uri' do
|
12
|
+
let(:uri) { ''.freeze }
|
39
13
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
14
|
+
it 'adds / to canonical string' do
|
15
|
+
expect(subject.canonical_string).to eq(',,/,')
|
16
|
+
end
|
17
|
+
end
|
44
18
|
|
45
|
-
|
46
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
34
|
+
it 'return / as canonical string path' do
|
35
|
+
expect(subject.canonical_string).to eq(',,/,')
|
36
|
+
end
|
92
37
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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 "
|
128
|
-
|
129
|
-
|
130
|
-
headers
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
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
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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 "
|
257
|
-
|
258
|
-
|
259
|
-
|
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
|
-
|
304
|
-
|
305
|
-
|
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
|
-
|
311
|
-
|
162
|
+
expect(driver).to receive(:md5_mismatch?).and_call_original
|
163
|
+
headers.md5_mismatch?
|
312
164
|
end
|
313
165
|
end
|
314
166
|
|
315
|
-
context
|
316
|
-
|
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
|
-
|
319
|
-
|
171
|
+
expect(driver).not_to receive(:md5_mismatch?).and_call_original
|
172
|
+
headers.md5_mismatch?
|
320
173
|
end
|
321
174
|
|
322
|
-
it
|
323
|
-
|
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
|
-
|
335
|
-
request.url.should eq(uri)
|
178
|
+
expect(headers.md5_mismatch?).to be false
|
336
179
|
end
|
337
180
|
end
|
338
181
|
end
|