[CLEANUP] Adjust code to coding guidelines
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Security / Channel / RequestHashServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Security\Channel;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009 Sebastian Kurfürst <sebastian@typo3.org>
8 * All rights reserved
9 *
10 * This class is a backport of the corresponding class of TYPO3 Flow.
11 * All credits go to the TYPO3 Flow team.
12 *
13 * This script is part of the TYPO3 project. The TYPO3 project is
14 * free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * The GNU General Public License can be found at
20 * http://www.gnu.org/copyleft/gpl.html.
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Testcase for the Request Hash Service
31 *
32 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser Public License, version 3 or later
33 */
34 class RequestHashServiceTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
35
36 /**
37 * @return array
38 */
39 public function dataProviderForGenerateRequestHash() {
40 return array(
41 // Simple cases
42 array(
43 array(),
44 array()
45 ),
46 array(
47 array('field1'),
48 array('field1' => 1)
49 ),
50 array(
51 array('field1', 'field2'),
52 array(
53 'field1' => 1,
54 'field2' => 1
55 )
56 ),
57 // recursion
58 array(
59 array('field1', 'field[subfield1]', 'field[subfield2]'),
60 array(
61 'field1' => 1,
62 'field' => array(
63 'subfield1' => 1,
64 'subfield2' => 1
65 )
66 )
67 ),
68 // recursion with duplicated field name
69 array(
70 array('field1', 'field[subfield1]', 'field[subfield2]', 'field1'),
71 array(
72 'field1' => 1,
73 'field' => array(
74 'subfield1' => 1,
75 'subfield2' => 1
76 )
77 )
78 ),
79 // Recursion with un-named fields at the end (...[]). There, they should be made explicit by increasing the counter
80 array(
81 array('field1', 'field[subfield1][]', 'field[subfield1][]', 'field[subfield2]'),
82 array(
83 'field1' => 1,
84 'field' => array(
85 'subfield1' => array(
86 0 => 1,
87 1 => 1
88 ),
89 'subfield2' => 1
90 )
91 )
92 )
93 );
94 }
95
96 /**
97 * Data provider for error cases which should throw an exception
98 *
99 * @return array
100 */
101 public function dataProviderForGenerateRequestHashWithUnallowedValues() {
102 return array(
103 // Overriding form fields (string overridden by array)
104 array(
105 array('field1', 'field2', 'field2[bla]', 'field2[blubb]')
106 ),
107 array(
108 array('field1', 'field2[bla]', 'field2[bla][blubb][blubb]')
109 ),
110 // Overriding form fields (array overridden by string)
111 array(
112 array('field1', 'field2[bla]', 'field2[blubb]', 'field2')
113 ),
114 array(
115 array('field1', 'field2[bla][blubb][blubb]', 'field2[bla]')
116 ),
117 // Empty [] not as last argument
118 array(
119 array('field1', 'field2[][bla]')
120 )
121 );
122 }
123
124 /**
125 * @test
126 * @author Sebastian Kurfürst <sebastian@typo3.org>
127 * @dataProvider dataProviderForGenerateRequestHash
128 * @param mixed $input
129 * @param mixed $expected
130 */
131 public function generateRequestHashGeneratesTheCorrectHashesInNormalOperation($input, $expected) {
132 $requestHashService = $this->getMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('serializeAndHashFormFieldArray'));
133 $requestHashService->expects($this->once())->method('serializeAndHashFormFieldArray')->with($expected);
134 $requestHashService->generateRequestHash($input);
135 }
136
137 /**
138 * @test
139 * @author Sebastian Kurfürst <sebastian@typo3.org>
140 * @dataProvider dataProviderForGenerateRequestHashWithUnallowedValues
141 * @expectedException \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForRequestHashGenerationException
142 * @param mixed $input
143 */
144 public function generateRequestHashThrowsExceptionInWrongCases($input) {
145 $requestHashService = $this->getMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('serializeAndHashFormFieldArray'));
146 $requestHashService->generateRequestHash($input);
147 }
148
149 /**
150 * @test
151 * @author Sebastian Kurfürst <sebastian@typo3.org>
152 */
153 public function serializeAndHashFormFieldArrayWorks() {
154 $formFieldArray = array(
155 'bla' => array(
156 'blubb' => 1,
157 'hu' => 1
158 )
159 );
160 $mockHash = '12345';
161 $hashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Cryptography\\HashService', array('generateHash'));
162 $hashService->expects($this->once())->method('generateHash')->with(serialize($formFieldArray))->will($this->returnValue($mockHash));
163 $requestHashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('dummy'));
164 $requestHashService->_set('hashService', $hashService);
165 $expected = serialize($formFieldArray) . $mockHash;
166 $actual = $requestHashService->_call('serializeAndHashFormFieldArray', $formFieldArray);
167 $this->assertEquals($expected, $actual);
168 }
169
170 /**
171 * @test
172 * @author Sebastian Kurfürst
173 */
174 public function verifyRequestHashSetsHmacVerifiedToFalseIfRequestDoesNotHaveAnHmacArgument() {
175 $request = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request', array('getInternalArgument', 'setHmacVerified'));
176 $request->expects($this->any())->method('getInternalArgument')->with('__hmac')->will($this->returnValue(FALSE));
177 $request->expects($this->once())->method('setHmacVerified')->with(FALSE);
178 $requestHashService = new \TYPO3\CMS\Extbase\Security\Channel\RequestHashService();
179 $requestHashService->verifyRequest($request);
180 }
181
182 /**
183 * @test
184 * @expectedException \TYPO3\CMS\Extbase\Security\Exception\SyntacticallyWrongRequestHashException
185 * @author Sebastian Kurfürst
186 */
187 public function verifyRequestHashThrowsExceptionIfHmacIsShortherThan40Characters() {
188 $request = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request', array('getInternalArgument', 'setHmacVerified'));
189 $request->expects($this->any())->method('getInternalArgument')->with('__hmac')->will($this->returnValue('abc'));
190 $requestHashService = new \TYPO3\CMS\Extbase\Security\Channel\RequestHashService();
191 $requestHashService->verifyRequest($request);
192 }
193
194 /**
195 * @test
196 * @author Sebastian Kurfürst
197 */
198 public function verifyRequestHashValidatesTheHashAndSetsHmacVerifiedToFalseIfHashCouldNotBeVerified() {
199 $request = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request', array('getInternalArgument', 'setHmacVerified'));
200 $request->expects($this->any())->method('getInternalArgument')->with('__hmac')->will($this->returnValue('11111' . '0000000000000000000000000000000000000000'));
201 $request->expects($this->once())->method('setHmacVerified')->with(FALSE);
202 $hashService = $this->getMock('TYPO3\\CMS\\Extbase\\Security\\Cryptography\\HashService', array('validateHash'));
203 $hashService->expects($this->once())->method('validateHash')->with('11111', '0000000000000000000000000000000000000000')->will($this->returnValue(FALSE));
204 $requestHashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('dummy'));
205 $requestHashService->_set('hashService', $hashService);
206 $requestHashService->verifyRequest($request);
207 }
208
209 /**
210 * @test
211 * @author Sebastian Kurfürst
212 */
213 public function verifyRequestHashValidatesTheHashAndSetsHmacVerifiedToTrueIfArgumentsAreIncludedInTheAllowedArgumentList() {
214 $data = serialize(array('a' => 1));
215 $request = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request', array('getInternalArgument', 'getArguments', 'setHmacVerified'));
216 $request->expects($this->any())->method('getInternalArgument')->with('__hmac')->will($this->returnValue($data . '0000000000000000000000000000000000000000'));
217 $request->expects($this->once())->method('getArguments')->will($this->returnValue(array(
218 '__hmac' => 'ABC',
219 '__referrer' => '...',
220 'a' => 'bla'
221 )));
222 $request->expects($this->once())->method('setHmacVerified')->with(TRUE);
223 $hashService = $this->getMock('TYPO3\\CMS\\Extbase\\Security\\Cryptography\\HashService', array('validateHash'));
224 $hashService->expects($this->once())->method('validateHash')->with($data, '0000000000000000000000000000000000000000')->will($this->returnValue(TRUE));
225 $requestHashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('checkFieldNameInclusion'));
226 $requestHashService->expects($this->once())->method('checkFieldNameInclusion')->with(array('a' => 'bla'), array('a' => 1))->will($this->returnValue(TRUE));
227 $requestHashService->_set('hashService', $hashService);
228 $requestHashService->verifyRequest($request);
229 }
230
231 /**
232 * @test
233 * @author Sebastian Kurfürst
234 */
235 public function verifyRequestHashValidatesTheHashAndSetsHmacVerifiedToFalseIfNotAllArgumentsAreIncludedInTheAllowedArgumentList() {
236 $data = serialize(array('a' => 1));
237 $request = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Web\\Request', array('getInternalArgument', 'getArguments', 'setHmacVerified'));
238 $request->expects($this->any())->method('getInternalArgument')->with('__hmac')->will($this->returnValue($data . '0000000000000000000000000000000000000000'));
239 $request->expects($this->once())->method('getArguments')->will($this->returnValue(array(
240 '__hmac' => 'ABC',
241 '__referrer' => '...',
242 'a' => 'bla',
243 'b' => 'blubb'
244 )));
245 $request->expects($this->once())->method('setHmacVerified')->with(FALSE);
246 $hashService = $this->getMock('TYPO3\\CMS\\Extbase\\Security\\Cryptography\\HashService', array('validateHash'));
247 $hashService->expects($this->once())->method('validateHash')->with($data, '0000000000000000000000000000000000000000')->will($this->returnValue(TRUE));
248 $requestHashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('checkFieldNameInclusion'));
249 $requestHashService->expects($this->once())->method('checkFieldNameInclusion')->with(array('a' => 'bla', 'b' => 'blubb'), array('a' => 1))->will($this->returnValue(FALSE));
250 $requestHashService->_set('hashService', $hashService);
251 $requestHashService->verifyRequest($request);
252 }
253
254 /**
255 * Data Provider for checkFieldNameInclusionWorks
256 *
257 * @return array
258 */
259 public function dataProviderForCheckFieldNameInclusion() {
260 return array(
261 // Simple fields with requestfields = responsefields
262 array(
263 // Request
264 array(
265 'a' => 'X',
266 'b' => 'X',
267 'c' => 'X'
268 ),
269 // Allowed
270 array(
271 'a' => 1,
272 'b' => 1,
273 'c' => 1
274 ),
275 // Expected result
276 TRUE
277 ),
278 // Simple fields with requestfields < responsefields
279 array(
280 // Request
281 array(
282 'a' => 'X',
283 'c' => 'X'
284 ),
285 // Allowed
286 array(
287 'a' => 1,
288 'b' => 1,
289 'c' => 1
290 ),
291 // Expected result
292 TRUE
293 ),
294 // Simple fields with requestfields > responsefields
295 array(
296 // Request
297 array(
298 'a' => 'X',
299 'b' => 'X',
300 'c' => 'X'
301 ),
302 // Allowed
303 array(
304 'a' => 1,
305 'b' => 1
306 ),
307 // Expected result
308 FALSE
309 ),
310 // Hierarchical fields with requestfields < responsefields
311 array(
312 // Request
313 array(
314 'a' => array(
315 'b' => 'X'
316 ),
317 'c' => 'X'
318 ),
319 // Allowed
320 array(
321 'a' => array(
322 'b' => 1,
323 'abc' => 1
324 ),
325 'c' => 1
326 ),
327 // Expected result
328 TRUE
329 ),
330 // Hierarchical fields with requestfields > responsefields
331 array(
332 // Request
333 array(
334 'a' => array(
335 'b' => 'X',
336 'abc' => 'X'
337 ),
338 'c' => 'X'
339 ),
340 // Allowed
341 array(
342 'a' => array(
343 'b' => 1
344 ),
345 'c' => 1
346 ),
347 // Expected result
348 FALSE
349 ),
350 // hierarchical fields with requestfields != responsefields (different types) - 1
351 array(
352 // Request
353 array(
354 'a' => array(
355 'b' => 'X',
356 'c' => 'X'
357 ),
358 'b' => 'X',
359 'c' => 'X'
360 ),
361 // Allowed
362 array(
363 'a' => 1,
364 'b' => 1,
365 'c' => 1
366 ),
367 // Expected result
368 FALSE
369 ),
370 // hierarchical fields with requestfields != responsefields (different types) - 2
371 array(
372 // Request
373 array(
374 'a' => 'X',
375 'b' => 'X',
376 'c' => 'X'
377 ),
378 // Allowed
379 array(
380 'a' => array(
381 'x' => 1,
382 'y' => 1
383 ),
384 'b' => 1,
385 'c' => 1
386 ),
387 // Expected result
388 FALSE
389 ),
390 // hierarchical fields with requestfields != responsefields (different types)
391 // This case happens if an array of checkboxes is rendered, in case they are fully unchecked.
392 array(
393 // Request
394 array(
395 'a' => '',
396 // this is the only allowed value.
397 'b' => 'X',
398 'c' => 'X'
399 ),
400 // Allowed
401 array(
402 'a' => array(
403 'x' => 1,
404 'y' => 1
405 ),
406 'b' => 1,
407 'c' => 1
408 ),
409 // Expected result
410 TRUE
411 )
412 );
413 }
414
415 /**
416 * @test
417 * @author Sebastian Kurfürst <sebastian@typo3.org>
418 * @dataProvider dataProviderForCheckFieldNameInclusion
419 * @param mixed $requestArguments
420 * @param mixed $allowedFields
421 * @param mixed $expectedResult
422 */
423 public function checkFieldNameInclusionWorks($requestArguments, $allowedFields, $expectedResult) {
424 $requestHashService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Security\\Channel\\RequestHashService', array('dummy'));
425 $this->assertEquals($expectedResult, $requestHashService->_call('checkFieldNameInclusion', $requestArguments, $allowedFields));
426 }
427 }
428
429 ?>