TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
BackendUserAuthenticationTest.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Authentication;
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;
27 
32 {
37  // File permissions
38  'addFile' => false,
39  'readFile' => false,
40  'writeFile' => false,
41  'copyFile' => false,
42  'moveFile' => false,
43  'renameFile' => false,
44  'deleteFile' => false,
45  // Folder permissions
46  'addFolder' => false,
47  'readFolder' => false,
48  'writeFolder' => false,
49  'copyFolder' => false,
50  'moveFolder' => false,
51  'renameFolder' => false,
52  'deleteFolder' => false,
53  'recursivedeleteFolder' => false
54  ];
55 
56  protected function setUp()
57  {
58  // reset hooks
59  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'] = [];
60  }
61 
62  protected function tearDown()
63  {
65  parent::tearDown();
66  }
67 
69  // Tests concerning the form protection
71 
74  public function logoffCleansFormProtectionIfBackendUserIsLoggedIn()
75  {
77  $connection = $this->prophesize(Connection::class);
78  $connection->delete('sys_lockedrecords', Argument::cetera())->willReturn(1);
79 
81  $connectionPool = $this->prophesize(ConnectionPool::class);
82  $connectionPool->getConnectionForTable(Argument::cetera())->willReturn($connection->reveal());
83 
84  GeneralUtility::addInstance(ConnectionPool::class, $connectionPool->reveal());
85 
87  $connection = $this->prophesize(Connection::class);
88  $connection->delete('be_sessions', Argument::cetera())->willReturn(1);
89 
91  $connectionPool = $this->prophesize(ConnectionPool::class);
92  $connectionPool->getConnectionForTable(Argument::cetera())->willReturn($connection->reveal());
93 
94  GeneralUtility::addInstance(ConnectionPool::class, $connectionPool->reveal());
95 
97  $formProtection = $this->prophesize(\TYPO3\CMS\Core\FormProtection\BackendFormProtection::class);
98  $formProtection->clean()->shouldBeCalled();
99 
101  'default',
102  $formProtection->reveal()
103  );
104 
105  // logoff() call the static factory that has a dependency to a valid BE_USER object. Mock this away
106  $GLOBALS['BE_USER'] = $this->createMock(BackendUserAuthentication::class);
107  $GLOBALS['BE_USER']->user = ['uid' => $this->getUniqueId()];
108 
110  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
111  ->setMethods(['dummy'])
112  ->disableOriginalConstructor()
113  ->getMock();
114  $subject->logoff();
115  }
116 
120  public function getTSConfigDataProvider()
121  {
122  $completeConfiguration = [
123  'value' => 'oneValue',
124  'value.' => ['oneProperty' => 'oneValue'],
125  'permissions.' => [
126  'file.' => [
127  'default.' => ['readAction' => '1'],
128  '1.' => ['writeAction' => '1'],
129  '0.' => ['readAction' => '0'],
130  ],
131  ]
132  ];
133 
134  return [
135  'single level string' => [
136  $completeConfiguration,
137  'permissions',
138  [
139  'value' => null,
140  'properties' =>
141  [
142  'file.' => [
143  'default.' => ['readAction' => '1'],
144  '1.' => ['writeAction' => '1'],
145  '0.' => ['readAction' => '0'],
146  ],
147  ],
148  ],
149  ],
150  'two levels string' => [
151  $completeConfiguration,
152  'permissions.file',
153  [
154  'value' => null,
155  'properties' =>
156  [
157  'default.' => ['readAction' => '1'],
158  '1.' => ['writeAction' => '1'],
159  '0.' => ['readAction' => '0'],
160  ],
161  ],
162  ],
163  'three levels string' => [
164  $completeConfiguration,
165  'permissions.file.default',
166  [
167  'value' => null,
168  'properties' =>
169  ['readAction' => '1'],
170  ],
171  ],
172  'three levels string with integer property' => [
173  $completeConfiguration,
174  'permissions.file.1',
175  [
176  'value' => null,
177  'properties' => ['writeAction' => '1'],
178  ],
179  ],
180  'three levels string with integer zero property' => [
181  $completeConfiguration,
182  'permissions.file.0',
183  [
184  'value' => null,
185  'properties' => ['readAction' => '0'],
186  ],
187  ],
188  'four levels string with integer zero property, value, no properties' => [
189  $completeConfiguration,
190  'permissions.file.0.readAction',
191  [
192  'value' => '0',
193  'properties' => null,
194  ],
195  ],
196  'four levels string with integer property, value, no properties' => [
197  $completeConfiguration,
198  'permissions.file.1.writeAction',
199  [
200  'value' => '1',
201  'properties' => null,
202  ],
203  ],
204  'one level, not existent string' => [
205  $completeConfiguration,
206  'foo',
207  [
208  'value' => null,
209  'properties' => null,
210  ],
211  ],
212  'two level, not existent string' => [
213  $completeConfiguration,
214  'foo.bar',
215  [
216  'value' => null,
217  'properties' => null,
218  ],
219  ],
220  'two level, where second level does not exist' => [
221  $completeConfiguration,
222  'permissions.bar',
223  [
224  'value' => null,
225  'properties' => null,
226  ],
227  ],
228  'three level, where third level does not exist' => [
229  $completeConfiguration,
230  'permissions.file.foo',
231  [
232  'value' => null,
233  'properties' => null,
234  ],
235  ],
236  'three level, where second and third level does not exist' => [
237  $completeConfiguration,
238  'permissions.foo.bar',
239  [
240  'value' => null,
241  'properties' => null,
242  ],
243  ],
244  'value and properties' => [
245  $completeConfiguration,
246  'value',
247  [
248  'value' => 'oneValue',
249  'properties' => ['oneProperty' => 'oneValue'],
250  ],
251  ],
252  ];
253  }
254 
262  public function getTSConfigReturnsCorrectArrayForGivenObjectString(array $completeConfiguration, $objectString, array $expectedConfiguration)
263  {
264  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
265  ->setMethods(['dummy'])
266  ->disableOriginalConstructor()
267  ->getMock();
268  $subject->userTS = $completeConfiguration;
269 
270  $actualConfiguration = $subject->getTSConfig($objectString);
271  $this->assertSame($expectedConfiguration, $actualConfiguration);
272  }
273 
278  {
279  return [
280  'Only read permissions' => [
281  [
282  'addFile' => 0,
283  'readFile' => 1,
284  'writeFile' => 0,
285  'copyFile' => 0,
286  'moveFile' => 0,
287  'renameFile' => 0,
288  'deleteFile' => 0,
289  'addFolder' => 0,
290  'readFolder' => 1,
291  'copyFolder' => 0,
292  'moveFolder' => 0,
293  'renameFolder' => 0,
294  'writeFolder' => 0,
295  'deleteFolder' => 0,
296  'recursivedeleteFolder' => 0,
297  ]
298  ],
299  'Uploading allowed' => [
300  [
301  'addFile' => 1,
302  'readFile' => 1,
303  'writeFile' => 1,
304  'copyFile' => 1,
305  'moveFile' => 1,
306  'renameFile' => 1,
307  'deleteFile' => 1,
308  'addFolder' => 0,
309  'readFolder' => 1,
310  'copyFolder' => 0,
311  'moveFolder' => 0,
312  'renameFolder' => 0,
313  'writeFolder' => 0,
314  'deleteFolder' => 0,
315  'recursivedeleteFolder' => 0
316  ]
317  ],
318  'One value is enough' => [
319  [
320  'addFile' => 1,
321  ]
322  ],
323  ];
324  }
325 
332  {
333  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
334  ->setMethods(['isAdmin'])
335  ->getMock();
336 
337  $subject
338  ->expects($this->any())
339  ->method('isAdmin')
340  ->will($this->returnValue(false));
341 
342  $subject->userTS = [
343  'permissions.' => [
344  'file.' => [
345  'default.' => $userTsConfiguration
346  ],
347  ]
348  ];
349 
350  $expectedPermissions = array_merge($this->defaultFilePermissions, $userTsConfiguration);
351  array_walk(
352  $expectedPermissions,
353  function (&$value) {
354  $value = (bool)$value;
355  }
356  );
357 
358  $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
359  }
360 
365  {
366  $defaultPermissions = [
367  'addFile' => true,
368  'readFile' => true,
369  'writeFile' => true,
370  'copyFile' => true,
371  'moveFile' => true,
372  'renameFile' => true,
373  'deleteFile' => true,
374  'addFolder' => true,
375  'readFolder' => true,
376  'copyFolder' => true,
377  'moveFolder' => true,
378  'renameFolder' => true,
379  'writeFolder' => true,
380  'deleteFolder' => true,
381  'recursivedeleteFolder' => true
382  ];
383 
384  return [
385  'Overwrites given storage permissions with default permissions' => [
386  $defaultPermissions,
387  1,
388  [
389  'addFile' => 0,
390  'recursivedeleteFolder' =>0
391  ],
392  [
393  'addFile' => 0,
394  'readFile' => 1,
395  'writeFile' => 1,
396  'copyFile' => 1,
397  'moveFile' => 1,
398  'renameFile' => 1,
399  'deleteFile' => 1,
400  'addFolder' => 1,
401  'readFolder' => 1,
402  'copyFolder' => 1,
403  'moveFolder' => 1,
404  'renameFolder' => 1,
405  'writeFolder' => 1,
406  'deleteFolder' => 1,
407  'recursivedeleteFolder' => 0
408  ]
409  ],
410  'Overwrites given storage 0 permissions with default permissions' => [
411  $defaultPermissions,
412  0,
413  [
414  'addFile' => 0,
415  'recursivedeleteFolder' =>0
416  ],
417  [
418  'addFile' => false,
419  'readFile' => true,
420  'writeFile' => true,
421  'copyFile' => true,
422  'moveFile' => true,
423  'renameFile' => true,
424  'deleteFile' => true,
425  'addFolder' => true,
426  'readFolder' => true,
427  'copyFolder' => true,
428  'moveFolder' => true,
429  'renameFolder' => true,
430  'writeFolder' => true,
431  'deleteFolder' => true,
432  'recursivedeleteFolder' => false
433  ]
434  ],
435  'Returns default permissions if no storage permissions are found' => [
436  $defaultPermissions,
437  1,
438  [],
439  [
440  'addFile' => true,
441  'readFile' => true,
442  'writeFile' => true,
443  'copyFile' => true,
444  'moveFile' => true,
445  'renameFile' => true,
446  'deleteFile' => true,
447  'addFolder' => true,
448  'readFolder' => true,
449  'copyFolder' => true,
450  'moveFolder' => true,
451  'renameFolder' => true,
452  'writeFolder' => true,
453  'deleteFolder' => true,
454  'recursivedeleteFolder' => true
455  ]
456  ],
457  ];
458  }
459 
468  public function getFilePermissionsFromStorageOverwritesDefaultPermissions(array $defaultPermissions, $storageUid, array $storagePermissions, array $expectedPermissions)
469  {
470  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
471  ->setMethods(['isAdmin', 'getFilePermissions'])
472  ->getMock();
473  $storageMock = $this->createMock(\TYPO3\CMS\Core\Resource\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 
506  public function getFilePermissionsFromStorageAlwaysReturnsDefaultPermissionsForAdmins(array $defaultPermissions, $storageUid, array $storagePermissions)
507  {
508  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
509  ->setMethods(['isAdmin', 'getFilePermissions'])
510  ->getMock();
511  $storageMock = $this->createMock(\TYPO3\CMS\Core\Resource\ResourceStorage::class);
512  $storageMock->expects($this->any())->method('getUid')->will($this->returnValue($storageUid));
513 
514  $subject
515  ->expects($this->any())
516  ->method('isAdmin')
517  ->will($this->returnValue(true));
518 
519  $subject
520  ->expects($this->any())
521  ->method('getFilePermissions')
522  ->will($this->returnValue($defaultPermissions));
523 
524  $subject->userTS = [
525  'permissions.' => [
526  'file.' => [
527  'storage.' => [
528  $storageUid . '.' => $storagePermissions
529  ],
530  ],
531  ]
532  ];
533 
534  $this->assertEquals($defaultPermissions, $subject->getFilePermissionsForStorage($storageMock));
535  }
536 
541  {
542  return [
543  'No permission' => [
544  '',
545  [
546  'addFile' => false,
547  'readFile' => false,
548  'writeFile' => false,
549  'copyFile' => false,
550  'moveFile' => false,
551  'renameFile' => false,
552  'deleteFile' => false,
553  'addFolder' => false,
554  'readFolder' => false,
555  'copyFolder' => false,
556  'moveFolder' => false,
557  'renameFolder' => false,
558  'writeFolder' => false,
559  'deleteFolder' => false,
560  'recursivedeleteFolder' => false
561  ]
562  ],
563  'Standard file permissions' => [
564  'addFile,readFile,writeFile,copyFile,moveFile,renameFile,deleteFile',
565  [
566  'addFile' => true,
567  'readFile' => true,
568  'writeFile' => true,
569  'copyFile' => true,
570  'moveFile' => true,
571  'renameFile' => true,
572  'deleteFile' => true,
573  'addFolder' => false,
574  'readFolder' => false,
575  'copyFolder' => false,
576  'moveFolder' => false,
577  'renameFolder' => false,
578  'writeFolder' => false,
579  'deleteFolder' => false,
580  'recursivedeleteFolder' => false
581  ]
582  ],
583  'Standard folder permissions' => [
584  'addFolder,readFolder,moveFolder,renameFolder,writeFolder,deleteFolder',
585  [
586  'addFile' => false,
587  'readFile' => false,
588  'writeFile' => false,
589  'copyFile' => false,
590  'moveFile' => false,
591  'renameFile' => false,
592  'deleteFile' => false,
593  'addFolder' => true,
594  'readFolder' => true,
595  'writeFolder' => true,
596  'copyFolder' => false,
597  'moveFolder' => true,
598  'renameFolder' => true,
599  'deleteFolder' => true,
600  'recursivedeleteFolder' => false
601  ]
602  ],
603  'Copy folder allowed' => [
604  'readFolder,copyFolder',
605  [
606  'addFile' => false,
607  'readFile' => false,
608  'writeFile' => false,
609  'copyFile' => false,
610  'moveFile' => false,
611  'renameFile' => false,
612  'deleteFile' => false,
613  'addFolder' => false,
614  'readFolder' => true,
615  'writeFolder' => false,
616  'copyFolder' => true,
617  'moveFolder' => false,
618  'renameFolder' => false,
619  'deleteFolder' => false,
620  'recursivedeleteFolder' => false
621  ]
622  ],
623  'Copy folder and remove subfolders allowed' => [
624  'readFolder,copyFolder,recursivedeleteFolder',
625  [
626  'addFile' => false,
627  'readFile' => false,
628  'writeFile' => false,
629  'copyFile' => false,
630  'moveFile' => false,
631  'renameFile' => false,
632  'deleteFile' => false,
633  'addFolder' => false,
634  'readFolder' => true,
635  'writeFolder' => false,
636  'copyFolder' => true,
637  'moveFolder' => false,
638  'renameFolder' => false,
639  'deleteFolder' => false,
640  'recursivedeleteFolder' => true
641  ]
642  ],
643  ];
644  }
645 
650  public function getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdmin($permissionValue, $expectedPermissions)
651  {
652  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
653  ->setMethods(['isAdmin'])
654  ->getMock();
655 
656  $subject
657  ->expects($this->any())
658  ->method('isAdmin')
659  ->will($this->returnValue(false));
660 
661  $subject->userTS = [];
662  $subject->groupData['file_permissions'] = $permissionValue;
663  $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
664  }
665 
670  {
671  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
672  ->setMethods(['isAdmin'])
673  ->getMock();
674 
675  $subject
676  ->expects($this->any())
677  ->method('isAdmin')
678  ->will($this->returnValue(true));
679 
680  $expectedPermissions = [
681  'addFile' => true,
682  'readFile' => true,
683  'writeFile' => true,
684  'copyFile' => true,
685  'moveFile' => true,
686  'renameFile' => true,
687  'deleteFile' => true,
688  'addFolder' => true,
689  'readFolder' => true,
690  'writeFolder' => true,
691  'copyFolder' => true,
692  'moveFolder' => true,
693  'renameFolder' => true,
694  'deleteFolder' => true,
695  'recursivedeleteFolder' => true
696  ];
697 
698  $this->assertEquals($expectedPermissions, $subject->getFilePermissions());
699  }
700 
705  {
706  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
707  ->setMethods(['getTSConfig'])
708  ->getMock();
709  $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 1]);
710 
711  $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
712  $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
713  }
714 
719  {
720  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
721  ->setMethods(['getTSConfig'])
722  ->getMock();
723  $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 3]);
724 
725  $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
726  $this->assertTrue($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
727  }
728 
733  {
734  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
735  ->setMethods(['getTSConfig'])
736  ->getMock();
737  $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => 0]);
738 
739  $this->assertFalse($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
740  $this->assertFalse($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE));
741  }
742 
747  {
748  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
749  ->setMethods(['getTSConfig'])
750  ->getMock();
751 
752  $this->assertTrue($subject->jsConfirmation(JsConfirmation::TYPE_CHANGE));
753  }
754 
766  {
767  return [
768  'for admin' => [
769  1,
770  true,
771  '',
772  ' 1=1'
773  ],
774  'for admin with groups' => [
775  11,
776  true,
777  '1,2',
778  ' 1=1'
779  ],
780  'for user' => [
781  2,
782  false,
783  '',
784  ' ((`pages`.`perms_everybody` & 2 = 2) OR' .
785  ' ((`pages`.`perms_userid` = 123) AND (`pages`.`perms_user` & 2 = 2)))'
786  ],
787  'for user with groups' => [
788  8,
789  false,
790  '1,2',
791  ' ((`pages`.`perms_everybody` & 8 = 8) OR' .
792  ' ((`pages`.`perms_userid` = 123) AND (`pages`.`perms_user` & 8 = 8))' .
793  ' OR ((`pages`.`perms_groupid` IN (1, 2)) AND (`pages`.`perms_group` & 8 = 8)))'
794  ],
795  ];
796  }
797 
806  public function getPagePermissionsClauseWithValidUser(int $perms, bool $admin, string $groups, string $expected)
807  {
808  // We only need to setup the mocking for the non-admin cases
809  // If this setup is done for admin cases the FIFO behavior
810  // of GeneralUtility::addInstance will influence other tests
811  // as the ConnectionPool is never used!
812  if (!$admin) {
814  $connectionProphet = $this->prophesize(Connection::class);
815  $connectionProphet->getDatabasePlatform()->willReturn(new MockPlatform());
816  $connectionProphet->quoteIdentifier(Argument::cetera())->will(function ($args) {
817  return '`' . str_replace('.', '`.`', $args[0]) . '`';
818  });
819 
821  $queryBuilderProphet = $this->prophesize(QueryBuilder::class);
822  $queryBuilderProphet->expr()->willReturn(
823  GeneralUtility::makeInstance(ExpressionBuilder::class, $connectionProphet->reveal())
824  );
825 
827  $databaseProphet = $this->prophesize(ConnectionPool::class);
828  $databaseProphet->getQueryBuilderForTable('pages')->willReturn($queryBuilderProphet->reveal());
829  GeneralUtility::addInstance(ConnectionPool::class, $databaseProphet->reveal());
830  }
831 
833  $subject = $this->getMockBuilder(BackendUserAuthentication::class)
834  ->setMethods(['isAdmin'])
835  ->getMock();
836  $subject->expects($this->any())
837  ->method('isAdmin')
838  ->will($this->returnValue($admin));
839 
840  $subject->user = ['uid' => 123];
841  $subject->groupList = $groups;
842 
843  $this->assertEquals($expected, $subject->getPagePermsClause($perms));
844  }
845 }
getFilePermissionsTakesUserDefaultPermissionsFromRecordIntoAccountIfUserIsNotAdmin($permissionValue, $expectedPermissions)
static set($classNameOrType, AbstractFormProtection $instance)
getFilePermissionsFromStorageOverwritesDefaultPermissions(array $defaultPermissions, $storageUid, array $storagePermissions, array $expectedPermissions)
getFilePermissionsFromStorageAlwaysReturnsDefaultPermissionsForAdmins(array $defaultPermissions, $storageUid, array $storagePermissions)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
getTSConfigReturnsCorrectArrayForGivenObjectString(array $completeConfiguration, $objectString, array $expectedConfiguration)
static addInstance($className, $instance)