[SECURITY] Check permissions in all actions of ResourceStorage 95/23595/2
authorSteffen Ritter <info@rs-websystems.de>
Wed, 4 Sep 2013 11:13:48 +0000 (13:13 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Wed, 4 Sep 2013 11:13:52 +0000 (13:13 +0200)
The ResourceStorage omits checks for the configured user and
group permissions within the actions on that Storage.

This patch refines some naming within the security methods
as well as adding security checks to every method.

PHP file extensions are now also removed from the
text file extension list.

Releases: 6.2, 6.1, 6.0
Fixes: #51079
Change-Id: I95a6d89da7eb2b6ea52afea1c49b1df8acb00707
Security-Commit: f5d926ec7a99098ad42117cf2e0b3b67dae057a4
Security-Bulletin: TYPO3-CORE-SA-2013-003
Reviewed-on: https://review.typo3.org/23595
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
typo3/sysext/backend/Classes/Controller/File/CreateFolderController.php
typo3/sysext/backend/Classes/Controller/File/EditFileController.php
typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php
typo3/sysext/core/Classes/Resource/ResourceStorage.php
typo3/sysext/core/Classes/Resource/Service/UserFileMountService.php
typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php
typo3/sysext/core/Tests/Unit/Resource/ResourceStorageTest.php
typo3/sysext/filelist/Classes/Controller/FileListController.php
typo3/sysext/filelist/Classes/FileList.php

index 9c68e72..26e3abb 100644 (file)
@@ -153,82 +153,87 @@ class CreateFolderController {
                // Start content compilation
                $this->content .= $this->doc->startPage($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle'));
                // Make page header:
-               $pageContent = '';
-               $pageContent .= $this->doc->header($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle'));
+               $pageContent = $this->doc->header($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle'));
                $pageContent .= $this->doc->spacer(5);
                $pageContent .= $this->doc->divider(5);
-               $code = '<form action="tce_file.php" method="post" name="editform">';
-               // Making the selector box for the number of concurrent folder-creations
-               $this->number = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->number, 1, 10);
-               $code .= '
-                       <div id="c-select">
-                               <label for="number-of-new-folders">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.number_of_folders') . '</label>
-                               <select name="number" id="number-of-new-folders" onchange="reload(this.options[this.selectedIndex].value);">';
-               for ($a = 1; $a <= $this->folderNumber; $a++) {
-                       $code .= '<option value="' . $a . '"' . ($this->number == $a ? ' selected="selected"' : '') . '>' . $a . '</option>';
-               }
-               $code .= '
-                               </select>
-                       </div>
+               if ($this->folderObject->checkActionPermission('add')) {
+                       $code = '<form action="tce_file.php" method="post" name="editform">';
+                       // Making the selector box for the number of concurrent folder-creations
+                       $this->number = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->number, 1, 10);
+                       $code .= '
+                               <div id="c-select">
+                                       <label for="number-of-new-folders">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.number_of_folders') . '</label>
+                                       <select name="number" id="number-of-new-folders" onchange="reload(this.options[this.selectedIndex].value);">';
+                       for ($a = 1; $a <= $this->folderNumber; $a++) {
+                               $code .= '<option value="' . $a . '"' . ($this->number == $a ? ' selected="selected"' : '') . '>' . $a . '</option>';
+                       }
+                       $code .= '
+                                       </select>
+                               </div>
+                               ';
+                       // Making the number of new-folder boxes needed:
+                       $code .= '
+                               <div id="c-createFolders">
+                       ';
+                       for ($a = 0; $a < $this->number; $a++) {
+                               $code .= '
+                                               <input' . $this->doc->formWidth(20) . ' type="text" name="file[newfolder][' . $a . '][data]" onchange="changed=true;" />
+                                               <input type="hidden" name="file[newfolder][' . $a . '][target]" value="' . htmlspecialchars($this->target) . '" /><br />
+                                       ';
+                       }
+                       $code .= '
+                               </div>
                        ';
-               // Making the number of new-folder boxes needed:
-               $code .= '
-                       <div id="c-createFolders">
-               ';
-               for ($a = 0; $a < $this->number; $a++) {
+                       // Making submit button for folder creation:
                        $code .= '
-                                       <input' . $this->doc->formWidth(20) . ' type="text" name="file[newfolder][' . $a . '][data]" onchange="changed=true;" />
-                                       <input type="hidden" name="file[newfolder][' . $a . '][target]" value="' . htmlspecialchars($this->target) . '" /><br />
+                               <div id="c-submitFolders">
+                                       <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.submit', TRUE) . '" />
+                                       <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.cancel', TRUE) . '" onclick="backToList(); return false;" />
+                                       <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
+                               </div>
                                ';
+                       // CSH:
+                       $code .= BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder', $GLOBALS['BACK_PATH'], '<br />');
+                       $pageContent .= $code;
+                       // Add spacer:
+                       $pageContent .= $this->doc->spacer(10);
+                       // Switching form tags:
+                       $pageContent .= $this->doc->sectionEnd() . '</form>';
                }
-               $code .= '
-                       </div>
-               ';
-               // Making submit button for folder creation:
-               $code .= '
-                       <div id="c-submitFolders">
-                               <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.submit', TRUE) . '" />
-                               <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.cancel', TRUE) . '" onclick="backToList(); return false;" />
-                               <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
-                       </div>
-                       ';
-               // CSH:
-               $code .= BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder', $GLOBALS['BACK_PATH'], '<br />');
-               $pageContent .= $code;
-               // Add spacer:
-               $pageContent .= $this->doc->spacer(10);
-               // Switching form tags:
-               $pageContent .= $this->doc->sectionEnd();
-               $pageContent .= '</form><form action="tce_file.php" method="post" name="editform2">';
-               // Create a list of allowed file extensions with the nice format "*.jpg, *.gif" etc.
-               $fileExtList = array();
-               $textfileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], TRUE);
-               foreach ($textfileExt as $fileExt) {
-                       if (!preg_match(('/' . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] . '/i'), ('.' . $fileExt))) {
-                               $fileExtList[] = '*.' . $fileExt;
+
+               if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) {
+                       $pageContent .= '<form action="tce_file.php" method="post" name="editform2">';
+                       // Create a list of allowed file extensions with the nice format "*.jpg, *.gif" etc.
+                       $fileExtList = array();
+                       $textfileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], TRUE);
+                       foreach ($textfileExt as $fileExt) {
+                               if (!preg_match(('/' . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] . '/i'), ('.' . $fileExt))) {
+                                       $fileExtList[] = '*.' . $fileExt;
+                               }
                        }
+                       // Add form fields for creation of a new, blank text file:
+                       $code = '
+                               <div id="c-newFile">
+                                       <p>[' . htmlspecialchars(implode(', ', $fileExtList)) . ']</p>
+                                       <input' . $this->doc->formWidth(20) . ' type="text" name="file[newfile][0][data]" onchange="changed=true;" />
+                                       <input type="hidden" name="file[newfile][0][target]" value="' . htmlspecialchars($this->target) . '" />
+                               </div>
+                               ';
+                       // Submit button for creation of a new file:
+                       $code .= '
+                               <div id="c-submitFiles">
+                                       <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile_submit', TRUE) . '" />
+                                       <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.cancel', TRUE) . '" onclick="backToList(); return false;" />
+                                       <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
+                               </div>
+                               ';
+                       // CSH:
+                       $code .= BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile', $GLOBALS['BACK_PATH'], '<br />');
+                       $pageContent .= $this->doc->section($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile'), $code);
+                       $pageContent .= $this->doc->sectionEnd();
+                       $pageContent .= '</form>';
                }
-               // Add form fields for creation of a new, blank text file:
-               $code = '
-                       <div id="c-newFile">
-                               <p>[' . htmlspecialchars(implode(', ', $fileExtList)) . ']</p>
-                               <input' . $this->doc->formWidth(20) . ' type="text" name="file[newfile][0][data]" onchange="changed=true;" />
-                               <input type="hidden" name="file[newfile][0][target]" value="' . htmlspecialchars($this->target) . '" />
-                       </div>
-                       ';
-               // Submit button for creation of a new file:
-               $code .= '
-                       <div id="c-submitFiles">
-                               <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile_submit', TRUE) . '" />
-                               <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.cancel', TRUE) . '" onclick="backToList(); return false;" />
-                               <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" />
-                       </div>
-                       ';
-               // CSH:
-               $code .= BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile', $GLOBALS['BACK_PATH'], '<br />');
-               $pageContent .= $this->doc->section($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile'), $code);
-               $pageContent .= $this->doc->sectionEnd();
-               $pageContent .= '</form>';
+
                $docHeaderButtons = array(
                        'back' => ''
                );
index 00b5855..2584026 100644 (file)
@@ -153,7 +153,10 @@ class EditFileController {
                $pageContent .= $this->doc->spacer(2);
                $code = '';
                $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
-               if ($extList && GeneralUtility::inList($extList, $this->fileObject->getExtension())) {
+               try {
+                       if (!$extList || !GeneralUtility::inList($extList, $this->fileObject->getExtension())) {
+                               throw new \Exception('Files with that extension are not editable.');
+                       }
                        // Read file content to edit:
                        $fileContent = $this->fileObject->getContents();
                        // Making the formfields
@@ -173,7 +176,7 @@ class EditFileController {
                        } else {
                                $docHeaderButtons['shortcut'] = '';
                        }
-               } else {
+               } catch (\Exception $e) {
                        $code .= sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:file_edit.php.coundNot'), $extList);
                }
                // Ending of section and outputting editing form:
index 28f594b..142d268 100644 (file)
@@ -1550,29 +1550,27 @@ class BackendUserAuthentication extends \TYPO3\CMS\Core\Authentication\AbstractU
         * permissions.file.default {
         * addFile = 1
         * readFile = 1
-        * editFile = 1
         * writeFile = 1
-        * uploadFile = 1
         * copyFile = 1
         * moveFile = 1
         * renameFile = 1
         * unzipFile = 1
-        * removeFile = 1
+        * deleteFile = 1
         *
         * addFolder = 1
         * readFolder = 1
+        * writeFolder = 1
         * copyFolder = 1
         * moveFolder = 1
-        * writeFolder = 1
         * renameFolder = 1
-        * removeFolder = 1
-        * removeSubfolders = 1
+        * deleteFolder = 1
+        * recursivedeleteFolder = 1
         * }
         *
         * # overwrite settings for a specific storageObject
         * permissions.file.storage.StorageUid {
-        * readFile = 0
-        * removeSubfolders = 1
+        * readFile = 1
+        * recursivedeleteFolder = 0
         * }
         *
         * Please note that these permissions only apply, if the storage has the
@@ -1587,23 +1585,21 @@ class BackendUserAuthentication extends \TYPO3\CMS\Core\Authentication\AbstractU
                                // File permissions
                                'addFile' => TRUE,
                                'readFile' => TRUE,
-                               'editFile' => TRUE,
                                'writeFile' => TRUE,
-                               'uploadFile' => TRUE,
                                'copyFile' => TRUE,
                                'moveFile' => TRUE,
                                'renameFile' => TRUE,
                                'unzipFile' => TRUE,
-                               'removeFile' => TRUE,
+                               'deleteFile' => TRUE,
                                // Folder permissions
                                'addFolder' => TRUE,
                                'readFolder' => TRUE,
+                               'writeFolder' => TRUE,
                                'copyFolder' => TRUE,
                                'moveFolder' => TRUE,
                                'renameFolder' => TRUE,
-                               'writeFolder' => TRUE,
-                               'removeFolder' => TRUE,
-                               'removeSubfolders' => TRUE
+                               'deleteFolder' => TRUE,
+                               'recursivedeleteFolder' => TRUE
                        );
                        if (!$this->isAdmin()) {
                                $defaultPermissionsTsConfig = $this->getTSConfigProp('permissions.file.default');
@@ -1614,29 +1610,27 @@ class BackendUserAuthentication extends \TYPO3\CMS\Core\Authentication\AbstractU
                                        // Lower permissions if the old file operation permissions are not set
                                        if (!($oldFileOperationPermissions & 1)) {
                                                $defaultOptions['addFile'] = FALSE;
-                                               $defaultOptions['uploadFile'] = FALSE;
+                                               $defaultOptions['writeFile'] = FALSE;
                                                $defaultOptions['copyFile'] = FALSE;
                                                $defaultOptions['moveFile'] = FALSE;
                                                $defaultOptions['renameFile'] = FALSE;
-                                               $defaultOptions['removeFile'] = FALSE;
-                                               $defaultOptions['editFile'] = FALSE;
-                                               $defaultOptions['writeFile'] = FALSE;
+                                               $defaultOptions['deleteFile'] = FALSE;
                                        }
                                        if (!($oldFileOperationPermissions & 2)) {
                                                $defaultOptions['unzipFile'] = FALSE;
                                        }
                                        if (!($oldFileOperationPermissions & 4)) {
                                                $defaultOptions['addFolder'] = FALSE;
+                                               $defaultOptions['writeFolder'] = FALSE;
                                                $defaultOptions['moveFolder'] = FALSE;
                                                $defaultOptions['renameFolder'] = FALSE;
-                                               $defaultOptions['removeFolder'] = FALSE;
-                                               $defaultOptions['writeFolder'] = FALSE;
+                                               $defaultOptions['deleteFolder'] = FALSE;
                                        }
                                        if (!($oldFileOperationPermissions & 8)) {
                                                $defaultOptions['copyFolder'] = FALSE;
                                        }
                                        if (!($oldFileOperationPermissions & 16)) {
-                                               $defaultOptions['removeSubfolders'] = FALSE;
+                                               $defaultOptions['recursivedeleteFolder'] = FALSE;
                                        }
                                }
                        }
index 52d484d..5cf4c52 100644 (file)
@@ -501,7 +501,7 @@ class ResourceStorage {
         */
        public function isWithinFileMountBoundaries($subject) {
                $isWithinFilemount = TRUE;
-               if (is_array($this->fileMounts)) {
+               if (is_array($this->fileMounts) && count($this->fileMounts)) {
                        $isWithinFilemount = FALSE;
                        if (!$subject) {
                                $subject = $this->getRootLevelFolder();
@@ -577,17 +577,21 @@ class ResourceStorage {
                if (!$isProcessedFile && $this->checkUserActionPermission($action, 'File') === FALSE) {
                        return FALSE;
                }
-               // Check 2: Does the user have the right to perform the action?
+               // Check 2: No action allowed on files for denied file extensions
+               if (!$this->checkFileExtensionPermission($file->getName())) {
+                       return FALSE;
+               }
+               // Check 3: Does the user have the right to perform the action?
                // (= is he within the file mount borders)
                if (!$isProcessedFile && is_array($this->fileMounts) && count($this->fileMounts) && !$this->isWithinFileMountBoundaries($file)) {
                        return FALSE;
                }
                $isReadCheck = FALSE;
-               if ($action === 'read') {
+               if (in_array($action, array('read', 'copy', 'move'), TRUE)) {
                        $isReadCheck = TRUE;
                }
                $isWriteCheck = FALSE;
-               if (in_array($action, array('add', 'edit', 'write', 'upload', 'move', 'rename', 'unzip', 'remove'))) {
+               if (in_array($action, array('add', 'write', 'move', 'rename', 'unzip', 'delete'), TRUE)) {
                        $isWriteCheck = TRUE;
                }
 
@@ -596,11 +600,11 @@ class ResourceStorage {
                        $isMissing = $file->isMissing();
                }
 
-               // Check 3: Check the capabilities of the storage (and the driver)
+               // Check 4: Check the capabilities of the storage (and the driver)
                if ($isWriteCheck && ($isMissing || !$this->isWritable())) {
                        return FALSE;
                }
-               // Check 4: "File permissions" of the driver (only when file isn't marked as missing)
+               // Check 5: "File permissions" of the driver (only when file isn't marked as missing)
                if (!$isMissing) {
                        $filePermissions = $this->driver->getFilePermissions($file);
                        if ($isReadCheck && !$filePermissions['r']) {
@@ -628,17 +632,23 @@ class ResourceStorage {
                if ($this->checkUserActionPermission($action, 'Folder') === FALSE) {
                        return FALSE;
                }
+
+               // If we do not have a folder here, we cannot do further checks
+               if ($folder === NULL) {
+                       return TRUE;
+               }
+
                // Check 2: Does the user has the right to perform the action?
                // (= is he within the file mount borders)
                if (is_array($this->fileMounts) && count($this->fileMounts) && !$this->isWithinFileMountBoundaries($folder)) {
                        return FALSE;
                }
                $isReadCheck = FALSE;
-               if ($action === 'read') {
+               if (in_array($action, array('read', 'copy'), TRUE)) {
                        $isReadCheck = TRUE;
                }
                $isWriteCheck = FALSE;
-               if (in_array($action, array('add', 'move', 'write', 'remove', 'rename'))) {
+               if (in_array($action, array('add', 'move', 'write', 'delete', 'rename'), TRUE)) {
                        $isWriteCheck = TRUE;
                }
                // Check 3: Check the capabilities of the storage (and the driver)
@@ -699,6 +709,316 @@ class ResourceStorage {
                return FALSE;
        }
 
+       /**
+        * @param Folder $folder If a folder is given, mountpoits are checked. If not only user folder read permissions are checked.
+        *
+        * @throws Exception\InsufficientFolderAccessPermissionsException
+        */
+       protected function assureFolderReadPermission(Folder $folder = NULL) {
+               if (!$this->checkFolderActionPermission('read', $folder)) {
+                       throw new Exception\InsufficientFolderAccessPermissionsException('You are not allowed to access the given folder', 1375955684);
+               }
+       }
+
+       /**
+        * @param Folder $folder If a folder is given, mountpoits are checked. If not only user folder delete permissions are checked.
+        * @param boolean $checkDeleteRecursively
+        *
+        * @throws Exception\InsufficientFolderAccessPermissionsException
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        */
+       protected function assureFolderDeletePermission(Folder $folder, $checkDeleteRecursively) {
+               // Check user permissions for recursive deletion if it is requested
+               if ($checkDeleteRecursively && !$this->checkUserActionPermission('recursivedelete', 'Folder')) {
+                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to delete folders recursively', 1377779423);
+               }
+               // Check user action permission
+               if (!$this->checkFolderActionPermission('delete', $folder)) {
+                       throw new Exception\InsufficientFolderAccessPermissionsException('You are not allowed to delete the given folder', 1377779039);
+               }
+               // Check if the user has write permissions to folders
+               // Would be good if we could check for actual write permissions in the containig folder
+               // but we cannot since we have no access to the containing folder of this file.
+               if (!$this->checkUserActionPermission('write', 'Folder')) {
+                       throw new Exception\InsufficientFolderWritePermissionsException('Writing to folders is not allowed.', 1377779111);
+               }
+       }
+
+       /**
+        * @param FileInterface $file
+        *
+        * @throws Exception\InsufficientFileAccessPermissionsException
+        * @throws Exception\IllegalFileExtensionException
+        */
+       protected function assureFileReadPermission(FileInterface $file) {
+               if (!$this->checkFileActionPermission('read', $file)) {
+                       throw new Exception\InsufficientFileAccessPermissionsException('You are not allowed to access that file.', 1375955429);
+               }
+               if (!$this->checkFileExtensionPermission($file->getName())) {
+                       throw new Exception\IllegalFileExtensionException('You are not allowed to use that file extension', 1375955430);
+               }
+       }
+
+       /**
+        * @param FileInterface $file
+        *
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileWritePermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        */
+       protected function assureFileWritePermissions(FileInterface $file) {
+               // Check if user is allowed to write the file and $file is writable
+               if (!$this->checkFileActionPermission('write', $file)) {
+                       throw new Exception\InsufficientFileWritePermissionsException('Writing to file "' . $file->getIdentifier() . '" is not allowed.', 1330121088);
+               }
+               if (!$this->checkFileExtensionPermission($file->getName())) {
+                       throw new Exception\IllegalFileExtensionException('You are not allowed to edit a file with extension "' . $file->getExtension() . '"', 1366711933);
+               }
+       }
+
+       /**
+        * @param FileInterface $file
+        *
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileWritePermissionsException
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        */
+       protected function assureFileDeletePermissions(FileInterface $file) {
+               // Check for disallowed file extensions
+               if (!$this->checkFileExtensionPermission($file->getName())) {
+                       throw new Exception\IllegalFileExtensionException('You are not allowed to delete a file with extension "' . $file->getExtension() . '"', 1377778916);
+               }
+               // Check further permissions if file is not a processed file
+               if (!$file instanceof ProcessedFile) {
+                       // Check if user is allowed to delete the file and $file is writable
+                       if (!$this->checkFileActionPermission('delete', $file)) {
+                               throw new Exception\InsufficientFileWritePermissionsException('You are not allowed to delete the file "' . $file->getIdentifier() . '\'', 1319550425);
+                       }
+                       // Check if the user has write permissions to folders
+                       // Would be good if we could check for actual write permissions in the containig folder
+                       // but we cannot since we have no access to the containing folder of this file.
+                       if (!$this->checkUserActionPermission('write', 'Folder')) {
+                               throw new Exception\InsufficientFolderWritePermissionsException('Writing to folders is not allowed.', 1377778702);
+                       }
+               }
+       }
+
+       /**
+        * Check if a file has the permission to be uploaded to a Folder/Storage,
+        * if not throw an exception
+        *
+        * @param string $localFilePath the temporary file name from $_FILES['file1']['tmp_name']
+        * @param Folder $targetFolder
+        * @param string $targetFileName the destination file name $_FILES['file1']['name']
+        *
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\UploadException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\UploadSizeException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFileAddPermissions($localFilePath, $targetFolder, $targetFileName) {
+               // Check for a valid file extension
+               if (!$this->checkFileExtensionPermission($targetFileName) || ($localFilePath && !$this->checkFileExtensionPermission($localFilePath))) {
+                       throw new Exception\IllegalFileExtensionException('Extension of file name is not allowed in "' . $targetFileName . '"!', 1322120271);
+               }
+               // Makes sure the user is allowed to upload
+               if (!$this->checkUserActionPermission('add', 'File')) {
+                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to add files to this storage "' . $this->getUid() . '"', 1376992145);
+               }
+               // Check if targetFolder is writable
+               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
+                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1322120356);
+               }
+       }
+
+       /**
+        * Check if a file has the permission to be uploaded to a Folder/Storage,
+        * if not throw an exception
+        *
+        * @param string $localFilePath the temporary file name from $_FILES['file1']['tmp_name']
+        * @param Folder $targetFolder
+        * @param string $targetFileName the destination file name $_FILES['file1']['name']
+        * @param integer $uploadedFileSize
+        *
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\UploadException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\UploadSizeException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileSize) {
+               // Makes sure this is an uploaded file
+               if (!is_uploaded_file($localFilePath)) {
+                       throw new Exception\UploadException('The upload has failed, no uploaded file found!', 1322110455);
+               }
+               // Max upload size (kb) for files.
+               $maxUploadFileSize = GeneralUtility::getMaxUploadFileSize() * 1024;
+               if ($uploadedFileSize >= $maxUploadFileSize) {
+                       unlink($localFilePath);
+                       throw new Exception\UploadSizeException('The uploaded file exceeds the size-limit of ' . $maxUploadFileSize . ' bytes', 1322110041);
+               }
+               $this->assureFileAddPermissions($localFilePath, $targetFolder, $targetFileName);
+       }
+
+       /**
+        * Checks for permissions to move a file.
+        *
+        * @throws \RuntimeException
+        * @throws Exception\InsufficientFileReadPermissionsException
+        * @throws Exception\InsufficientFileWritePermissionsException
+        * @throws Exception\InsufficientFolderAccessPermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @param FileInterface $file
+        * @param Folder $targetFolder
+        * @param string $targetFileName
+        * @return void
+        */
+       protected function assureFileMovePermissions(FileInterface $file, Folder $targetFolder, $targetFileName) {
+               // Check if targetFolder is within this storage
+               if ($this->getUid() !== $targetFolder->getStorage()->getUid()) {
+                       throw new \RuntimeException();
+               }
+               // Check for a valid file extension
+               if (!$this->checkFileExtensionPermission($targetFileName)) {
+                       throw new Exception\IllegalFileExtensionException('Extension of file name is not allowed in "' . $targetFileName . '"!', 1378243279);
+               }
+               // Check if user is allowed to move and $file is readable and writable
+               if (!$this->checkFileActionPermission('move', $file)) {
+                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to move files to storage "' . $this->getUid() . '"', 1319219349);
+               }
+               // Check if target folder is writable
+               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
+                       throw new Exception\InsufficientFolderAccessPermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319219349);
+               }
+       }
+
+       /**
+        * Checks for permissions to rename a file.
+        *
+        * @param FileInterface $file
+        * @param string $targetFileName
+        * @throws Exception\InsufficientFileWritePermissionsException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileReadPermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFileRenamePermissions(FileInterface $file, $targetFileName) {
+               // Check if file extension is allowed
+               if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkFileExtensionPermission($file->getName())) {
+                       throw new Exception\IllegalFileExtensionException('You are not allowed to rename a file with to this extension', 1371466663);
+               }
+               // Check if user is allowed to rename
+               if (!$this->checkFileActionPermission('rename', $file)) {
+                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to rename files."', 1319219349);
+               }
+               // Check if the user is allowed to write to folders
+               // Although it would be good to check, we cannot check here if the folder actually is writable
+               // because we do not know in which folder the file resides.
+               // So we rely on the driver to throw an exception in case the renaming failed.
+               if (!$this->checkFolderActionPermission('write')) {
+                       throw new Exception\InsufficientFileWritePermissionsException('You are not allowed to write to folders', 1319219349);
+               }
+       }
+
+       /**
+        * Check if a file has the permission to be copied on a File/Folder/Storage,
+        * if not throw an exception
+        *
+        * @param FileInterface $file
+        * @param Folder $targetFolder
+        * @param string $targetFileName
+        *
+        * @throws Exception
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileReadPermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFileCopyPermissions(FileInterface $file, Folder $targetFolder, $targetFileName) {
+               // Check if targetFolder is within this storage, this should never happen
+               if ($this->getUid() != $targetFolder->getStorage()->getUid()) {
+                       throw new Exception('The operation of the folder cannot be called by this storage "' . $this->getUid() . '"', 1319550405);
+               }
+               // Check if user is allowed to copy
+               if (!$this->checkFileActionPermission('copy', $file)) {
+                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to copy the file "' . $file->getIdentifier() . '\'', 1319550425);
+               }
+               // Check if targetFolder is writable
+               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
+                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319550435);
+               }
+               // Check for a valid file extension
+               if (!$this->checkFileExtensionPermission($targetFileName) || !$this->checkFileExtensionPermission($file->getName())) {
+                       throw new Exception\IllegalFileExtensionException('You are not allowed to copy a file of that type.', 1319553317);
+               }
+       }
+
+       /**
+        * Check if a file has the permission to be copied on a File/Folder/Storage,
+        * if not throw an exception
+        *
+        * @param FolderInterface $folderToCopy
+        * @param FolderInterface $targetParentFolder
+        *
+        * @throws Exception
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileReadPermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFolderCopyPermissions(FolderInterface $folderToCopy, FolderInterface $targetParentFolder) {
+               // Check if targetFolder is within this storage, this should never happen
+               if ($this->getUid() !== $targetParentFolder->getStorage()->getUid()) {
+                       throw new Exception('The operation of the folder cannot be called by this storage "' . $this->getUid() . '"', 1377777624);
+               }
+               // Check if user is allowed to copy and the folder is readable
+               if (!$this->checkFolderActionPermission('copy', $folderToCopy)) {
+                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to copy the folder "' . $folderToCopy->getIdentifier() . '\'', 1377777629);
+               }
+               // Check if targetFolder is writable
+               if (!$this->checkFolderActionPermission('write', $targetParentFolder)) {
+                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetParentFolder->getIdentifier() . '"', 1377777635);
+               }
+       }
+
+       /**
+        * Check if a file has the permission to be copied on a File/Folder/Storage,
+        * if not throw an exception
+        *
+        * @param FolderInterface $folderToMove
+        * @param FolderInterface $targetParentFolder
+        *
+        * @throws \InvalidArgumentException
+        * @throws Exception\InsufficientFolderWritePermissionsException
+        * @throws Exception\IllegalFileExtensionException
+        * @throws Exception\InsufficientFileReadPermissionsException
+        * @throws Exception\InsufficientUserPermissionsException
+        * @return void
+        */
+       protected function assureFolderMovePermissions(FolderInterface $folderToMove, FolderInterface $targetParentFolder) {
+               // Check if targetFolder is within this storage, this should never happen
+               if ($this->getUid() !== $targetParentFolder->getStorage()->getUid()) {
+                       throw new \InvalidArgumentException('Cannot move a folder into a folder that does not belong to this storage.', 1325777289);
+               }
+               // Check if user is allowed to move and the folder is writable
+               // In fact we would need to check if the parent folder of the folder to move is writable also
+               // But as of now we cannot extract the parent folder from this folder
+               if (!$this->checkFolderActionPermission('move', $folderToMove)) {
+                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to copy the folder "' . $folderToMove->getIdentifier() . '\'', 1377778045);
+               }
+               // Check if targetFolder is writable
+               if (!$this->checkFolderActionPermission('write', $targetParentFolder)) {
+                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetParentFolder->getIdentifier() . '"', 1377778049);
+               }
+       }
+
        /********************
         * FILE ACTIONS
         ********************/
@@ -707,29 +1027,29 @@ class ResourceStorage {
         *
         * @param string $localFilePath The file on the server's hard disk to add.
         * @param Folder $targetFolder The target path, without the fileName
-        * @param string $fileName The fileName. If not set, the local file name is used.
+        * @param string $targetFileName The fileName. If not set, the local file name is used.
         * @param string $conflictMode possible value are 'cancel', 'replace', 'changeName'
         *
         * @throws \InvalidArgumentException
         * @throws Exception\ExistingTargetFileNameException
         * @return FileInterface
         */
-       public function addFile($localFilePath, Folder $targetFolder, $fileName = '', $conflictMode = 'changeName') {
+       public function addFile($localFilePath, Folder $targetFolder, $targetFileName = '', $conflictMode = 'changeName') {
                $localFilePath = PathUtility::getCanonicalPath($localFilePath);
-               // TODO check permissions (write on target, upload, ...)
                if (!file_exists($localFilePath)) {
                        throw new \InvalidArgumentException('File "' . $localFilePath . '" does not exist.', 1319552745);
                }
+               $this->assureFileAddPermissions($localFilePath, $targetFolder, $targetFileName);
                $targetFolder = $targetFolder ? $targetFolder : $this->getDefaultFolder();
-               $fileName = $fileName ? $fileName : PathUtility::basename($localFilePath);
-               if ($conflictMode === 'cancel' && $this->driver->fileExistsInFolder($fileName, $targetFolder)) {
-                       throw new Exception\ExistingTargetFileNameException('File "' . $fileName . '" already exists in folder ' . $targetFolder->getIdentifier(), 1322121068);
+               $targetFileName = $targetFileName ? $targetFileName : PathUtility::basename($localFilePath);
+               if ($conflictMode === 'cancel' && $this->driver->fileExistsInFolder($targetFileName, $targetFolder)) {
+                       throw new Exception\ExistingTargetFileNameException('File "' . $targetFileName . '" already exists in folder ' . $targetFolder->getIdentifier(), 1322121068);
                } elseif ($conflictMode === 'changeName') {
-                       $fileName = $this->getUniqueName($targetFolder, $fileName);
+                       $targetFileName = $this->getUniqueName($targetFolder, $targetFileName);
                }
                // We do not care whether the file exists if $conflictMode is "replace",
                // so just use the name as is in that case
-               return $this->driver->addFile($localFilePath, $targetFolder, $fileName);
+               return $this->driver->addFile($localFilePath, $targetFolder, $targetFileName);
        }
 
        /**
@@ -901,9 +1221,11 @@ class ResourceStorage {
        // TODO check if we should use a folder object instead of $path
        // TODO add unit test for $loadIndexRecords
        public function getFileList($path, $start = 0, $numberOfItems = 0, $useFilters = TRUE, $loadIndexRecords = TRUE, $recursive = FALSE) {
+               // This also checks for read permissions on folder
+               $folder = $this->getFolder($path);
                $rows = array();
                if ($loadIndexRecords) {
-                       $rows = $this->getFileRepository()->getFileIndexRecordsForFolder($this->getFolder($path));
+                       $rows = $this->getFileRepository()->getFileIndexRecordsForFolder($folder);
                }
                $filters = $useFilters == TRUE ? $this->fileAndFolderNameFilters : array();
                $items = $this->driver->getFileList($path, $start, $numberOfItems, $filters, $rows, $recursive);
@@ -923,7 +1245,7 @@ class ResourceStorage {
         * @return boolean
         */
        public function hasFile($identifier) {
-               // @todo: access check?
+               $this->assureFolderReadPermission();
                return $this->driver->fileExists($identifier);
        }
 
@@ -935,6 +1257,7 @@ class ResourceStorage {
         * @return boolean
         */
        public function hasFileInFolder($fileName, Folder $folder) {
+               $this->assureFolderReadPermission($folder);
                return $this->driver->fileExistsInFolder($fileName, $folder);
        }
 
@@ -947,10 +1270,7 @@ class ResourceStorage {
         * @return string
         */
        public function getFileContents($file) {
-               // Check if $file is readable
-               if (!$this->checkFileActionPermission('read', $file)) {
-                       throw new Exception\InsufficientFileReadPermissionsException('Reading file "' . $file->getIdentifier() . '" is not allowed.', 1330121089);
-               }
+               $this->assureFileReadPermission($file);
                return $this->driver->getFileContents($file);
        }
 
@@ -966,18 +1286,9 @@ class ResourceStorage {
         * @return integer The number of bytes written to the file
         */
        public function setFileContents(AbstractFile $file, $contents) {
-                       // Check if user is allowed to edit
-               if (!$this->checkUserActionPermission('edit', 'File')) {
-                       throw new Exception\InsufficientUserPermissionsException(('Updating file "' . $file->getIdentifier()) . '" not allowed for user.', 1330121117);
-               }
-                       // Check if $file is writable
-               if (!$this->checkFileActionPermission('write', $file)) {
-                       throw new Exception\InsufficientFileWritePermissionsException('Writing to file "' . $file->getIdentifier() . '" is not allowed.', 1330121088);
-               }
-               if ($this->checkFileExtensionPermission($file->getName()) === FALSE) {
-                       throw new Exception\IllegalFileExtensionException('You are not allowed to edit a file with extension "' . $file->getExtension() . '"', 1366711933);
-               }
-                       // Call driver method to update the file and update file properties afterwards
+               // Check if user is allowed to edit
+               $this->assureFileWritePermissions($file);
+               // Call driver method to update the file and update file properties afterwards
                $result = $this->driver->setFileContents($file, $contents);
                $fileInfo = $this->driver->getFileInfo($file);
                $fileInfo['sha1'] = $this->driver->hash($file, 'sha1');
@@ -994,16 +1305,12 @@ class ResourceStorage {
         * @param string $fileName
         * @param Folder $targetFolderObject
         *
+        * @throws Exception\IllegalFileExtensionException
         * @throws Exception\InsufficientFolderWritePermissionsException
         * @return FileInterface The file object
         */
        public function createFile($fileName, Folder $targetFolderObject) {
-               if ($this->checkFileExtensionPermission($fileName) === FALSE) {
-                       throw new Exception\IllegalFileExtensionException('You are not allowed to create a file with this extension on storage "' . $targetFolderObject->getCombinedIdentifier() . '"', 1366711745);
-               }
-               if (!$this->checkFolderActionPermission('add', $targetFolderObject)) {
-                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to create directories on this storage "' . $targetFolderObject->getIdentifier() . '"', 1323059807);
-               }
+               $this->assureFileAddPermissions('', $targetFolderObject, $fileName);
                return $this->driver->createFile($fileName, $targetFolderObject);
        }
 
@@ -1016,9 +1323,7 @@ class ResourceStorage {
         * @return boolean TRUE if deletion succeeded
         */
        public function deleteFile($fileObject) {
-               if (!$this->checkFileActionPermission('remove', $fileObject)) {
-                       throw new Exception\InsufficientFileAccessPermissionsException('You are not allowed to delete the file "' . $fileObject->getIdentifier() . '\'', 1319550425);
-               }
+               $this->assureFileDeletePermissions($fileObject);
 
                $this->emitPreFileDeleteSignal($fileObject);
 
@@ -1049,11 +1354,11 @@ class ResourceStorage {
         * @return FileInterface
         */
        public function copyFile(FileInterface $file, Folder $targetFolder, $targetFileName = NULL, $conflictMode = 'renameNewFile') {
-               $this->emitPreFileCopySignal($file, $targetFolder);
-               $this->checkFileCopyPermissions($file, $targetFolder, $targetFileName);
                if ($targetFileName === NULL) {
                        $targetFileName = $file->getName();
                }
+               $this->assureFileCopyPermissions($file, $targetFolder, $targetFileName);
+               $this->emitPreFileCopySignal($file, $targetFolder);
                // File exists and we should abort, let's abort
                if ($conflictMode === 'cancel' && $targetFolder->hasFile($targetFileName)) {
                        throw new Exception\ExistingTargetFileNameException('The target file already exists.', 1320291063);
@@ -1076,84 +1381,6 @@ class ResourceStorage {
        }
 
        /**
-        * Check if a file has the permission to be uploaded to a Folder/Storage,
-        * if not throw an exception
-        *
-        * @param string $localFilePath the temporary file name from $_FILES['file1']['tmp_name']
-        * @param Folder $targetFolder
-        * @param string $targetFileName the destination file name $_FILES['file1']['name']
-        * @param integer $uploadedFileSize
-        *
-        * @throws Exception\InsufficientFolderWritePermissionsException
-        * @throws Exception\UploadException
-        * @throws Exception\IllegalFileExtensionException
-        * @throws Exception\UploadSizeException
-        * @throws Exception\InsufficientUserPermissionsException
-        * @return void
-        */
-       protected function checkFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileSize) {
-               // Makes sure the user is allowed to upload
-               if (!$this->checkUserActionPermission('upload', 'File')) {
-                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to upload files to this storage "' . $this->getUid() . '"', 1322112430);
-               }
-               // Makes sure this is an uploaded file
-               if (!is_uploaded_file($localFilePath)) {
-                       throw new Exception\UploadException('The upload has failed, no uploaded file found!', 1322110455);
-               }
-               // Max upload size (kb) for files.
-               $maxUploadFileSize = GeneralUtility::getMaxUploadFileSize() * 1024;
-               if ($uploadedFileSize >= $maxUploadFileSize) {
-                       throw new Exception\UploadSizeException('The uploaded file exceeds the size-limit of ' . $maxUploadFileSize . ' bytes', 1322110041);
-               }
-               // Check if targetFolder is writable
-               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
-                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1322120356);
-               }
-               // Check for a valid file extension
-               if (!$this->checkFileExtensionPermission($targetFileName)) {
-                       throw new Exception\IllegalFileExtensionException('Extension of file name is not allowed in "' . $targetFileName . '"!', 1322120271);
-               }
-       }
-
-       /**
-        * Check if a file has the permission to be copied on a File/Folder/Storage,
-        * if not throw an exception
-        *
-        * @param FileInterface $file
-        * @param Folder $targetFolder
-        * @param string $targetFileName
-        *
-        * @throws Exception
-        * @throws Exception\InsufficientFolderWritePermissionsException
-        * @throws Exception\IllegalFileExtensionException
-        * @throws Exception\InsufficientFileReadPermissionsException
-        * @throws Exception\InsufficientUserPermissionsException
-        * @return void
-        */
-       protected function checkFileCopyPermissions(FileInterface $file, Folder $targetFolder, $targetFileName) {
-               // Check if targetFolder is within this storage, this should never happen
-               if ($this->getUid() != $targetFolder->getStorage()->getUid()) {
-                       throw new Exception('The operation of the folder cannot be called by this storage "' . $this->getUid() . '"', 1319550405);
-               }
-               // Check if user is allowed to copy
-               if (!$this->checkUserActionPermission('copy', 'File')) {
-                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to copy files to this storage "' . $this->getUid() . '"', 1319550415);
-               }
-               // Check if $file is readable
-               if (!$this->checkFileActionPermission('read', $file)) {
-                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . '\'', 1319550425);
-               }
-               // Check if targetFolder is writable
-               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
-                       throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319550435);
-               }
-               // Check for a valid file extension
-               if (!$this->checkFileExtensionPermission($targetFileName)) {
-                       throw new Exception\IllegalFileExtensionException('You are not allowed to copy a file of that type.', 1319553317);
-               }
-       }
-
-       /**
         * Moves a $file into a $targetFolder
         * the target folder has to be part of this storage
         *
@@ -1168,10 +1395,10 @@ class ResourceStorage {
         * @return FileInterface
         */
        public function moveFile($file, $targetFolder, $targetFileName = NULL, $conflictMode = 'renameNewFile') {
-               $this->checkFileMovePermissions($file, $targetFolder);
                if ($targetFileName === NULL) {
                        $targetFileName = $file->getName();
                }
+               $this->assureFileMovePermissions($file, $targetFolder, $targetFileName);
                if ($targetFolder->hasFile($targetFileName)) {
                        // File exists and we should abort, let's abort
                        if ($conflictMode === 'renameNewFile') {
@@ -1233,41 +1460,6 @@ class ResourceStorage {
        }
 
        /**
-        * Checks for permissions to move a file.
-        *
-        * @throws \RuntimeException
-        * @throws Exception\InsufficientFileReadPermissionsException
-        * @throws Exception\InsufficientFileWritePermissionsException
-        * @throws Exception\InsufficientFolderAccessPermissionsException
-        * @throws Exception\InsufficientUserPermissionsException
-        * @param FileInterface $file
-        * @param Folder $targetFolder
-        * @return void
-        */
-       protected function checkFileMovePermissions(FileInterface $file, Folder $targetFolder) {
-               // Check if targetFolder is within this storage
-               if ($this->getUid() != $targetFolder->getStorage()->getUid()) {
-                       throw new \RuntimeException();
-               }
-               // Check if user is allowed to move
-               if (!$this->checkUserActionPermission('move', 'File')) {
-                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to move files to storage "' . $this->getUid() . '"', 1319219349);
-               }
-               // Check if $file is readable
-               if (!$this->checkFileActionPermission('read', $file)) {
-                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . '\'', 1319219349);
-               }
-               // Check if $file is writable
-               if (!$this->checkFileActionPermission('write', $file)) {
-                       throw new Exception\InsufficientFileWritePermissionsException('You are not allowed to move the file "' . $file->getIdentifier() . '\'', 1319219349);
-               }
-               // Check if targetFolder is writable
-               if (!$this->checkFolderActionPermission('write', $targetFolder)) {
-                       throw new Exception\InsufficientFolderAccessPermissionsException('You are not allowed to write to the target folder "' . $targetFolder->getIdentifier() . '"', 1319219349);
-               }
-       }
-
-       /**
         * Previously in \TYPO3\CMS\Core\Utility\File\ExtendedFileUtility::func_rename()
         *
         * @param FileInterface $file
@@ -1281,26 +1473,10 @@ class ResourceStorage {
        // TODO add $conflictMode setting
        public function renameFile($file, $targetFileName) {
                // The name should be different from the current.
-               if ($file->getIdentifier() == $targetFileName) {
+               if ($file->getName() === $targetFileName) {
                        return $file;
                }
-               // Check if file extension is allowed
-               if ($this->checkFileExtensionPermission($targetFileName) === FALSE) {
-                       throw new Exception\IllegalFileExtensionException('You are not allowed to rename a file with to this extension', 1371466663);
-               }
-               // Check if user is allowed to rename
-               if (!$this->checkUserActionPermission('rename', 'File')) {
-                       throw new Exception\InsufficientUserPermissionsException('You are not allowed to rename files."', 1319219349);
-               }
-               // Check if $file is readable
-               if (!$this->checkFileActionPermission('read', $file)) {
-                       throw new Exception\InsufficientFileReadPermissionsException('You are not allowed to read the file "' . $file->getIdentifier() . '\'', 1319219349);
-               }
-               // Check if $file is writable
-               if (!$this->checkFileActionPermission('write', $file)) {
-                       throw new Exception\InsufficientFileWritePermissionsException('You are not allowed to rename the file "' . $file->getIdentifier() . '\'', 1319219349);
-               }
-
+               $this->assureFileRenamePermissions($file, $targetFileName);
                $this->emitPreFileRenameSignal($file, $targetFileName);
 
                // Call driver method to rename the file that also updates the file
@@ -1328,6 +1504,10 @@ class ResourceStorage {
         * @return FileInterface
         */
        public function replaceFile(FileInterface $file, $localFilePath) {
+               $this->assureFileWritePermissions($file);
+               if (!$this->checkFileExtensionPermission($localFilePath)) {
+                       throw new Exception\IllegalFileExtensionException('Sorce file extension not allowed', 1378132239);
+               }
                if (!file_exists($localFilePath)) {
                        throw new \InvalidArgumentException('File "' . $localFilePath . '" does not exist.', 1325842622);
                }
@@ -1356,7 +1536,7 @@ class ResourceStorage {
                        $targetFileName = $uploadedFileData['name'];
                }
                // Handling $conflictMode is delegated to addFile()
-               $this->checkFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileData['size']);
+               $this->assureFileUploadPermissions($localFilePath, $targetFolder, $targetFileName, $uploadedFileData['size']);
                $resultObject = $this->addFile($localFilePath, $targetFolder, $targetFileName, $conflictMode);
                return $resultObject;
        }
@@ -1400,11 +1580,9 @@ class ResourceStorage {
         */
        // TODO add tests
        public function moveFolder(Folder $folderToMove, Folder $targetParentFolder, $newFolderName = NULL, $conflictMode = 'renameNewFolder') {
+               $this->assureFolderMovePermissions($folderToMove, $targetParentFolder);
                $sourceStorage = $folderToMove->getStorage();
                $returnObject = NULL;
-               if (!$targetParentFolder->getStorage() == $this) {
-                       throw new \InvalidArgumentException('Cannot move a folder into a folder that does not belong to this storage.', 1325777289);
-               }
                $newFolderName = $newFolderName ? $newFolderName : $folderToMove->getName();
                // TODO check if folder already exists in $targetParentFolder, handle this conflict then
                $this->emitPreFolderMoveSignal($folderToMove, $targetParentFolder, $newFolderName);
@@ -1442,15 +1620,15 @@ class ResourceStorage {
        /**
         * Copy folder
         *
-        * @param Folder $folderToCopy The folder to copy
-        * @param Folder $targetParentFolder The target folder
+        * @param FolderInterface $folderToCopy The folder to copy
+        * @param FolderInterface $targetParentFolder The target folder
         * @param string $newFolderName
         * @param string $conflictMode  "overrideExistingFolder", "renameNewFolder", "cancel
         * @return Folder The new (copied) folder object
         */
-       public function copyFolder(Folder $folderToCopy, Folder $targetParentFolder, $newFolderName = NULL, $conflictMode = 'renameNewFolder') {
+       public function copyFolder(FolderInterface $folderToCopy, FolderInterface $targetParentFolder, $newFolderName = NULL, $conflictMode = 'renameNewFolder') {
                // TODO implement the $conflictMode handling
-               // TODO permission checks
+               $this->assureFolderCopyPermissions($folderToCopy, $targetParentFolder);
                $returnObject = NULL;
                $newFolderName = $newFolderName ? $newFolderName : $folderToCopy->getName();
                $this->emitPreFolderCopySignal($folderToCopy, $targetParentFolder, $newFolderName);
@@ -1496,6 +1674,8 @@ class ResourceStorage {
        public function renameFolder($folderObject, $newName) {
                // TODO unit tests
 
+               // Renaming the folder should check if the parent folder is writable
+               // We cannot do this however because we cannot extract the parent folder from a folder currently
                if (!$this->checkFolderActionPermission('rename', $folderObject)) {
                        throw new \TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException('You are not allowed to rename the folder "' . $folderObject->getIdentifier() . '\'', 1357811441);
                }
@@ -1525,17 +1705,15 @@ class ResourceStorage {
        /**
         * Previously in \TYPO3\CMS\Core\Utility\File\ExtendedFileUtility::folder_delete()
         *
-        * @param Folder    $folderObject
-        * @param bool $deleteRecursively
+        * @param Folder $folderObject
+        * @param boolean $deleteRecursively
         * @throws \RuntimeException
-        * @throws Exception\InsufficientFileAccessPermissionsException
         * @return boolean
         */
        public function deleteFolder($folderObject, $deleteRecursively = FALSE) {
-               if (!$this->checkFolderActionPermission('remove', $folderObject)) {
-                       throw new Exception\InsufficientFileAccessPermissionsException('You are not allowed to access the folder "' . $folderObject->getIdentifier() . '\'', 1323423953);
-               }
-               if (!$this->driver->isFolderEmpty($folderObject) && !$deleteRecursively) {
+               $isEmpty = $this->driver->isFolderEmpty($folderObject);
+               $this->assureFolderDeletePermission($folderObject, ($deleteRecursively && !$isEmpty));
+               if (!$isEmpty && !$deleteRecursively) {
                        throw new \RuntimeException('Could not delete folder "' . $folderObject->getIdentifier() . '" because it is not empty.', 1325952534);
                }
 
@@ -1558,6 +1736,7 @@ class ResourceStorage {
         * @return array Information about the folders found.
         */
        public function getFolderList($path, $start = 0, $numberOfItems = 0, $useFilters = TRUE) {
+               // Permissions are checked in $this->fetchFolderListFromDriver()
                $filters = $useFilters === TRUE ? $this->fileAndFolderNameFilters : array();
                return $this->fetchFolderListFromDriver($path, $start, $numberOfItems, $filters);
        }
@@ -1571,6 +1750,10 @@ class ResourceStorage {
         * @return array
         */
        public function fetchFolderListFromDriver($path, $start = 0, $numberOfItems = 0, array $folderFilterCallbacks = array(), $recursive = FALSE) {
+               // This also checks for access to that path and throws exceptions accordingly
+               if ($this->getFolder($path) === NULL) {
+                       return array();
+               }
                $items = $this->driver->getFolderList($path, $start, $numberOfItems, $folderFilterCallbacks, $recursive);
                if (!empty($items)) {
                        // Exclude the _processed_ folder, so it won't get indexed etc
@@ -1598,6 +1781,7 @@ class ResourceStorage {
         * @return boolean
         */
        public function hasFolder($identifier) {
+               $this->assureFolderReadPermission();
                return $this->driver->folderExists($identifier);
        }
 
@@ -1609,6 +1793,7 @@ class ResourceStorage {
         * @return boolean
         */
        public function hasFolderInFolder($folderName, Folder $folder) {
+               $this->assureFolderReadPermission($folder);
                return $this->driver->folderExistsInFolder($folderName, $folder);
        }
 
@@ -1634,6 +1819,7 @@ class ResourceStorage {
                if (!$this->checkFolderActionPermission('add', $parentFolder)) {
                        throw new Exception\InsufficientFolderWritePermissionsException('You are not allowed to create directories in the folder "' . $parentFolder->getIdentifier() . '"', 1323059807);
                }
+               // TODO this only works with hirachical file systems
                $folderParts = GeneralUtility::trimExplode('/', $folderName, TRUE);
                foreach ($folderParts as $folder) {
                        // TODO check if folder creation succeeded
@@ -1666,12 +1852,10 @@ class ResourceStorage {
                if (!$this->driver->folderExists($identifier)) {
                        throw new Exception\FolderDoesNotExistException('Folder ' . $identifier . ' does not exist.', 1320575630);
                }
-               $folderObject = $this->driver->getFolder($identifier);
-               if ($this->fileMounts && !$this->isWithinFileMountBoundaries($folderObject)) {
-                       throw new Exception\NotInMountPointException('Folder "' . $identifier . '" is not within your mount points.', 1330120649);
-               } else {
-                       return $folderObject;
-               }
+               $folder = $this->driver->getFolder($identifier);
+               $this->assureFolderReadPermission($folder);
+
+               return $folder;
        }
 
        /**
index e44733f..b2cd31b 100644 (file)
@@ -26,6 +26,8 @@ namespace TYPO3\CMS\Core\Resource\Service;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Service class for implementing the user filemounts,
@@ -56,16 +58,29 @@ class UserFileMountService {
                }
                if ($storageUid > 0) {
                        /** @var $storageRepository \TYPO3\CMS\Core\Resource\StorageRepository */
-                       $storageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
+                       $storageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
                        /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
                        $storage = $storageRepository->findByUid($storageUid);
-                       $rootLevelFolder = $storage->getRootLevelFolder();
-                       $folderItems = $this->getSubfoldersForOptionList($rootLevelFolder);
-                       foreach ($folderItems as $item) {
-                               $PA['items'][] = array(
-                                       htmlspecialchars($item->getIdentifier()),
-                                       htmlspecialchars($item->getIdentifier())
-                               );
+                       if ($storage->isBrowsable()) {
+                               $rootLevelFolder = $storage->getRootLevelFolder();
+                               $folderItems = $this->getSubfoldersForOptionList($rootLevelFolder);
+                               foreach ($folderItems as $item) {
+                                       $PA['items'][] = array(
+                                               htmlspecialchars($item->getIdentifier()),
+                                               htmlspecialchars($item->getIdentifier())
+                                       );
+                               }
+                       } else {
+                               /** @var \TYPO3\CMS\Core\Messaging\FlashMessageService $flashMessageService */
+                               $flashMessageService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessageService');
+                               $queue = $flashMessageService->getMessageQueueByIdentifier();
+                               $queue->enqueue(new FlashMessage('Storage "' . $storage->getName() . '" is not browsable. No folder is currently selectable.', '', FlashMessage::WARNING));
+                               if (!count($PA['items'])) {
+                                       $PA['items'][] = array(
+                                               $PA['row'][$PA['field']],
+                                               $PA['row'][$PA['field']]
+                                       );
+                               }
                        }
                } else {
                        $PA['items'][] = array('', 'Please choose a FAL mount from above first.');
index 270f2dc..44fc3fd 100644 (file)
@@ -715,7 +715,7 @@ class ExtendedFileUtility extends \TYPO3\CMS\Core\Utility\File\BasicFileUtility
                        } catch (\TYPO3\CMS\Core\Resource\Exception\InsufficientUserPermissionsException $e) {
                                $this->writelog(5, 1, 102, 'You are not allowed to rename files!', '');
                        } catch (\TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException $e) {
-                               $this->writelog(5, 1, 101, 'Extension of file name "%s" was not allowed!', array($targetFile));
+                               $this->writelog(5, 1, 101, 'Extension of file name "%s" or "%s" was not allowed!', array($sourceFileObject->getName(), $targetFile));
                        } catch (\TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException $e) {
                                $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
                        } catch (\TYPO3\CMS\Core\Resource\Exception\NotInMountPointException $e) {
index f3ccf79..601c93c 100644 (file)
@@ -109,7 +109,7 @@ return array(
                 */
                'curlTimeout' => 0,                                             // Integer: Timeout value for cURL requests in seconds. 0 means to wait indefinitely. Deprecated since 4.6 - will be removed in 6.2. See below for http options.
                'form_enctype' => 'multipart/form-data',// String: This is the default form encoding type for most forms in TYPO3. It allows for file uploads to be in the form. However if file-upload is disabled for your PHP version even ordinary data sent with this encryption will not get to the server. So if you have file_upload disabled, you will have to change this to eg. 'application/x-www-form-urlencoded'
-               'textfile_ext' => 'txt,html,htm,css,tmpl,js,sql,xml,csv,' . PHP_EXTENSIONS_DEFAULT,             // Text file extensions. Those that can be edited. Executable PHP files may not be editable in webspace if disallowed!
+               'textfile_ext' => 'txt,html,htm,css,tmpl,js,sql,xml,csv',               // Text file extensions. Those that can be edited. Executable PHP files may not be editable in webspace if disallowed!
                'contentTable' => '',                                   // This is the page-content table (Normally 'tt_content')
                'binPath' => '',                                                // String: List of absolute paths where external programs should be searched for. Eg. <code>/usr/local/webbin/,/home/xyz/bin/</code>. (ImageMagick path have to be configured separately)
                'binSetup' => '',                                               // String (textarea): List of programs (separated by newline or comma). By default programs will be searched in default paths and the special paths defined by 'binPath'. When PHP has openbasedir enabled the programs can not be found and have to be configured here. Example: <code>perl=/usr/bin/perl,unzip=/usr/local/bin/unzip</code>
index 9b136d4..128a82e 100644 (file)
@@ -221,44 +221,40 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 0,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0,
                                )
                        ),
                        'Uploading allowed' => array(
                                array(
                                        'addFile' => 1,
                                        'readFile' => 1,
-                                       'editFile' => 1,
                                        'writeFile' => 1,
-                                       'uploadFile' => 1,
                                        'copyFile' => 1,
                                        'moveFile' => 1,
                                        'renameFile' => 1,
                                        'unzipFile' => 0,
-                                       'removeFile' => 1,
+                                       'deleteFile' => 1,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'One value is enough' => array(
@@ -304,22 +300,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $defaultPermissions = array(
                        'addFile' => 1,
                        'readFile' => 1,
-                       'editFile' => 1,
                        'writeFile' => 1,
-                       'uploadFile' => 1,
                        'copyFile' => 1,
                        'moveFile' => 1,
                        'renameFile' => 1,
                        'unzipFile' => 1,
-                       'removeFile' => 1,
+                       'deleteFile' => 1,
                        'addFolder' => 1,
                        'readFolder' => 1,
                        'copyFolder' => 1,
                        'moveFolder' => 1,
                        'renameFolder' => 1,
                        'writeFolder' => 1,
-                       'removeFolder' => 1,
-                       'removeSubfolders' => 1
+                       'deleteFolder' => 1,
+                       'recursivedeleteFolder' => 1
                );
 
                return array(
@@ -328,27 +322,25 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                1,
                                array(
                                        'addFile' => 0,
-                                       'removeSubfolders' =>0
+                                       'recursivedeleteFolder' =>0
                                ),
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 1,
                                        'writeFile' => 1,
-                                       'uploadFile' => 1,
                                        'copyFile' => 1,
                                        'moveFile' => 1,
                                        'renameFile' => 1,
                                        'unzipFile' => 1,
-                                       'removeFile' => 1,
+                                       'deleteFile' => 1,
                                        'addFolder' => 1,
                                        'readFolder' => 1,
                                        'copyFolder' => 1,
                                        'moveFolder' => 1,
                                        'renameFolder' => 1,
                                        'writeFolder' => 1,
-                                       'removeFolder' => 1,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 1,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Overwrites given storage 0 permissions with default permissions' => array(
@@ -356,27 +348,25 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                0,
                                array(
                                        'addFile' => 0,
-                                       'removeSubfolders' =>0
+                                       'recursivedeleteFolder' =>0
                                ),
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 1,
                                        'writeFile' => 1,
-                                       'uploadFile' => 1,
                                        'copyFile' => 1,
                                        'moveFile' => 1,
                                        'renameFile' => 1,
                                        'unzipFile' => 1,
-                                       'removeFile' => 1,
+                                       'deleteFile' => 1,
                                        'addFolder' => 1,
                                        'readFolder' => 1,
                                        'copyFolder' => 1,
                                        'moveFolder' => 1,
                                        'renameFolder' => 1,
                                        'writeFolder' => 1,
-                                       'removeFolder' => 1,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 1,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Returns default permissions if no storage permissions are found' => array(
@@ -386,22 +376,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 1,
                                        'readFile' => 1,
-                                       'editFile' => 1,
                                        'writeFile' => 1,
-                                       'uploadFile' => 1,
                                        'copyFile' => 1,
                                        'moveFile' => 1,
                                        'renameFile' => 1,
                                        'unzipFile' => 1,
-                                       'removeFile' => 1,
+                                       'deleteFile' => 1,
                                        'addFolder' => 1,
                                        'readFolder' => 1,
                                        'copyFolder' => 1,
                                        'moveFolder' => 1,
                                        'renameFolder' => 1,
                                        'writeFolder' => 1,
-                                       'removeFolder' => 1,
-                                       'removeSubfolders' => 1
+                                       'deleteFolder' => 1,
+                                       'recursivedeleteFolder' => 1
                                )
                        ),
                );
@@ -488,22 +476,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 0,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Uploading allowed' => array(
@@ -511,22 +497,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 1,
                                        'readFile' => 1,
-                                       'editFile' => 1,
                                        'writeFile' => 1,
-                                       'uploadFile' => 1,
                                        'copyFile' => 1,
                                        'moveFile' => 1,
                                        'renameFile' => 1,
                                        'unzipFile' => 0,
-                                       'removeFile' => 1,
+                                       'deleteFile' => 1,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Unzip allowed' => array(
@@ -534,22 +518,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 1,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Write folder allowed' => array(
@@ -557,22 +539,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 0,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 1,
                                        'readFolder' => 1,
                                        'copyFolder' => 0,
                                        'moveFolder' => 1,
                                        'renameFolder' => 1,
                                        'writeFolder' => 1,
-                                       'removeFolder' => 1,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 1,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Copy folder allowed' => array(
@@ -580,22 +560,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 0,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 1,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 0
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 0
                                )
                        ),
                        'Copy folder and remove subfolders allowed' => array(
@@ -603,22 +581,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                array(
                                        'addFile' => 0,
                                        'readFile' => 1,
-                                       'editFile' => 0,
                                        'writeFile' => 0,
-                                       'uploadFile' => 0,
                                        'copyFile' => 0,
                                        'moveFile' => 0,
                                        'renameFile' => 0,
                                        'unzipFile' => 0,
-                                       'removeFile' => 0,
+                                       'deleteFile' => 0,
                                        'addFolder' => 0,
                                        'readFolder' => 1,
                                        'copyFolder' => 1,
                                        'moveFolder' => 0,
                                        'renameFolder' => 0,
                                        'writeFolder' => 0,
-                                       'removeFolder' => 0,
-                                       'removeSubfolders' => 1
+                                       'deleteFolder' => 0,
+                                       'recursivedeleteFolder' => 1
                                )
                        ),
                );
@@ -659,22 +635,20 @@ class BackendUserAuthenticationTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $expectedPermissions = array(
                        'addFile' => TRUE,
                        'readFile' => TRUE,
-                       'editFile' => TRUE,
                        'writeFile' => TRUE,
-                       'uploadFile' => TRUE,
                        'copyFile' => TRUE,
                        'moveFile' => TRUE,
                        'renameFile' => TRUE,
                        'unzipFile' => TRUE,
-                       'removeFile' => TRUE,
+                       'deleteFile' => TRUE,
                        'addFolder' => TRUE,
                        'readFolder' => TRUE,
                        'copyFolder' => TRUE,
                        'moveFolder' => TRUE,
                        'renameFolder' => TRUE,
                        'writeFolder' => TRUE,
-                       'removeFolder' => TRUE,
-                       'removeSubfolders' => TRUE
+                       'deleteFolder' => TRUE,
+                       'recursivedeleteFolder' => TRUE
                );
 
                $this->assertEquals($expectedPermissions, $this->fixture->getFilePermissions());
index fd4a80d..83a5592 100644 (file)
@@ -67,7 +67,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         * @return void
         */
        protected function prepareFixture($configuration, $mockPermissionChecks = FALSE, $driverObject = NULL, array $storageRecord = array()) {
-               $permissionMethods = array('checkFolderActionPermission', 'checkFileActionPermission', 'checkUserActionPermission');
+               $permissionMethods = array('assureFileAddPermissions', 'checkFolderActionPermission', 'checkFileActionPermission', 'checkUserActionPermission', 'checkFileExtensionPermission', 'isWithinFileMountBoundaries');
                $mockedMethods = NULL;
                $configuration = $this->convertConfigurationArrayToFlexformXml($configuration);
                $storageRecord = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($storageRecord, array(
@@ -240,7 +240,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                ));
                $this->initializeVfs();
                $localFilePath = $this->getUrlInMount('file.ext');
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                /** @var $driver \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
                $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array('addFile'), array(array('basePath' => $this->getUrlInMount('targetFolder/'))));
                $driver->expects($this->once())->method('addFile')->with($this->equalTo($localFilePath), $this->anything(), $this->equalTo('file.ext'));
@@ -261,7 +261,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                        'file.ext' => 'ajslkd'
                ));
                $this->initializeVfs();
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                /** @var $driver \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
                $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array('addFile', 'fileExistsInFolder'), array(array('basePath' => $this->getUrlInMount('targetFolder/'))));
                $driver->expects($this->once())->method('addFile')->with($this->anything(), $this->anything(), $this->equalTo('file_02.ext'));
@@ -296,16 +296,17 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                        'read action on readable/writable folder' => array(
                                'read',
                                array('r' => TRUE, 'w' => TRUE),
+                               TRUE
                        ),
                        'read action on unreadable folder' => array(
                                'read',
                                array('r' => FALSE, 'w' => TRUE),
-                               'TYPO3\\CMS\\Core\\Resource\\Exception\\InsufficientFolderReadPermissionsException'
+                               FALSE
                        ),
                        'write action on read-only folder' => array(
                                'write',
                                array('r' => TRUE, 'w' => FALSE),
-                               'TYPO3\\CMS\\Core\\Resource\\Exception\\InsufficientFolderWritePermissionsException'
+                               FALSE
                        )
                );
        }
@@ -315,9 +316,9 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         * @dataProvider checkFolderPermissionsFilesystemPermissionsDataProvider
         * @param string $action 'read' or 'write'
         * @param array $permissionsFromDriver The permissions as returned from the driver
-        * @param boolean $expectedException
+        * @param boolean $expectedResult
         */
-       public function checkFolderPermissionsRespectsFilesystemPermissions($action, $permissionsFromDriver, $expectedException = '') {
+       public function checkFolderPermissionsRespectsFilesystemPermissions($action, $permissionsFromDriver, $expectedResult) {
                $mockedDriver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver');
                $mockedDriver->expects($this->any())->method('getFolderPermissions')->will($this->returnValue($permissionsFromDriver));
                $mockedFolder = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Folder', array(), array(), '', FALSE);
@@ -328,13 +329,8 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                $fixture->expects($this->any())->method('isBrowsable')->will($this->returnValue(TRUE));
                $fixture->expects($this->any())->method('checkUserActionPermission')->will($this->returnValue(TRUE));
                $fixture->setDriver($mockedDriver);
-               if ($expectedException == '') {
-                       $this->assertTrue($fixture->checkFolderActionPermission($action, $mockedFolder));
-               } else {
-                       $this->markTestSkipped('The exception has been disable in TYPO3\\CMS\\Core\\Resource\\ResourceStorage');
-                       $this->setExpectedException($expectedException);
-                       $fixture->checkFolderActionPermission($action, $mockedFolder);
-               }
+
+               $this->assertSame($expectedResult, $fixture->checkFolderActionPermission($action, $mockedFolder));
        }
 
        /**
@@ -389,6 +385,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         */
        public function userActionIsDisallowedIfPermissionIsSetToFalse() {
                $this->prepareFixture(array());
+               $this->fixture->setEvaluatePermissions(TRUE);
                $this->fixture->setUserPermissions(array('readFolder' => FALSE));
                $this->assertFalse($this->fixture->checkUserActionPermission('read', 'folder'));
        }
@@ -398,6 +395,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         */
        public function userActionIsDisallowedIfPermissionIsNotSet() {
                $this->prepareFixture(array());
+               $this->fixture->setEvaluatePermissions(TRUE);
                $this->fixture->setUserPermissions(array('readFolder' => TRUE));
                $this->assertFalse($this->fixture->checkUserActionPermission('write', 'folder'));
        }
@@ -407,7 +405,6 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         * @group integration
         */
        public function setFileContentsUpdatesObjectProperties() {
-               $fileContents = 'asdf';
                $this->initializeVfs();
                $this->prepareFixture(array(), TRUE);
                $fileProperties = array(
@@ -448,7 +445,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array(), array(array('basePath' => $this->getMountRootUrl())));
                $driver->expects($this->once())->method('addFileRaw')->with($localFilePath, $targetFolder, $this->equalTo('file.ext'))->will($this->returnValue('/targetFolder/file.ext'));
                /** @var $fixture \TYPO3\CMS\Core\Resource\ResourceStorage */
-               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('checkFileMovePermissions', 'updateFile'), array($driver, array('configuration' => $configuration)));
+               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('assureFileMovePermissions', 'updateFile'), array($driver, array('configuration' => $configuration)));
                $fixture->expects($this->once())->method('updateFile')->with($this->equalTo($sourceFile), $this->equalTo('/targetFolder/file.ext'));
                $fixture->moveFile($sourceFile, $targetFolder, 'file.ext');
        }
@@ -474,7 +471,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                $driver = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array(), array(array('basePath' => $this->getMountRootUrl())));
                $driver->expects($this->once())->method('addFile')->with($localFilePath, $targetFolder, $this->equalTo('file.ext'));
                /** @var $fixture \TYPO3\CMS\Core\Resource\ResourceStorage */
-               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('checkFileCopyPermissions'), array($driver, array('configuration' => $storageConfiguration)));
+               $fixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('assureFileCopyPermissions'), array($driver, array('configuration' => $storageConfiguration)));
                $fixture->copyFile($sourceFile, $targetFolder, 'file.ext');
        }
 
@@ -509,7 +506,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                        'File' => '',
                        'fail' => ''
                );
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                $driver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), $this->fixture, array('getFileList'));
                $driver->expects($this->once())->method('getFileList')->will($this->returnValue($fileList));
                $fileList = $this->fixture->getFileList('/');
@@ -527,7 +524,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                        '12345' => 'fdsa',
                        'IMG_1234.jpg' => 'asdf'
                );
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                $driver = $this->createDriverMock(array(), $this->fixture, array('getFileList'));
                $driver->expects($this->once())->method('getFileList')->will($this->returnValue($fileList));
                $fileList = $this->fixture->getFileList('/');
@@ -657,7 +654,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         * @test
         */
        public function getFileListHandsOverRecursiveFALSEifNotExplicitlySet() {
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                $driver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), $this->fixture, array('getFileList'));
                $driver->expects($this->once())
                        ->method('getFileList')
@@ -671,7 +668,7 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
         */
        public function getFileListHandsOverRecursiveTRUEifSet() {
 
-               $this->prepareFixture(array());
+               $this->prepareFixture(array(), TRUE);
                $driver = $this->createDriverMock(array('basePath' => $this->getMountRootUrl()), $this->fixture, array('getFileList'));
                $driver->expects($this->once())
                        ->method('getFileList')
@@ -804,12 +801,9 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
        public function fetchFolderListFromDriverReturnsFolderWithoutProcessedFolder($path, $processingFolder, $folderList, $expectedItems) {
                $driverMock = $this->createDriverMock(array(), NULL, array('getFolderList', 'folderExists'));
                $driverMock->expects($this->once())->method('getFolderList')->will($this->returnValue($folderList));
-               if (!empty($expectedItems)) {
-                       // This function is called only if there were any folders retrieved
-                       $driverMock->expects($this->once())->method('folderExists')->will($this->returnValue(TRUE));
-               }
+               $driverMock->expects($this->any())->method('folderExists')->will($this->returnValue(TRUE));
 
-               $this->prepareFixture(array(), FALSE, $driverMock, array('processingfolder' => $processingFolder));
+               $this->prepareFixture(array(), TRUE, $driverMock, array('processingfolder' => $processingFolder));
 
                $this->assertSame($expectedItems, $this->fixture->fetchFolderListFromDriver($path));
        }
index a4d84e6..d6cff17 100644 (file)
@@ -427,11 +427,11 @@ class FileListController {
                // FileList Module CSH:
                $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'filelist_module', $GLOBALS['BACK_PATH'], '', TRUE);
                // Upload button (only if upload to this directory is allowed)
-               if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission('upload', 'File') && $this->folderObject->checkActionPermission('write')) {
+               if ($this->folderObject && $this->folderObject->getStorage()->checkUserActionPermission('add', 'File') && $this->folderObject->checkActionPermission('write')) {
                        $buttons['upload'] = '<a href="' . $GLOBALS['BACK_PATH'] . 'file_upload.php?target=' . rawurlencode($this->folderObject->getCombinedIdentifier()) . '&amp;returnUrl=' . rawurlencode($this->filelist->listURL()) . '" id="button-upload" title="' . $GLOBALS['LANG']->makeEntities($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.upload', TRUE)) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-upload') . '</a>';
                }
                // New folder button
-               if ($this->folderObject && $this->folderObject->checkActionPermission('add')) {
+               if ($this->folderObject && ($this->folderObject->checkActionPermission('add') || $this->folderObject->getStorage()->checkUserActionPermission('add', 'File'))) {
                        $buttons['new'] = '<a href="' . $GLOBALS['BACK_PATH'] . 'file_newfolder.php?target=' . rawurlencode($this->folderObject->getCombinedIdentifier()) . '&amp;returnUrl=' . rawurlencode($this->filelist->listURL()) . '" title="' . $GLOBALS['LANG']->makeEntities($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.new', TRUE)) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new') . '</a>';
                }
                return $buttons;
index 4e505a8..fa21c24 100644 (file)
@@ -725,7 +725,7 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                $fullIdentifier = $fileOrFolderObject->getCombinedIdentifier();
                // Edit metadata of file
                try {
-                       if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File') && $fileOrFolderObject->isIndexed() && $fileOrFolderObject->checkActionPermission('edit')) {
+                       if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File') && $fileOrFolderObject->isIndexed() && $fileOrFolderObject->checkActionPermission('write')) {
                                $data = array(
                                        'sys_file' => array($fileOrFolderObject->getUid() => 'edit')
                                );
@@ -738,7 +738,7 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                        $cells['editmetadata'] = IconUtility::getSpriteIcon('empty-empty');
                }
                // Edit file content (if editable)
-               if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File') && $fileOrFolderObject->checkActionPermission('edit') && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileOrFolderObject->getExtension())) {
+               if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File') && $fileOrFolderObject->checkActionPermission('write') && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileOrFolderObject->getExtension())) {
                        $editOnClick = 'top.content.list_frame.location.href=top.TS.PATH_typo3+\'file_edit.php?target=' . rawurlencode($fullIdentifier) . '&returnUrl=\'+top.rawurlencode(top.content.list_frame.document.location.pathname+top.content.list_frame.document.location.search);return false;';
                        $cells['edit'] = '<a href="#" onclick="' . $editOnClick . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.edit') . '">' . IconUtility::getSpriteIcon('actions-page-open') . '</a>';
                } else {
@@ -751,17 +751,21 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                } else {
                        $cells['rename'] = IconUtility::getSpriteIcon('empty-empty');
                }
-               if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\Folder')) {
-                       $infoOnClick = 'top.launchView( \'_FOLDER\', \'' . $fullIdentifier . '\');return false;';
-               } elseif (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File')) {
-                       $infoOnClick = 'top.launchView( \'_FILE\', \'' . $fullIdentifier . '\');return false;';
+               if ($fileOrFolderObject->checkActionPermission('read')) {
+                       if (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\Folder')) {
+                               $infoOnClick = 'top.launchView( \'_FOLDER\', \'' . $fullIdentifier . '\');return false;';
+                       } elseif (is_a($fileOrFolderObject, 'TYPO3\\CMS\\Core\\Resource\\File')) {
+                               $infoOnClick = 'top.launchView( \'_FILE\', \'' . $fullIdentifier . '\');return false;';
+                       }
+                       $cells['info'] = '<a href="#" onclick="' . $infoOnClick . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.info') . '">' . IconUtility::getSpriteIcon('status-dialog-information') . '</a>';
+               } else {
+                       $cells['info'] = IconUtility::getSpriteIcon('empty-empty');
                }
-               $cells['info'] = '<a href="#" onclick="' . $infoOnClick . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:cm.info') . '">' . IconUtility::getSpriteIcon('status-dialog-information') . '</a>';
 
                // delete the file
-               if ($fileOrFolderObject->checkActionPermission('remove')) {
+               if ($fileOrFolderObject->checkActionPermission('delete')) {
                        $identifier = $fileOrFolderObject->getIdentifier();
-                       if ($fileOrFolderObject instanceof TYPO3\CMS\Core\Resource\Folder) {
+                       if ($fileOrFolderObject instanceof \TYPO3\CMS\Core\Resource\Folder) {
                                $referenceCountText = BackendUtility::referenceCount('_FILE', $identifier, ' (There are %s reference(s) to this folder!)');
                        } else {
                                $referenceCountText = BackendUtility::referenceCount('sys_file', $identifier, ' (There are %s reference(s) to this file!)');