[BUGFIX] Notice free FormEngine testing
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Form / FormDataProvider / DatabaseUserPermissionCheckTest.php
1 <?php
2 namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Prophecy\Argument;
18 use Prophecy\Prophecy\ObjectProphecy;
19 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedContentEditException;
20 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedEditInternalsException;
21 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedHookException;
22 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedPageEditException;
23 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedPageNewException;
24 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedRootNodeException;
25 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedTableModifyException;
26 use TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseUserPermissionCheck;
27 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
28 use TYPO3\CMS\Core\Type\Bitmask\Permission;
29 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
30
31 /**
32 * Test case
33 */
34 class DatabaseUserPermissionCheckTest extends UnitTestCase
35 {
36 /**
37 * @var BackendUserAuthentication | ObjectProphecy
38 */
39 protected $beUserProphecy;
40
41 protected function setUp()
42 {
43 $this->beUserProphecy = $this->prophesize(BackendUserAuthentication::class);
44 $GLOBALS['BE_USER'] = $this->beUserProphecy->reveal();
45 $GLOBALS['BE_USER']->user['uid'] = 42;
46 }
47
48 /**
49 * @test
50 */
51 public function addDataSetsUserPermissionsOnPageForAdminUser()
52 {
53 $this->beUserProphecy->isAdmin()->willReturn(true);
54
55 $result = (new DatabaseUserPermissionCheck)->addData([]);
56
57 $this->assertSame(Permission::ALL, $result['userPermissionOnPage']);
58 }
59
60 /**
61 * @test
62 */
63 public function addDataThrowsExceptionIfUserHasNoTablesModifyPermissionForGivenTable()
64 {
65 $input = [
66 'tableName' => 'tt_content',
67 ];
68 $this->beUserProphecy->isAdmin()->willReturn(false);
69 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(false);
70
71 $this->expectException(AccessDeniedTableModifyException::class);
72 $this->expectExceptionCode(1437683248);
73
74 (new DatabaseUserPermissionCheck)->addData($input);
75 }
76
77 /**
78 * @test
79 */
80 public function addDataThrowsExceptionIfUserHasNoContentEditPermissionsOnPage()
81 {
82 $input = [
83 'tableName' => 'tt_content',
84 'command' => 'edit',
85 'vanillaUid' => 123,
86 'parentPageRow' => [
87 'uid' => 42,
88 'pid' => 321,
89 ],
90 ];
91 $this->beUserProphecy->isAdmin()->willReturn(false);
92 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
93 $this->beUserProphecy->calcPerms(['uid' => 42, 'pid' => 321])->willReturn(Permission::NOTHING);
94
95 $this->expectException(AccessDeniedContentEditException::class);
96 $this->expectExceptionCode(1437679657);
97
98 (new DatabaseUserPermissionCheck)->addData($input);
99 }
100
101 /**
102 * @test
103 */
104 public function addDataAddsUserPermissionsOnPageForContentIfUserHasCorrespondingPermissions()
105 {
106 $input = [
107 'tableName' => 'tt_content',
108 'command' => 'edit',
109 'vanillaUid' => 123,
110 'databaseRow' => [],
111 'parentPageRow' => [
112 'pid' => 321,
113 ],
114 ];
115 $this->beUserProphecy->isAdmin()->willReturn(false);
116 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
117 $this->beUserProphecy->calcPerms(['pid' => 321])->willReturn(Permission::CONTENT_EDIT);
118 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::any())->willReturn(true);
119
120 $result = (new DatabaseUserPermissionCheck)->addData($input);
121
122 $this->assertSame(Permission::CONTENT_EDIT, $result['userPermissionOnPage']);
123 }
124
125 /**
126 * @test
127 */
128 public function addDataThrowsExceptionIfCommandIsEditTableIsPagesAndUserHasNoPagePermissions()
129 {
130 $input = [
131 'tableName' => 'pages',
132 'command' => 'edit',
133 'vanillaUid' => 123,
134 'databaseRow' => [
135 'uid' => 123,
136 'pid' => 321
137 ],
138 ];
139 $this->beUserProphecy->isAdmin()->willReturn(false);
140 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
141 $this->beUserProphecy->calcPerms($input['databaseRow'])->willReturn(Permission::NOTHING);
142
143 $this->expectException(AccessDeniedPageEditException::class);
144 $this->expectExceptionCode(1437679336);
145
146 (new DatabaseUserPermissionCheck)->addData($input);
147 }
148
149 /**
150 * @test
151 */
152 public function addDataThrowsExceptionIfCommandIsEditTableIsPagesAndUserHasNoDoktypePermissions()
153 {
154 $input = [
155 'tableName' => 'pages',
156 'command' => 'edit',
157 'vanillaUid' => 123,
158 'databaseRow' => [
159 'uid' => 123,
160 'pid' => 321,
161 'doktype' => 1,
162 ],
163 'processedTca' => [
164 'ctrl' => [
165 'type' => 'doktype'
166 ]
167 ]
168 ];
169 $this->beUserProphecy->isAdmin()->willReturn(false);
170 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
171 $this->beUserProphecy->check('pagetypes_select', $input['databaseRow']['doktype'])->willReturn(false);
172 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
173 $this->beUserProphecy->calcPerms($input['databaseRow'])->willReturn(Permission::ALL);
174
175 $this->expectException(AccessDeniedPageEditException::class);
176 $this->expectExceptionCode(1437679336);
177
178 (new DatabaseUserPermissionCheck)->addData($input);
179 }
180
181 /**
182 * @test
183 */
184 public function addDataAddsUserPermissionsOnPageIfTableIsPagesAndUserHasPagePermissions()
185 {
186 $input = [
187 'tableName' => 'pages',
188 'command' => 'edit',
189 'vanillaUid' => 123,
190 'databaseRow' => [
191 'uid' => 123,
192 'pid' => 321,
193 'doktype' => 1,
194 ],
195 'processedTca' => [
196 'ctrl' => [
197 'type' => 'doktype'
198 ]
199 ]
200 ];
201 $this->beUserProphecy->isAdmin()->willReturn(false);
202 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
203 $this->beUserProphecy->check('pagetypes_select', $input['databaseRow']['doktype'])->willReturn(true);
204 $this->beUserProphecy->calcPerms($input['databaseRow'])->willReturn(Permission::PAGE_EDIT);
205 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
206
207 $result = (new DatabaseUserPermissionCheck)->addData($input);
208
209 $this->assertSame(Permission::PAGE_EDIT, $result['userPermissionOnPage']);
210 }
211
212 /**
213 * @test
214 */
215 public function addDataSetsPermissionsToAllIfRootLevelRestrictionForTableIsIgnoredForContentEditRecord()
216 {
217 $input = [
218 'tableName' => 'tt_content',
219 'command' => 'edit',
220 'vanillaUid' => 123,
221 'databaseRow' => [
222 'uid' => 123,
223 'pid' => 0,
224 ],
225 ];
226 $this->beUserProphecy->isAdmin()->willReturn(false);
227 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
228 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
229 $GLOBALS['TCA'][$input['tableName']]['ctrl']['security']['ignoreRootLevelRestriction'] = true;
230
231 $result = (new DatabaseUserPermissionCheck)->addData($input);
232
233 $this->assertSame(Permission::ALL, $result['userPermissionOnPage']);
234 }
235
236 /**
237 * @test
238 */
239 public function addDataThrowsExceptionIfRootNodeShouldBeEditedWithoutPermissions()
240 {
241 $input = [
242 'tableName' => 'tt_content',
243 'command' => 'edit',
244 'vanillaUid' => 123,
245 'databaseRow' => [
246 'uid' => 123,
247 'pid' => 0,
248 ],
249 ];
250 $this->beUserProphecy->isAdmin()->willReturn(false);
251 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
252 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
253
254 $this->expectException(AccessDeniedRootNodeException::class);
255 $this->expectExceptionCode(1437679856);
256
257 (new DatabaseUserPermissionCheck)->addData($input);
258 }
259
260 /**
261 * @test
262 */
263 public function addDataThrowsExceptionIfRecordEditAccessInternalsReturnsFalse()
264 {
265 $input = [
266 'tableName' => 'tt_content',
267 'command' => 'edit',
268 'vanillaUid' => 123,
269 'databaseRow' => [],
270 'parentPageRow' => [
271 'uid' => 123,
272 'pid' => 321,
273 ],
274 ];
275 $this->beUserProphecy->isAdmin()->willReturn(false);
276 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
277 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::ALL);
278 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(false);
279
280 $this->expectException(AccessDeniedEditInternalsException::class);
281 $this->expectExceptionCode(1437687404);
282
283 (new DatabaseUserPermissionCheck)->addData($input);
284 }
285
286 /**
287 * @test
288 */
289 public function addDataThrowsExceptionForNewContentRecordWithoutPermissions()
290 {
291 $input = [
292 'tableName' => 'tt_content',
293 'command' => 'new',
294 'vanillaUid' => 123,
295 'parentPageRow' => [
296 'uid' => 123,
297 'pid' => 321,
298 ],
299 ];
300 $this->beUserProphecy->isAdmin()->willReturn(false);
301 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
302 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::NOTHING);
303
304 $this->expectException(AccessDeniedContentEditException::class);
305 $this->expectExceptionCode(1437745759);
306
307 (new DatabaseUserPermissionCheck)->addData($input);
308 }
309
310 /**
311 * @test
312 */
313 public function addDataThrowsExceptionForNewPageWithoutPermissions()
314 {
315 $input = [
316 'tableName' => 'pages',
317 'command' => 'new',
318 'vanillaUid' => 123,
319 'databaseRow' => [
320 'uid' => 'NEW123',
321 ],
322 'parentPageRow' => [
323 'uid' => 123,
324 'pid' => 321,
325 ],
326 ];
327 $this->beUserProphecy->isAdmin()->willReturn(false);
328 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
329 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::NOTHING);
330
331 $this->expectException(AccessDeniedPageNewException::class);
332 $this->expectExceptionCode(1437745640);
333
334 (new DatabaseUserPermissionCheck)->addData($input);
335 }
336
337 /**
338 * @test
339 */
340 public function addDataThrowsExceptionIfHookDeniesAccess()
341 {
342 $input = [
343 'tableName' => 'tt_content',
344 'command' => 'edit',
345 'vanillaUid' => 123,
346 'databaseRow' => [
347 'uid' => 5,
348 ],
349 'parentPageRow' => [
350 'uid' => 123,
351 'pid' => 321,
352 ],
353 ];
354 $this->beUserProphecy->isAdmin()->willReturn(false);
355 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
356 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::ALL);
357 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
358
359 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] = [
360 'unitTest' => function () {
361 return false;
362 }
363 ];
364
365 $this->expectException(AccessDeniedHookException::class);
366 $this->expectExceptionCode(1437689705);
367
368 (new DatabaseUserPermissionCheck)->addData($input);
369 }
370
371 /**
372 * @test
373 */
374 public function addDataSetsUserPermissionsOnPageForNewPageIfPageNewIsDeniedAndHookAllowsAccess()
375 {
376 $input = [
377 'tableName' => 'pages',
378 'command' => 'new',
379 'vanillaUid' => 123,
380 'databaseRow' => [
381 'uid' => 'NEW5',
382 ],
383 'parentPageRow' => [
384 'uid' => 123,
385 'pid' => 321,
386 ],
387 ];
388 $this->beUserProphecy->isAdmin()->willReturn(false);
389 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
390 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::CONTENT_EDIT);
391 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
392
393 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] = [
394 'unitTest' => function () {
395 return true;
396 }
397 ];
398
399 $result = (new DatabaseUserPermissionCheck)->addData($input);
400
401 $this->assertSame(Permission::CONTENT_EDIT, $result['userPermissionOnPage']);
402 }
403
404 /**
405 * @test
406 */
407 public function addDataSetsUserPermissionsOnPageForNewPage()
408 {
409 $input = [
410 'tableName' => 'pages',
411 'command' => 'new',
412 'vanillaUid' => 123,
413 'parentPageRow' => [
414 'uid' => 123,
415 'pid' => 321,
416 ],
417 ];
418 $this->beUserProphecy->isAdmin()->willReturn(false);
419 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
420 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::PAGE_NEW);
421 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
422
423 $result = (new DatabaseUserPermissionCheck)->addData($input);
424
425 $this->assertSame(Permission::PAGE_NEW, $result['userPermissionOnPage']);
426 }
427
428 /**
429 * @test
430 */
431 public function addDataSetsUserPermissionsOnPageForNewContentRecord()
432 {
433 $input = [
434 'tableName' => 'tt_content',
435 'command' => 'new',
436 'vanillaUid' => 123,
437 'parentPageRow' => [
438 'uid' => 123,
439 'pid' => 321,
440 ],
441 ];
442 $this->beUserProphecy->isAdmin()->willReturn(false);
443 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
444 $this->beUserProphecy->calcPerms($input['parentPageRow'])->willReturn(Permission::CONTENT_EDIT);
445 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
446
447 $result = (new DatabaseUserPermissionCheck)->addData($input);
448
449 $this->assertSame(Permission::CONTENT_EDIT, $result['userPermissionOnPage']);
450 }
451
452 /**
453 * @test
454 */
455 public function addDataSetsPermissionsToAllIfRootLevelRestrictionForTableIsIgnoredForNewContentRecord()
456 {
457 $input = [
458 'tableName' => 'pages',
459 'command' => 'new',
460 'vanillaUid' => 123,
461 'parentPageRow' => null,
462 ];
463 $this->beUserProphecy->isAdmin()->willReturn(false);
464 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
465 $this->beUserProphecy->recordEditAccessInternals($input['tableName'], Argument::cetera())->willReturn(true);
466 $GLOBALS['TCA'][$input['tableName']]['ctrl']['security']['ignoreRootLevelRestriction'] = true;
467
468 $result = (new DatabaseUserPermissionCheck)->addData($input);
469
470 $this->assertSame(Permission::ALL, $result['userPermissionOnPage']);
471 }
472
473 /**
474 * @test
475 */
476 public function addDataThrowsExceptionForNewRecordsOnRootLevelWithoutPermissions()
477 {
478 $input = [
479 'tableName' => 'pages',
480 'command' => 'new',
481 'vanillaUid' => 123,
482 'parentPageRow' => null,
483 ];
484
485 $this->beUserProphecy->isAdmin()->willReturn(false);
486 $this->beUserProphecy->check('tables_modify', $input['tableName'])->willReturn(true);
487
488 $this->expectException(AccessDeniedRootNodeException::class);
489 $this->expectExceptionCode(1437745221);
490
491 (new DatabaseUserPermissionCheck)->addData($input);
492 }
493 }