|
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 | 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 | 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 | 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 | 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 |
|
153 | 182 | context 'when putting' do |
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 | 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 commit comments