[!!!][TASK] Extract testing framework for TYPO3
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Mvc / Controller / MvcPropertyMappingConfigurationServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Mvc\Controller;
3
4 /* *
5 * This script belongs to the Extbase framework *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 use TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException;
24
25 /**
26 * Test case
27 */
28 class MvcPropertyMappingConfigurationServiceTest extends \TYPO3\CMS\Components\TestingFramework\Core\UnitTestCase
29 {
30 /**
31 * Data provider for generating the list of trusted properties
32 *
33 * @return array
34 */
35 public function dataProviderForgenerateTrustedPropertiesToken()
36 {
37 return [
38 'Simple Case - Empty' => [
39 [],
40 [],
41 ],
42 'Simple Case - Single Value' => [
43 ['field1'],
44 ['field1' => 1],
45 ],
46 'Simple Case - Two Values' => [
47 ['field1', 'field2'],
48 [
49 'field1' => 1,
50 'field2' => 1
51 ],
52 ],
53 'Recursion' => [
54 ['field1', 'field[subfield1]', 'field[subfield2]'],
55 [
56 'field1' => 1,
57 'field' => [
58 'subfield1' => 1,
59 'subfield2' => 1
60 ]
61 ],
62 ],
63 'recursion with duplicated field name' => [
64 ['field1', 'field[subfield1]', 'field[subfield2]', 'field1'],
65 [
66 'field1' => 1,
67 'field' => [
68 'subfield1' => 1,
69 'subfield2' => 1
70 ]
71 ],
72 ],
73 'Recursion with un-named fields at the end (...[]). There, they should be made explicit by increasing the counter' => [
74 ['field1', 'field[subfield1][]', 'field[subfield1][]', 'field[subfield2]'],
75 [
76 'field1' => 1,
77 'field' => [
78 'subfield1' => [
79 0 => 1,
80 1 => 1
81 ],
82 'subfield2' => 1
83 ]
84 ],
85 ],
86 ];
87 }
88
89 /**
90 * Data Provider for invalid values in generating the list of trusted properties,
91 * which should result in an exception
92 *
93 * @return array
94 */
95 public function dataProviderForgenerateTrustedPropertiesTokenWithUnallowedValues()
96 {
97 return [
98 'Overriding form fields (string overridden by array) - 1' => [
99 ['field1', 'field2', 'field2[bla]', 'field2[blubb]'],
100 1255072196
101 ],
102 'Overriding form fields (string overridden by array) - 2' => [
103 ['field1', 'field2[bla]', 'field2[bla][blubb][blubb]'],
104 1255072196
105 ],
106 'Overriding form fields (array overridden by string) - 1' => [
107 ['field1', 'field2[bla]', 'field2[blubb]', 'field2'],
108 1255072587
109 ],
110 'Overriding form fields (array overridden by string) - 2' => [
111 ['field1', 'field2[bla][blubb][blubb]', 'field2[bla]'],
112 1255072587
113 ],
114 'Empty [] not as last argument' => [
115 ['field1', 'field2[][bla]'],
116 1255072832
117 ]
118
119 ];
120 }
121
122 /**
123 * @test
124 * @dataProvider dataProviderForgenerateTrustedPropertiesToken
125 */
126 public function generateTrustedPropertiesTokenGeneratesTheCorrectHashesInNormalOperation($input, $expected)
127 {
128 $requestHashService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService::class)
129 ->setMethods(['serializeAndHashFormFieldArray'])
130 ->getMock();
131 $requestHashService->expects($this->once())->method('serializeAndHashFormFieldArray')->with($expected);
132 $requestHashService->generateTrustedPropertiesToken($input);
133 }
134
135 /**
136 * @param $input
137 * @param $expectExceptionCode
138 * @test
139 * @dataProvider dataProviderForgenerateTrustedPropertiesTokenWithUnallowedValues
140 */
141 public function generateTrustedPropertiesTokenThrowsExceptionInWrongCases($input, $expectExceptionCode)
142 {
143 $this->expectException(InvalidArgumentForHashGenerationException::class);
144 $this->expectExceptionCode($expectExceptionCode);
145 $requestHashService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService::class)
146 ->setMethods(['serializeAndHashFormFieldArray'])
147 ->getMock();
148 $requestHashService->generateTrustedPropertiesToken($input);
149 }
150
151 /**
152 * @test
153 */
154 public function serializeAndHashFormFieldArrayWorks()
155 {
156 $formFieldArray = [
157 'bla' => [
158 'blubb' => 1,
159 'hu' => 1
160 ]
161 ];
162 $mockHash = '12345';
163
164 $hashService = $this->getMockBuilder($this->buildAccessibleProxy(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService::class))
165 ->setMethods(['appendHmac'])
166 ->getMock();
167 $hashService->expects($this->once())->method('appendHmac')->with(serialize($formFieldArray))->will($this->returnValue(serialize($formFieldArray) . $mockHash));
168
169 $requestHashService = $this->getMockBuilder($this->buildAccessibleProxy(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService::class))
170 ->setMethods(['dummy'])
171 ->getMock();
172 $requestHashService->_set('hashService', $hashService);
173
174 $expected = serialize($formFieldArray) . $mockHash;
175 $actual = $requestHashService->_call('serializeAndHashFormFieldArray', $formFieldArray);
176 $this->assertEquals($expected, $actual);
177 }
178
179 /**
180 * @test
181 */
182 public function initializePropertyMappingConfigurationDoesNothingIfTrustedPropertiesAreNotSet()
183 {
184 $request = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Request::class)->setMethods(['getInternalArgument'])->disableOriginalConstructor()->getMock();
185 $request->expects($this->any())->method('getInternalArgument')->with('__trustedProperties')->will($this->returnValue(null));
186 $arguments = new \TYPO3\CMS\Extbase\Mvc\Controller\Arguments();
187
188 $requestHashService = new \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService;
189 $requestHashService->initializePropertyMappingConfigurationFromRequest($request, $arguments);
190 }
191
192 /**
193 * @test
194 */
195 public function initializePropertyMappingConfigurationReturnsEarlyIfNoTrustedPropertiesAreSet()
196 {
197 $trustedProperties = [
198 'foo' => 1
199 ];
200 $this->initializePropertyMappingConfiguration($trustedProperties);
201 }
202
203 /**
204 * @test
205 */
206 public function initializePropertyMappingConfigurationReturnsEarlyIfArgumentIsUnknown()
207 {
208 $trustedProperties = [
209 'nonExistingArgument' => 1
210 ];
211 $arguments = $this->initializePropertyMappingConfiguration($trustedProperties);
212 $this->assertFalse($arguments->hasArgument('nonExistingArgument'));
213 }
214
215 /**
216 * @test
217 */
218 public function initializePropertyMappingConfigurationSetsModificationAllowedIfIdentityPropertyIsSet()
219 {
220 $trustedProperties = [
221 'foo' => [
222 '__identity' => 1,
223 'nested' => [
224 '__identity' => 1,
225 ]
226 ]
227 ];
228 $arguments = $this->initializePropertyMappingConfiguration($trustedProperties);
229 $propertyMappingConfiguration = $arguments->getArgument('foo')->getPropertyMappingConfiguration();
230 $this->assertTrue($propertyMappingConfiguration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED), 'ConfigurationValue is not CONFIGURATION_MODIFICATION_ALLOWED at line ' . __LINE__);
231 $this->assertNull($propertyMappingConfiguration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED), 'ConfigurationValue is not NULL at line ' . __LINE__);
232 $this->assertFalse($propertyMappingConfiguration->shouldMap('someProperty'), 'Value is not FALSE at line ' . __LINE__);
233
234 $this->assertTrue($propertyMappingConfiguration->forProperty('nested')->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED), 'ConfigurationValue is not CONFIGURATION_MODIFICATION_ALLOWED at line ' . __LINE__);
235 $this->assertNull($propertyMappingConfiguration->forProperty('nested')->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED), 'ConfigurationValue is not NULL at line ' . __LINE__);
236 $this->assertFalse($propertyMappingConfiguration->forProperty('nested')->shouldMap('someProperty'), 'Value is not FALSE at line ' . __LINE__);
237 }
238
239 /**
240 * @test
241 */
242 public function initializePropertyMappingConfigurationSetsCreationAllowedIfIdentityPropertyIsNotSet()
243 {
244 $trustedProperties = [
245 'foo' => [
246 'bar' => []
247 ]
248 ];
249 $arguments = $this->initializePropertyMappingConfiguration($trustedProperties);
250 $propertyMappingConfiguration = $arguments->getArgument('foo')->getPropertyMappingConfiguration();
251 $this->assertNull($propertyMappingConfiguration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED));
252 $this->assertTrue($propertyMappingConfiguration->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED));
253 $this->assertFalse($propertyMappingConfiguration->shouldMap('someProperty'));
254
255 $this->assertNull($propertyMappingConfiguration->forProperty('bar')->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED));
256 $this->assertTrue($propertyMappingConfiguration->forProperty('bar')->getConfigurationValue(\TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::class, \TYPO3\CMS\Extbase\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED));
257 $this->assertFalse($propertyMappingConfiguration->forProperty('bar')->shouldMap('someProperty'));
258 }
259
260 /**
261 * @test
262 */
263 public function initializePropertyMappingConfigurationSetsAllowedFields()
264 {
265 $trustedProperties = [
266 'foo' => [
267 'bar' => 1
268 ]
269 ];
270 $arguments = $this->initializePropertyMappingConfiguration($trustedProperties);
271 $propertyMappingConfiguration = $arguments->getArgument('foo')->getPropertyMappingConfiguration();
272 $this->assertFalse($propertyMappingConfiguration->shouldMap('someProperty'));
273 $this->assertTrue($propertyMappingConfiguration->shouldMap('bar'));
274 }
275
276 /**
277 * @test
278 */
279 public function initializePropertyMappingConfigurationSetsAllowedFieldsRecursively()
280 {
281 $trustedProperties = [
282 'foo' => [
283 'bar' => [
284 'foo' => 1
285 ]
286 ]
287 ];
288 $arguments = $this->initializePropertyMappingConfiguration($trustedProperties);
289 $propertyMappingConfiguration = $arguments->getArgument('foo')->getPropertyMappingConfiguration();
290 $this->assertFalse($propertyMappingConfiguration->shouldMap('someProperty'));
291 $this->assertTrue($propertyMappingConfiguration->shouldMap('bar'));
292 $this->assertTrue($propertyMappingConfiguration->forProperty('bar')->shouldMap('foo'));
293 }
294
295 /**
296 * Helper which initializes the property mapping configuration and returns arguments
297 *
298 * @param array $trustedProperties
299 *
300 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Arguments
301 */
302 protected function initializePropertyMappingConfiguration(array $trustedProperties)
303 {
304 $request = $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Request::class)->setMethods(['getInternalArgument'])->disableOriginalConstructor()->getMock();
305 $request->expects($this->any())->method('getInternalArgument')->with('__trustedProperties')->will($this->returnValue('fooTrustedProperties'));
306
307 $mockHashService = $this->getMockBuilder(\TYPO3\CMS\Extbase\Security\Cryptography\HashService::class)
308 ->setMethods(['validateAndStripHmac'])
309 ->getMock();
310 $mockHashService->expects($this->once())->method('validateAndStripHmac')->with('fooTrustedProperties')->will($this->returnValue(serialize($trustedProperties)));
311
312 $requestHashService = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfigurationService::class, ['dummy']);
313 $requestHashService->_set('hashService', $mockHashService);
314
315 $mockObjectManager = $this->createMock(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class);
316 $mockArgument = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\Controller\Argument::class, ['getName'], [], '', false);
317
318 $propertyMappingConfiguration = new \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration();
319
320 $mockArgument->_set('propertyMappingConfiguration', $propertyMappingConfiguration);
321 $mockArgument->expects($this->any())->method('getName')->will($this->returnValue('foo'));
322 $mockObjectManager->expects($this->once())->method('get')->with(\TYPO3\CMS\Extbase\Mvc\Controller\Argument::class)->will($this->returnValue($mockArgument));
323
324 $arguments = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\Controller\Arguments::class, ['dummy']);
325 $arguments->_set('objectManager', $mockObjectManager);
326 $arguments->addNewArgument('foo');
327
328 $requestHashService->initializePropertyMappingConfigurationFromRequest($request, $arguments);
329
330 return $arguments;
331 }
332 }