1

I'm facing a challenge with file access control in TYPO3, and I'm hoping to get some guidance or suggestions from the community.

Problem: I need to implement a file access control system in TYPO3 where users have access to specific folders based on their individual permissions. I'm using the sr_feuser_register extension to create front-end user accounts, and I have modified it to automatically create a folder for each new user (see code below). Now, I want to grant each user read access only to their respective folder.

What I've tried so far: I've explored the built-in user group functionality in TYPO3, but it only allows me to assign access permissions at the group level, rather than at the individual folder level. I've researched available TYPO3 extensions such as secure_downloads, fal_securedownload etc. but none of them seem to provide the exact functionality I need.

Desired Solution: I'm looking for suggestions, guidance, or alternative approaches to achieving fine-grained file access control in TYPO3. Specifically, I want to grant each user read access to their own folder while restricting access to other users' folders. The goal is to upload files to the fileadmin location which the frontend users then can access through their login credentials. I'm currently using TYPO3 version v11.5.22 without composer mode and the sr_feuser_register extension to manage user registration. Ideally, I would like to integrate a solution that works seamlessly with these components.

I'm open to any custom solutions or utilizing third-party extensions if they provide the required functionality.

Any help or insights on this matter would be greatly appreciated. Thank you in advance!

Here is the code that i added to the CreateActionController.php of the sr_feuser_register extension to create the custom folders in fileadmin (i can provide the full code if needed):

<?php
namespace SJBR\SrFeuserRegister\Controller;

//....classes

/**
 * Create action controller
 */
class CreateActionController extends AbstractActionController
{
    /**
     * Processes the create request
     *
     * @param array $dataArray: array of form input fields
     * @param string $cmd: the command
     * @param string $cmdKey: the command key
     * @return string the template with substituted markers
     */
    public function doProcessing(array $finalDataArray, $cmd, $cmdKey) {
        

        //......


        // Set the time zone
        date_default_timezone_set('Europe/Berlin'); // Replace 'Europe/Berlin' with your desired time zone

        // Get the current date
        $currentDate = date('ymd');

        // Prepare the folder name
        $firstName = $finalDataArray['first_name'];
        $lastName = $finalDataArray['last_name'];

        // Convert special characters to ASCII equivalents
        $firstName = iconv('UTF-8', 'ASCII//TRANSLIT', $firstName);
        $lastName = iconv('UTF-8', 'ASCII//TRANSLIT', $lastName);

        // Replace umlaut characters with their ASCII equivalents
        $firstName = str_replace(['ä', 'ö', 'ü', 'ß'], ['ae', 'oe', 'ue', 'ss'], $firstName);
        $lastName = str_replace(['ä', 'ö', 'ü', 'ß'], ['ae', 'oe', 'ue', 'ss'], $lastName);

        // Remove non-alphanumeric characters
        $firstName = preg_replace('/[^a-zA-Z0-9]/', '', $firstName);
        $lastName = preg_replace('/[^a-zA-Z0-9]/', '', $lastName);

        // Check if the first name and last name are not empty
        if (!empty($firstName) && !empty($lastName)) {
            // Construct the folder name
            $folderName = $currentDate . '_' . strtolower($lastName) . '_' . strtolower($firstName);

            // Create the folder path
            $folderPath = 'fileadmin/data/' . $folderName;

            // Attempt to create the folder
            if (mkdir($folderPath, 0755)) {
                // Folder created successfully
                // Set folder permissions
                chmod($folderPath, 0755); // Adjust the permissions as needed

                // Get the FE user UID
                $feUserUid = $GLOBALS['TSFE']->fe_user->user['uid'];

                // Set folder access rights for the FE user
                $feUserUid = $GLOBALS['TSFE']->fe_user->user['uid'];

                // Get the FE user group ID
                $groupId = $GLOBALS['TSFE']->fe_user->user['usergroup'];

                // Get the TYPO3 database connection
                $databaseConnection = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)->getConnectionForTable('sys_file_metadata');

                // Clear any existing folder permissions for the patient's folder
                $databaseConnection->exec_DELETEquery(
                    'sys_file_metadata',
                    $databaseConnection->quoteIdentifier('table_local') . ' = 1 AND ' .
                    $databaseConnection->quoteIdentifier('identifier') . ' = ' . $databaseConnection->quote($folderName)
                );

                // Grant folder permissions to the FE user group for the patient's folder
                $databaseConnection->insert(
                    'sys_file_metadata',
                    [
                        'uid' => $groupId,
                        'table_local' => 1,
                        'identifier' => $folderName,
                        'permissions' => 31, // Set desired folder permissions (e.g., 31 for full access)
                        'modified' => time()
                    ]
                );
            }
        }



        //......
    }
}
weiss
  • 31
  • 6
  • TYPO3 never had user specific access rights, only groups. Therefore one solution is to have one group per user. Otherwise you need to program the access control yourself, for every kind of data. – Bernd Wilke πφ May 15 '23 at 05:47
  • Unfortunately that's not an option because during the registration the extension is assigning a specific user group to the frontend users (double opt-in). Otherwise i would have to completely rebuild the registration process. Is there an alternative solution? How would i program the access control ? – weiss May 15 '23 at 18:03
  • I would consider it easier to add one additional group to each user, even if this group needs to be created beforehand. otherwise you need to add an additional field to each record you want to control. and each query to those records needs additional wheres to this field. maybe the sys ext `fe_login` might give a little hint about the complexity. – Bernd Wilke πφ May 16 '23 at 10:03
  • Hello Bernd, thanks for you help. I have problems assigning the new usergroup to the user. maybe it is due to the fact, that sr_feuser_register automatically assigns a group after confirmation of the user. I also checked the SetfixedActionController.php but i have no idea how to override the usergroup assignment. Here is my current code of the CreateActionController.php: https://codefile.io/f/mbwBGLvbdL – weiss May 19 '23 at 15:49
  • sorry. I'm not familiar with `ext:sr_feuser_register` (how to avoid or enhance assignments in that extension). You may contact the author or the community around that extension: you may ask in typo3.slack.com or talk.typo3.org and mention this question. – Bernd Wilke πφ May 22 '23 at 05:30

2 Answers2

1

IMMO there is no ready-to-use solution for this case. So you would have to create your own extension for that.

For that:

  1. You will need a non public file storage, as described here under point 2 (Don't forget the .htaccess file or use folder outside docroot): https://docs.typo3.org/p/beechit/fal-securedownload/4.0/en-us/Installation/Index.html
  2. You will need a database table to save the folder permissions. You could check out EXT:fal_securedownload on how to assign groups to folders. And then rebuild it, assigning fe_users to folders.
  3. You need a controller and the plugins to handle the files of logged in user. (i.e. A list view)
  4. Adjust your CreateActionController to create the folder permissions, when creating the user folder.

OR

You could use the EXT:fal_securedownload completely and realize the user permissions with usergroups. You could create the groups in your CreateActionController and assign them to the fe_user. The Extensions comes with an TreeView for files and folders.

Mogens
  • 548
  • 1
  • 3
  • 10
  • Thank you for the input! I have made some progress and have successfully modified the code to automatically create a folder for each new user during registration. Additionally, I can now create a user group but I'm struggling with assigning the created user group to the corresponding user. In the code above, after saving the new user, I'm attempting to create a new user group and assign it to the user. However, the assignment does not seem to be successful. Thank you all for your support and guidance! Here is the updated code snippet for reference: https://codefile.io/f/mbwBGLvbdL – weiss May 19 '23 at 15:47
  • Maybe a better solution instead of Xclassing the CreateActionController is to use one of the hooks "registrationProcess_afterSaveCreate" or "confirmRegistrationClass_postProcess". I think the usergroup else is removed because of security reasons. The sr_feuser_register extension has the ability to select usergroups in the registration-process. So maybe unallowed groups are removed, when added to early in the registration-process. – Mogens May 21 '23 at 09:52
  • Thanks for your help! In theory that should work, unfortunately also when using the "registrationProcess_afterSaveCreate" hook the group is not assigned: codefile.io/f/koJHEeAYwi The usergroup is always overrided by [plugin.tx_srfeuserregister_pi1.userGroupAfterConfirmation] in "Constants". However also when i set the automatic group assigning after Confirmation to an empty value (disabled), the new group is not getting assigned. Also, allowedUserGroups in "Constants" are set to 'ALL'. I was not able to make the "confirmRegistrationClass_postProcess" work though. Any more ideas? – weiss May 21 '23 at 19:03
  • After assigning the Usergroup to the user, you must update your user in the FrontendUserRepository in line 67 of your code. $frontendUserRepository->update($newUser); I tried it using the in2code/femanager extension with the FinalCreateEvent. Worked like a charme. If it's still not working with sr_feuser_register i would suggest to use the femanager extension. Would be great if you could up my answer, to let me gain some points. – Mogens May 21 '23 at 20:24
  • And be aware of that the Extbase FrontendUser model and repository is deprected since TYPO3 11 and will be removed in TYPO3 12. I would suggest to already now use own model and repository for your extension if possible. https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/11.4/Deprecation-94654-GenericExtbaseDomainClasses.html – Mogens May 21 '23 at 20:52
  • Thanks again! I am going to follow your advice and use 'femanager'. The usergroup assignment would work in the same way as with sr_feuser_register? The typoscript settings of femanager only allow the group pid, not a data value which i would need. Oh and I already gave you my vote, but it didn't count because of my reputation! – weiss May 22 '23 at 10:33
  • Yes. I mainly used your example code to create the usergroup and attach it to the user. The only thing i changed was that i got the feUser object from the Event. And after persisting the new Usergroup i didn't fetched the group again from the repo. Instead i used the created group. And don't forget to update the FeUser in teh Repo at the end. – Mogens May 23 '23 at 14:37
  • Here is how i did: https://codefile.io/f/In8bJ3WnN0 – Mogens May 23 '23 at 14:58
  • Thank you so much for providing the code.. Unfortunately i can't get it to create the usergroup! I tried it with an event Listener like you did, as well as directly adding the code to the FinalcreateEvent.php. Tried different versions of code. Nothing works. I also tried debugging by creating logs.. I must be jinxed.. – weiss May 23 '23 at 20:57
  • The Eventlistener is also called when executing the registration? The Folder is created? Or does nothing work in the Eventlistener? How did you register the Eventlistener? – Mogens May 24 '23 at 21:28
  • Here is how i registered the EventListener: https://codefile.io/f/ab3kxN82R6 Drop the CommandController. Thats for other purposes. The yaml file must be located in the Configuration folder of your extension. If you run a composer setup, dont forget to dumpautoload. – Mogens May 24 '23 at 21:31
  • No, i wasn't able to execute the Listener at all. I tried adding it to the `extlocalconf.php` but also using your `services.yaml` file it's not doing anything. Do i have to register the yaml somewhere? Anyway, also when i use my code with the added `update($newUser)` function directly in the `FinalCreateEvent.php` file of `femanager` it only creates the group and folder but doesn't add the group to the user (https://codefile.io/f/EY5D0UUSvV). I really don't know what i'm overlooking.. When i used your eventListener Code in the file directly, no group was added at all. – weiss May 24 '23 at 22:09
  • The Services.yaml file needs to be placed in the Configuration folder like Ext:Configuration/Services.yaml - No further registration needed. Your Eventlistener must have an __invoke Function. First of all try to get the Eventlistener running. You could use mine for that. Just adjust the namespace and place it in /Classes/EventListener/FinalCreateEvent.php - In the Services.yaml adjust the Namespace as well. Do not do any fancy constructor overloading before the Eventlistener is running. – Mogens May 24 '23 at 23:11
  • Yes, that's what i did. I copied your code and adapted it to my extension. – weiss May 25 '23 at 17:31
  • Please show your Service.yaml file and your Eventlistener file. – Mogens May 26 '23 at 06:21
  • Here is the Event Listener file https://codefile.io/f/ZUVnwPRC95 and yaml file https://codefile.io/f/ULVKQQo6pR – weiss May 26 '23 at 18:18
  • Are you running TYPO3 with composer? If yes. Did you dumped the autoloading? – Mogens May 26 '23 at 18:48
  • No, i'm using the normal mode! – weiss May 26 '23 at 22:01
  • I tested the code again in my environment. Runs without problems. Make sure you cleared all caches. Else i don't know why it's not running in your env. – Mogens May 26 '23 at 22:40
  • In normal mode you should go to Admin-Tools->Maintenance and flush TYPO3 and PHP Cache. Then go to System->Configuration and check the PSR-14 Event Listeners. There your custom EventListener should be listed. – Mogens May 26 '23 at 23:36
  • Oh perfect! I found the error, services.yaml file was written in lowercase. The EventListener creates and assigns the usergroup now! I am really grateful. Do you by chance have any idea how i can now assign the specific user folder to this usergroup in fal_securedownloads? Would it also work with an event Listener? Or does this only work manually ? – weiss May 27 '23 at 09:34
  • Great. You can either extend the usergroup by a custom Textfield to save the path/foldername. Or you could implement an m:n table that joins the path to the usergroup. I would suggest to extend the usergroup because you only need a 1:1 relation. You can assign the path in the Eventlistener you just implemented. I would suggest to post a new Question for that. You can post the link here. – Mogens May 27 '23 at 10:17
  • Thanks! Made a new [post](https://stackoverflow.com/questions/76346721/automatic-folder-access-for-usergroups-in-typo3-assigning-usergroups-users-t) – weiss May 27 '23 at 11:42
0

I solved the problem by writing data with an event listener in my own typo3 extension into the tx_falsecuredownload_folder table in the typo3 database. You have to generate a sha1-hash for the folder path and use the fe_groups uid and timestamp variable.

Here is the link to the post: Automatically set fe_groups folder access permissions with fal_securedownload - Assign usergroups/users to specific folders in TYPO3

weiss
  • 31
  • 6