a30290757ff3d7f1daa07eca65e0a31aa5321257
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Authentication / BackendUserAuthenticationTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Core\Tests\Unit\Authentication;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Prophecy\Argument;
19 use Prophecy\Prophecy\ObjectProphecy;
20 use Psr\Log\NullLogger;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\Database\Connection;
23 use TYPO3\CMS\Core\Database\ConnectionPool;
24 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
25 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
26 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
27 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
28 use TYPO3\CMS\Core\Resource\ResourceStorage;
29 use TYPO3\CMS\Core\Tests\Unit\Database\Mocks\MockPlatform;
30 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
33
34 /**
35 * Test case
36 */
37 class BackendUserAuthenticationTest extends UnitTestCase
38 {
39 /**
40 * @var array
41 */
42 protected $defaultFilePermissions = [
43 // File permissions
44 'addFile' => false,
45 'readFile' => false,
46 'writeFile' => false,
47 'copyFile' => false,
48 'moveFile' => false,
49 'renameFile' => false,
50 'deleteFile' => false,
51 // Folder permissions
52 'addFolder' => false,
53 'readFolder' => false,
54 'writeFolder' => false,
55 'copyFolder' => false,
56 'moveFolder' => false,
57 'renameFolder' => false,
58 'deleteFolder' => false,
59 'recursivedeleteFolder' => false
60 ];
61
62 /**
63 * Tear down
64 */
65 protected function tearDown(): void
66 {
67 FormProtectionFactory::purgeInstances();
68 parent::tearDown();
69 }
70
71 /////////////////////////////////////////
72 // Tests concerning the form protection
73 /////////////////////////////////////////
74 /**
75 * @test
76 */
77 public function logoffCleansFormProtectionIfBackendUserIsLoggedIn(): void
78 {
79 /** @var ObjectProphecy|Connection $connection */
80 $connection = $this->prophesize(Connection::class);
81 $connection->delete('sys_lockedrecords', Argument::cetera())->willReturn(1);
82
83 /** @var ObjectProphecy|ConnectionPool $connectionPool */
84 $connectionPool = $this->prophesize(ConnectionPool::class);
85 $connectionPool->getConnectionForTable(Argument::cetera())->willReturn($connection->reveal());
86
87 GeneralUtility::addInstance(ConnectionPool::class, $connectionPool->reveal());
88
89 /** @var ObjectProphecy|\TYPO3\CMS\Core\FormProtection\AbstractFormProtection $formProtection */
90 $formProtection = $this->prophesize(BackendFormProtection::class);
91 $formProtection->clean()->shouldBeCalled();
92
93 FormProtectionFactory::set(
94 'default',
95 $formProtection->reveal()
96 );
97
98 $GLOBALS['BE_USER'] = $this->getMockBuilder(BackendUserAuthentication::class)->getMock();
99 $GLOBALS['BE_USER']->user = ['uid' => $this->getUniqueId()];
100 $GLOBALS['BE_USER']->setLogger(new NullLogger());
101
102 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
103 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
104 ->setMethods(['dummy'])
105 ->disableOriginalConstructor()
106 ->getMock();
107
108 $subject->setLogger(new NullLogger());
109 $subject->logoff();
110 }
111
112 /**
113 * @return array
114 */
115 public function getTSConfigDataProvider(): array
116 {
117 $completeConfiguration = [
118 'value' => 'oneValue',
119 'value.' => ['oneProperty' => 'oneValue'],
120 'permissions.' => [
121 'file.' => [
122 'default.' => ['readAction' => '1'],
123 '1.' => ['writeAction' => '1'],
124 '0.' => ['readAction' => '0'],
125 ],
126 ]
127 ];
128
129 return [
130 'single level string' => [
131 $completeConfiguration,
132 'permissions',
133 [
134 'value' => null,
135 'properties' =>
136 [
137 'file.' => [
138 'default.' => ['readAction' => '1'],
139 '1.' => ['writeAction' => '1'],
140 '0.' => ['readAction' => '0'],
141 ],
142 ],
143 ],
144 ],
145 'two levels string' => [
146 $completeConfiguration,
147 'permissions.file',
148 [
149 'value' => null,
150 'properties' =>
151 [
152 'default.' => ['readAction' => '1'],
153 '1.' => ['writeAction' => '1'],
154 '0.' => ['readAction' => '0'],
155 ],
156 ],
157 ],
158 'three levels string' => [
159 $completeConfiguration,
160 'permissions.file.default',
161 [
162 'value' => null,
163 'properties' =>
164 ['readAction' => '1'],
165 ],
166 ],
167 'three levels string with integer property' => [
168 $completeConfiguration,
169 'permissions.file.1',
170 [
171 'value' => null,
172 'properties' => ['writeAction' => '1'],
173 ],
174 ],
175 'three levels string with integer zero property' => [
176 $completeConfiguration,
177 'permissions.file.0',
178 [
179 'value' => null,
180 'properties' => ['readAction' => '0'],
181 ],
182 ],
183 'four levels string with integer zero property, value, no properties' => [
184 $completeConfiguration,
185 'permissions.file.0.readAction',
186 [
187 'value' => '0',
188 'properties' => null,
189 ],
190 ],
191 'four levels string with integer property, value, no properties' => [
192 $completeConfiguration,
193 'permissions.file.1.writeAction',
194 [
195 'value' => '1',
196 'properties' => null,
197 ],
198 ],
199 'one level, not existent string' => [
200 $completeConfiguration,
201 'foo',
202 [
203 'value' => null,
204 'properties' => null,
205 ],
206 ],
207 'two level, not existent string' => [
208 $completeConfiguration,
209 'foo.bar',
210 [
211 'value' => null,
212 'properties' => null,
213 ],
214 ],
215 'two level, where second level does not exist' => [
216 $completeConfiguration,
217 'permissions.bar',
218 [
219 'value' => null,
220 'properties' => null,
221 ],
222 ],
223 'three level, where third level does not exist' => [
224 $completeConfiguration,
225 'permissions.file.foo',
226 [
227 'value' => null,
228 'properties' => null,
229 ],
230 ],
231 'three level, where second and third level does not exist' => [
232 $completeConfiguration,
233 'permissions.foo.bar',
234 [
235 'value' => null,
236 'properties' => null,
237 ],
238 ],
239 'value and properties' => [
240 $completeConfiguration,
241 'value',
242 [
243 'value' => 'oneValue',
244 'properties' => ['oneProperty' => 'oneValue'],
245 ],
246 ],
247 ];
248 }
249
250 /**
251 * @param array $completeConfiguration
252 * @param string $objectString
253 * @param array $expectedConfiguration
254 * @dataProvider getTSConfigDataProvider
255 * @test
256 */
257 public function getTSConfigReturnsCorrectArrayForGivenObjectString(array $completeConfiguration, $objectString, array $expectedConfiguration): void
258 {
259 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
260 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
261 ->setMethods(['dummy'])
262 ->disableOriginalConstructor()
263 ->getMock();
264 $subject->setLogger(new NullLogger());
265 $subject->userTS = $completeConfiguration;
266
267 $actualConfiguration = $subject->getTSConfig($objectString);
268 $this->assertSame($expectedConfiguration, $actualConfiguration);
269 }
270
271 /**
272 * @return array
273 */
274 public function getFilePermissionsTakesUserDefaultAndStoragePermissionsIntoAccountIfUserIsNotAdminDataProvider(): array
275 {
276 return [
277 'Only read permissions' => [
278 [
279 'addFile' => 0,
280 'readFile' => 1,
281 'writeFile' => 0,
282 'copyFile' => 0,
283 'moveFile' => 0,
284 'renameFile' => 0,
285 'deleteFile' => 0,
286 'addFolder' => 0,
287 'readFolder' => 1,
288 'copyFolder' => 0,
289 'moveFolder' => 0,
290 'renameFolder' => 0,
291 'writeFolder' => 0,
292 'deleteFolder' => 0,
293 'recursivedeleteFolder' => 0,
294 ]
295 ],
296 'Uploading allowed' => [
297 [
298 'addFile' => 1,
299 'readFile' => 1,
300 'writeFile' => 1,
301 'copyFile' => 1,
302 'moveFile' => 1,
303 'renameFile' => 1,
304 'deleteFile' => 1,
305 'addFolder' => 0,
306 'readFolder' => 1,
307 'copyFolder' => 0,
308 'moveFolder' => 0,
309 'renameFolder' => 0,
310 'writeFolder' => 0,
311 'deleteFolder' => 0,
312 'recursivedeleteFolder' => 0
313 ]
314 ],
315 'One value is enough' => [
316 [
317 'addFile' => 1,
318 ]
319 ],
320 ];
321 }
322
323 /**
324 * @param array $userTsConfiguration
325 * @test
326 * @dataProvider getFilePermissionsTakesUserDefaultAndStoragePermissionsIntoAccountIfUserIsNotAdminDataProvider
327 */
328 public function getFilePermissionsTakesUserDefaultPermissionsFromTsConfigIntoAccountIfUserIsNotAdmin(array $userTsConfiguration): void
329 {
330 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
331 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
332 ->setMethods(['isAdmin'])
333 ->getMock();
334
335 $subject
336 ->expects($this->any())
337 ->method('isAdmin')
338 ->will($this->returnValue(false));
339
340 $subject->setLogger(new NullLogger());
341 $subject->userTS = [
342 'permissions.' => [
343 'file.' => [
344 'default.' => $userTsConfiguration
345 ],
346 ]
347 ];
348
349 $expectedPermissions = array_merge($this->defaultFilePermissions, $userTsConfiguration);
350 array_walk(
351 $expectedPermissions,
352 function (&$value) {
353 $value = (bool)$value;
354 }
355 );
356
357 $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
358 }
359
360 /**
361 * @return array
362 */
363 public function getFilePermissionsFromStorageDataProvider(): array
364 {
365 $defaultPermissions = [
366 'addFile' => true,
367 'readFile' => true,
368 'writeFile' => true,
369 'copyFile' => true,
370 'moveFile' => true,
371 'renameFile' => true,
372 'deleteFile' => true,
373 'addFolder' => true,
374 'readFolder' => true,
375 'copyFolder' => true,
376 'moveFolder' => true,
377 'renameFolder' => true,
378 'writeFolder' => true,
379 'deleteFolder' => true,
380 'recursivedeleteFolder' => true
381 ];
382
383 return [
384 'Overwrites given storage permissions with default permissions' => [
385 $defaultPermissions,
386 1,
387 [
388 'addFile' => 0,
389 'recursivedeleteFolder' =>0
390 ],
391 [
392 'addFile' => 0,
393 'readFile' => 1,
394 'writeFile' => 1,
395 'copyFile' => 1,
396 'moveFile' => 1,
397 'renameFile' => 1,
398 'deleteFile' => 1,
399 'addFolder' => 1,
400 'readFolder' => 1,
401 'copyFolder' => 1,
402 'moveFolder' => 1,
403 'renameFolder' => 1,
404 'writeFolder' => 1,
405 'deleteFolder' => 1,
406 'recursivedeleteFolder' => 0
407 ]
408 ],
409 'Overwrites given storage 0 permissions with default permissions' => [
410 $defaultPermissions,
411 0,
412 [
413 'addFile' => 0,
414 'recursivedeleteFolder' =>0
415 ],
416 [
417 'addFile' => false,
418 'readFile' => true,
419 'writeFile' => true,
420 'copyFile' => true,
421 'moveFile' => true,
422 'renameFile' => true,
423 'deleteFile' => true,
424 'addFolder' => true,
425 'readFolder' => true,
426 'copyFolder' => true,
427 'moveFolder' => true,
428 'renameFolder' => true,
429 'writeFolder' => true,
430 'deleteFolder' => true,
431 'recursivedeleteFolder' => false
432 ]
433 ],
434 'Returns default permissions if no storage permissions are found' => [
435 $defaultPermissions,
436 1,
437 [],
438 [
439 'addFile' => true,
440 'readFile' => true,
441 'writeFile' => true,
442 'copyFile' => true,
443 'moveFile' => true,
444 'renameFile' => true,
445 'deleteFile' => true,
446 'addFolder' => true,
447 'readFolder' => true,
448 'copyFolder' => true,
449 'moveFolder' => true,
450 'renameFolder' => true,
451 'writeFolder' => true,
452 'deleteFolder' => true,
453 'recursivedeleteFolder' => true
454 ]
455 ],
456 ];
457 }
458
459 /**
460 * @param array $defaultPermissions
461 * @param int $storageUid
462 * @param array $storagePermissions
463 * @param array $expectedPermissions
464 * @test
465 * @dataProvider getFilePermissionsFromStorageDataProvider
466 */
467 public function getFilePermissionsFromStorageOverwritesDefaultPermissions(array $defaultPermissions, $storageUid, array $storagePermissions, array $expectedPermissions): void
468 {
469 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
470 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
471 ->setMethods(['isAdmin', 'getFilePermissions'])
472 ->getMock();
473 $storageMock = $this->createMock(ResourceStorage::class);
474 $storageMock->expects($this->any())->method('getUid')->will($this->returnValue($storageUid));
475
476 $subject
477 ->expects($this->any())
478 ->method('isAdmin')
479 ->will($this->returnValue(false));
480
481 $subject
482 ->expects($this->any())
483 ->method('getFilePermissions')
484 ->will($this->returnValue($defaultPermissions));
485
486 $subject->userTS = [
487 'permissions.' => [
488 'file.' => [
489 'storage.' => [
490 $storageUid . '.' => $storagePermissions
491 ],
492 ],
493 ]
494 ];
495
496 $this->assertEquals($expectedPermissions, $subject->getFilePermissionsForStorage($storageMock));
497 }
498
499 /**
500 * @param array $defaultPermissions
501 * @param $storageUid
502 * @param array $storagePermissions
503 * @test
504 * @dataProvider getFilePermissionsFromStorageDataProvider
505 */
506 public function getFilePermissionsFromStorageAlwaysReturnsDefaultPermissionsForAdmins(array $defaultPermissions, $storageUid, array $storagePermissions): void
507 {
508 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
509 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
510 ->setMethods(['isAdmin', 'getFilePermissions'])
511 ->getMock();
512 $storageMock = $this->createMock(ResourceStorage::class);
513 $storageMock->expects($this->any())->method('getUid')->will($this->returnValue($storageUid));
514
515 $subject
516 ->expects($this->any())
517 ->method('isAdmin')
518 ->will($this->returnValue(true));
519
520 $subject
521 ->expects($this->any())
522 ->method('getFilePermissions')
523 ->will($this->returnValue($defaultPermissions));
524
525 $subject->userTS = [
526 'permissions.' => [
527 'file.' => [
528 'storage.' => [
529 $storageUid . '.' => $storagePermissions
530 ],
531 ],
532 ]
533 ];
534
535 $this->assertEquals($defaultPermissions, $subject->getFilePermissionsForStorage($storageMock));
536 }
537
538 /**
539 * @return array
540 */
541 public function getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdminDataProvider(): array
542 {
543 return [
544 'No permission' => [
545 '',
546 [
547 'addFile' => false,
548 'readFile' => false,
549 'writeFile' => false,
550 'copyFile' => false,
551 'moveFile' => false,
552 'renameFile' => false,
553 'deleteFile' => false,
554 'addFolder' => false,
555 'readFolder' => false,
556 'copyFolder' => false,
557 'moveFolder' => false,
558 'renameFolder' => false,
559 'writeFolder' => false,
560 'deleteFolder' => false,
561 'recursivedeleteFolder' => false
562 ]
563 ],
564 'Standard file permissions' => [
565 'addFile,readFile,writeFile,copyFile,moveFile,renameFile,deleteFile',
566 [
567 'addFile' => true,
568 'readFile' => true,
569 'writeFile' => true,
570 'copyFile' => true,
571 'moveFile' => true,
572 'renameFile' => true,
573 'deleteFile' => true,
574 'addFolder' => false,
575 'readFolder' => false,
576 'copyFolder' => false,
577 'moveFolder' => false,
578 'renameFolder' => false,
579 'writeFolder' => false,
580 'deleteFolder' => false,
581 'recursivedeleteFolder' => false
582 ]
583 ],
584 'Standard folder permissions' => [
585 'addFolder,readFolder,moveFolder,renameFolder,writeFolder,deleteFolder',
586 [
587 'addFile' => false,
588 'readFile' => false,
589 'writeFile' => false,
590 'copyFile' => false,
591 'moveFile' => false,
592 'renameFile' => false,
593 'deleteFile' => false,
594 'addFolder' => true,
595 'readFolder' => true,
596 'writeFolder' => true,
597 'copyFolder' => false,
598 'moveFolder' => true,
599 'renameFolder' => true,
600 'deleteFolder' => true,
601 'recursivedeleteFolder' => false
602 ]
603 ],
604 'Copy folder allowed' => [
605 'readFolder,copyFolder',
606 [
607 'addFile' => false,
608 'readFile' => false,
609 'writeFile' => false,
610 'copyFile' => false,
611 'moveFile' => false,
612 'renameFile' => false,
613 'deleteFile' => false,
614 'addFolder' => false,
615 'readFolder' => true,
616 'writeFolder' => false,
617 'copyFolder' => true,
618 'moveFolder' => false,
619 'renameFolder' => false,
620 'deleteFolder' => false,
621 'recursivedeleteFolder' => false
622 ]
623 ],
624 'Copy folder and remove subfolders allowed' => [
625 'readFolder,copyFolder,recursivedeleteFolder',
626 [
627 'addFile' => false,
628 'readFile' => false,
629 'writeFile' => false,
630 'copyFile' => false,
631 'moveFile' => false,
632 'renameFile' => false,
633 'deleteFile' => false,
634 'addFolder' => false,
635 'readFolder' => true,
636 'writeFolder' => false,
637 'copyFolder' => true,
638 'moveFolder' => false,
639 'renameFolder' => false,
640 'deleteFolder' => false,
641 'recursivedeleteFolder' => true
642 ]
643 ],
644 ];
645 }
646
647 /**
648 * @test
649 *
650 * @param string $permissionValue
651 * @param array $expectedPermissions
652 *
653 * @dataProvider getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdminDataProvider
654 */
655 public function getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdmin(string $permissionValue, array $expectedPermissions): void
656 {
657 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
658 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
659 ->setMethods(['isAdmin'])
660 ->getMock();
661
662 $subject
663 ->expects($this->any())
664 ->method('isAdmin')
665 ->will($this->returnValue(false));
666
667 $subject->userTS = [];
668 $subject->groupData['file_permissions'] = $permissionValue;
669 $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
670 }
671
672 /**
673 * @test
674 */
675 public function getFilePermissionsGrantsAllPermissionsToAdminUsers(): void
676 {
677 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
678 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
679 ->setMethods(['isAdmin'])
680 ->getMock();
681
682 $subject
683 ->expects($this->any())
684 ->method('isAdmin')
685 ->will($this->returnValue(true));
686
687 $expectedPermissions = [
688 'addFile' => true,
689 'readFile' => true,
690 'writeFile' => true,
691 'copyFile' => true,
692 'moveFile' => true,
693 'renameFile' => true,
694 'deleteFile' => true,
695 'addFolder' => true,
696 'readFolder' => true,
697 'writeFolder' => true,
698 'copyFolder' => true,
699 'moveFolder' => true,
700 'renameFolder' => true,
701 'deleteFolder' => true,
702 'recursivedeleteFolder' => true
703 ];
704
705 $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
706 }
707
708 /**
709 * @test
710 */
711 public function jsConfirmationReturnsTrueIfPassedValueEqualsConfiguration(): void
712 {
713 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
714 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
715 ->setMethods(['getTSConfig'])
716 ->getMock();
717 $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 1]);
718
719 $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
720 $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
721 }
722
723 /**
724 * @test
725 */
726 public function jsConfirmationAllowsSettingMultipleBitsInValue(): void
727 {
728 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
729 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
730 ->setMethods(['getTSConfig'])
731 ->getMock();
732 $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 3]);
733
734 $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
735 $this->assertTrue($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
736 }
737
738 /**
739 * @test
740 * @dataProvider jsConfirmationsWithUnsetBits
741 *
742 * @param int $jsConfirmation
743 * @param int $typeChangeAllowed
744 * @param int $copyMovePasteAllowed
745 * @param int $deleteAllowed
746 * @param int $feEditAllowed
747 * @param int $otherAllowed
748 */
749 public function jsConfirmationAllowsUnsettingBitsInValue($jsConfirmation, $typeChangeAllowed, $copyMovePasteAllowed, $deleteAllowed, $feEditAllowed, $otherAllowed): void
750 {
751 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
752 ->setMethods(['getTSConfig'])
753 ->getMock();
754 $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => $jsConfirmation]);
755
756 $this->assertEquals($typeChangeAllowed, $subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
757 $this->assertEquals($copyMovePasteAllowed, $subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
758 $this->assertEquals($deleteAllowed, $subject->jsConfirmation(JsConfirmation::DELETE));
759 $this->assertEquals($feEditAllowed, $subject->jsConfirmation(JsConfirmation::FE_EDIT));
760 $this->assertEquals($otherAllowed, $subject->jsConfirmation(JsConfirmation::OTHER));
761 }
762
763 /**
764 * @return array
765 */
766 public function jsConfirmationsWithUnsetBits(): array
767 {
768 return [
769 'All except "type change" and "copy/move/paste"' => [
770 252,
771 false,
772 false,
773 true,
774 true,
775 true,
776 ],
777 'All except "other"' => [
778 127,
779 true,
780 true,
781 true,
782 true,
783 false,
784 ],
785 ];
786 }
787
788 /**
789 * @test
790 */
791 public function jsConfirmationAlwaysReturnsFalseIfNoConfirmationIsSet(): void
792 {
793 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
794 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
795 ->setMethods(['getTSConfig'])
796 ->getMock();
797 $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 0]);
798
799 $this->assertFalse($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
800 $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
801 }
802
803 /**
804 * @test
805 */
806 public function jsConfirmationReturnsTrueIfConfigurationIsMissing(): void
807 {
808 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
809 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
810 ->setMethods(['getTSConfig'])
811 ->getMock();
812
813 $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
814 }
815
816 /**
817 * Data provider to test page permissions constraints
818 * returns an array of test conditions:
819 * - permission bit(s) as integer
820 * - admin flag
821 * - groups for user
822 * - expected SQL fragment
823 *
824 * @return array
825 */
826 public function getPagePermissionsClauseWithValidUserDataProvider(): array
827 {
828 return [
829 'for admin' => [
830 1,
831 true,
832 '',
833 ' 1=1'
834 ],
835 'for admin with groups' => [
836 11,
837 true,
838 '1,2',
839 ' 1=1'
840 ],
841 'for user' => [
842 2,
843 false,
844 '',
845 ' ((`pages`.`perms_everybody` & 2 = 2) OR' .
846 ' ((`pages`.`perms_userid` = 123) AND (`pages`.`perms_user` & 2 = 2)))'
847 ],
848 'for user with groups' => [
849 8,
850 false,
851 '1,2',
852 ' ((`pages`.`perms_everybody` & 8 = 8) OR' .
853 ' ((`pages`.`perms_userid` = 123) AND (`pages`.`perms_user` & 8 = 8))' .
854 ' OR ((`pages`.`perms_groupid` IN (1, 2)) AND (`pages`.`perms_group` & 8 = 8)))'
855 ],
856 ];
857 }
858
859 /**
860 * @test
861 * @dataProvider getPagePermissionsClauseWithValidUserDataProvider
862 * @param int $perms
863 * @param bool $admin
864 * @param string $groups
865 * @param string $expected
866 */
867 public function getPagePermissionsClauseWithValidUser(int $perms, bool $admin, string $groups, string $expected): void
868 {
869 // We only need to setup the mocking for the non-admin cases
870 // If this setup is done for admin cases the FIFO behavior
871 // of GeneralUtility::addInstance will influence other tests
872 // as the ConnectionPool is never used!
873 if (!$admin) {
874 /** @var Connection|ObjectProphecy $connectionProphecy */
875 $connectionProphecy = $this->prophesize(Connection::class);
876 $connectionProphecy->getDatabasePlatform()->willReturn(new MockPlatform());
877 $connectionProphecy->quoteIdentifier(Argument::cetera())->will(function ($args) {
878 return '`' . str_replace('.', '`.`', $args[0]) . '`';
879 });
880
881 /** @var QueryBuilder|ObjectProphecy $queryBuilderProphecy */
882 $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
883 $queryBuilderProphecy->expr()->willReturn(
884 new ExpressionBuilder($connectionProphecy->reveal())
885 );
886
887 /** @var ConnectionPool|ObjectProphecy $databaseProphecy */
888 $databaseProphecy = $this->prophesize(ConnectionPool::class);
889 $databaseProphecy->getQueryBuilderForTable('pages')->willReturn($queryBuilderProphecy->reveal());
890 // Shift previously added instance
891 GeneralUtility::makeInstance(ConnectionPool::class);
892 GeneralUtility::addInstance(ConnectionPool::class, $databaseProphecy->reveal());
893 }
894
895 /** @var BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject $subject */
896 $subject = $this->getMockBuilder(BackendUserAuthentication::class)
897 ->setMethods(['isAdmin'])
898 ->getMock();
899 $subject->setLogger(new NullLogger());
900 $subject->expects($this->any())
901 ->method('isAdmin')
902 ->will($this->returnValue($admin));
903
904 $subject->user = ['uid' => 123];
905 $subject->groupList = $groups;
906
907 $this->assertEquals($expected, $subject->getPagePermsClause($perms));
908 }
909 }