Contribute to this guideReport an issue

guidePrivate folders per user

To create separate directories for users, you need to create a simple mechanism to map the current user to an appropriate directory path.

When building the directory path, you should remember about the following that may lead to path traversal attacks:

  • Do not reveal any sensitive information.
  • Do not use any insecure data.

To set a private directory for the current user, you need to dynamically change the configuration in the current HTTP request scope. This can be done with a custom event listener component that listens for the GetConfigForRequestEvent event.

In the example below, it is assumed that the user has been authenticated and their username is stored in the username session attribute. The private user directory path is built using the current user username, so each user has their own directory inside the /tmp folder (e.g. /tmp/user1, /tmp/user2).

package com.cksource.ckfinder.listener;

import com.cksource.ckfinder.config.Config;
import com.cksource.ckfinder.event.GetConfigForRequestEvent;
import com.cksource.ckfinder.exception.InvalidRequestException;
import com.cksource.ckfinder.listener.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Named
public class PerRequestConfigListener implements Listener<GetConfigForRequestEvent> {
    private static final Logger logger = LoggerFactory.getLogger(PerRequestConfigListener.class);

    @Inject
    private HttpSession session;

    @Override
    public void onApplicationEvent(GetConfigForRequestEvent event) {
        String username = (String) session.getAttribute("username");

        if (username == null) {
            throw new InvalidRequestException("Username is not set");
        }

        // It is assumed that the username is safe to use as a part of the file system path.
        // You might need to perform some validation to avoid path traversal security issues.
        String userFolderPath = "/tmp/" + username;

        Path dirPath = Paths.get(userFolderPath);

        // If the directory does not exist, create one.
        if (!Files.exists(dirPath)) {
            logger.info(String.format("Private directory for user \"%s\" doesn't exist", username));

            try {
                Files.createDirectories(dirPath);
                logger.info(String.format("Created private directory for user \"%s\" under %s", username, dirPath));
            } catch (IOException e) {
                logger.error(String.format("Could not create private directory for user \"%s\" under %s", username, dirPath));
            }
        }

        // Update the configuration and use the path as the root of the backend named "default".
        Config.Backend backendConfig = event.getConfig().getBackendConfig("default");

        backendConfig.setRoot(userFolderPath);
    }
}