Skip to content

Commit

Permalink
Fix bug when limited user tries to copy contentlet (#31346)
Browse files Browse the repository at this point in the history
**Bug Description**
The issue occurs when attempting to copy a Contentlet from a Page that
contains a FileContainer while using a limited user account that lacks
READ permission on the DEFAULT host.

**Proposed Fix**
In the Copy Contentlet process, we resolve the FileContainer path using
the getLiveContainerByFolderPath method. This happens after saving the
Contentlet to create a new MultiTree entry, linking the new Contentlet
with the Page.

**Code Reference:**

[ContainerAPIImpl.java#L1151-L1189](https://github.com/dotCMS/core/blob/main/dotCMS/src/main/java/com/dotmarketing/portlets/containers/business/ContainerAPIImpl.java#L1151-L1189)

Related Logic:

[PageResourceHelper.java#L467-L499](https://github.com/dotCMS/core/blob/65c8ebbbf258630b0e053d8f7b06e39062dde4d8/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageResourceHelper.java#L467-L499)

Path Resolution Steps
When resolving the path, the system attempts to:

Use the host from the inputPath parameter.
Use the current host (if there is an active request in the thread).
Use the DEFAULT host.
Currently, all three host options are pre-fetched, and the system
attempts to resolve the path for each. However, if the user lacks READ
permission on the DEFAULT host, a DotSecurityException is thrown.

Fix Implementation
The DEFAULT host is unnecessary for path resolution when the host is
already included in the inputPath. Additionally, if the user lacks READ
permission and the host is missing from the path, resolution will fail
regardless—since the system cannot locate the Container on the DEFAULT
host.

Solution: Ignore the DotSecurityException and exclude the DEFAULT host
from the resolution process.

Fix Reference:
[PR
#31344](https://github.com/dotCMS/core/pull/31344/files#diff-c627ef648a3d8efeafa59e5035157f16ea8ebd05131cecd2375fd2f9d74be5afR1185-R1190)
  • Loading branch information
freddyDOTCMS authored Feb 14, 2025
1 parent 3c19b92 commit 8a67ede
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1179,11 +1179,19 @@ private ResolvedPath resolvePath(final String inputPath,
hostsToFound.put(currentHost.getInode(), currentHost);
}
} catch(DotSecurityException e) {

Logger.debug(ContainerAPIImpl.class,
() -> String.format("The User %s don't have read permission in the default Host, so it is going to be excluded to resolve the follow path %s",
user.getUserId(), inputPath));
}

final Host defaultHost = APILocator.getHostAPI().findDefaultHost(user, respectFrontEndEndRoles);
hostsToFound.put(defaultHost.getInode(), defaultHost);
try {
final Host defaultHost = APILocator.getHostAPI().findDefaultHost(user, respectFrontEndEndRoles);
hostsToFound.put(defaultHost.getInode(), defaultHost);
} catch(DotSecurityException e) {
Logger.debug(ContainerAPIImpl.class,
() -> String.format("The User %s don't have read permission in the default Host, so it is going to be excluded to resolve the follow path %s",
user.getUserId(), inputPath));
}

return find(relativePath, hostsToFound, user, live, respectFrontEndEndRoles);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import com.dotmarketing.business.Role;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.liferay.portal.model.User;

import java.util.Arrays;

public final class PermissionUtilTest {

Expand All @@ -21,4 +24,22 @@ public static void addAnonymousUser(final Permissionable permissionable) throws
PermissionAPI.PERMISSION_READ);
APILocator.getPermissionAPI().save(permission, permissionable, APILocator.systemUser(), false);
}

public static void addPermission(final Permissionable permissionable,
final User user, final String permissionType, final int... permissions) throws DotDataException {

final int permission = Arrays.stream(permissions).sum();

final Permission permissionObject = new Permission(permissionType,
permissionable.getPermissionId(),
APILocator.getRoleAPI().loadRoleByKey(user.getUserId()).getId(),
permission, true);

try {
APILocator.getPermissionAPI().save(permissionObject, permissionable,
APILocator.systemUser(), false);
} catch (DotSecurityException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@

import com.dotcms.JUnit4WeldRunner;
import com.dotcms.contenttype.model.type.ContentType;
import com.dotcms.datagen.ContainerAsFileDataGen;
import com.dotcms.datagen.ContainerDataGen;
import com.dotcms.datagen.ContentTypeDataGen;
import com.dotcms.datagen.SiteDataGen;
import com.dotcms.datagen.TestDataUtils;
import com.dotmarketing.beans.ContainerStructure;
import com.dotmarketing.beans.Host;
import com.dotmarketing.beans.Identifier;
import com.dotmarketing.beans.Inode;
import com.dotcms.datagen.*;
import com.dotmarketing.beans.*;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.CacheLocator;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.db.HibernateUtil;
import com.dotmarketing.db.LocalTransaction;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.AssetUtil;
import com.dotmarketing.portlets.ContentletBaseTest;
import com.dotmarketing.portlets.containers.model.Container;
import com.dotmarketing.portlets.containers.model.FileAssetContainer;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.folders.model.Folder;
import com.dotmarketing.util.UUIDGenerator;
import com.dotmarketing.util.UtilMethods;
import com.liferay.portal.model.User;
import io.vavr.control.Try;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -31,7 +30,9 @@
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;

import static com.dotmarketing.util.Constants.CONTAINER_FOLDER_PATH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
Expand Down Expand Up @@ -490,5 +491,4 @@ private static String generateRandomName(int length) {
}
return name.toString();
}

}

0 comments on commit 8a67ede

Please sign in to comment.