This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new b361fe2b34 Fixed: moveContentJson lets a caller without UPDATE
permission re-parent content associations
b361fe2b34 is described below
commit b361fe2b34f0825b996bdcc155962fc891c005e9
Author: Mridul Pathak <[email protected]>
AuthorDate: Mon Sep 21 17:06:07 2026 +0530
Fixed: moveContentJson lets a caller without UPDATE permission re-parent
content associations
ContentJsonEvents.moveContent (backing POST
/content/control/moveContentJson) performed no permission check at all, unlike
the equivalent updateContent/createContentAssoc/removeContentAssoc services,
which all require genericContentPermission UPDATE, so any authenticated user,
including one with only view-only content roles, could call the endpoint
directly and move a content association away from its current parent to any
other regardless of ownership.
Check UPDATE permission on both the old and the new parent content before
performing the move, mirroring what createContentAssoc/removeContentAssoc each
already require for the equivalent entity-level change.
---
.../ofbiz/content/cms/ContentJsonEvents.java | 26 +++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git
a/applications/content/src/main/java/org/apache/ofbiz/content/cms/ContentJsonEvents.java
b/applications/content/src/main/java/org/apache/ofbiz/content/cms/ContentJsonEvents.java
index b6beb0dad7..bc8bc7ca3b 100644
---
a/applications/content/src/main/java/org/apache/ofbiz/content/cms/ContentJsonEvents.java
+++
b/applications/content/src/main/java/org/apache/ofbiz/content/cms/ContentJsonEvents.java
@@ -28,12 +28,14 @@ import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.ofbiz.base.lang.JSON;
import org.apache.ofbiz.base.util.UtilDateTime;
import org.apache.ofbiz.base.util.UtilGenerics;
+import org.apache.ofbiz.base.util.UtilHttp;
import org.apache.ofbiz.base.util.UtilMisc;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
@@ -43,6 +45,9 @@ import org.apache.ofbiz.entity.condition.EntityCondition;
import org.apache.ofbiz.entity.transaction.TransactionUtil;
import org.apache.ofbiz.entity.util.EntityUtil;
import org.apache.ofbiz.entity.util.EntityQuery;
+import org.apache.ofbiz.service.GenericServiceException;
+import org.apache.ofbiz.service.LocalDispatcher;
+import org.apache.ofbiz.service.ServiceUtil;
public class ContentJsonEvents {
@@ -83,8 +88,13 @@ public class ContentJsonEvents {
return "success";
}
- public static String moveContent(HttpServletRequest request,
HttpServletResponse response) throws GenericEntityException, IOException {
+ public static String moveContent(HttpServletRequest request,
HttpServletResponse response)
+ throws GenericEntityException, GenericServiceException,
IOException {
final Delegator delegator = (Delegator)
request.getAttribute("delegator");
+ final LocalDispatcher dispatcher = (LocalDispatcher)
request.getAttribute("dispatcher");
+ final HttpSession session = request.getSession();
+ final GenericValue userLogin = (GenericValue)
session.getAttribute("userLogin");
+ final Locale locale = UtilHttp.getLocale(request);
final String contentIdTo = request.getParameter("contentIdTo");
final String contentIdFrom = request.getParameter("contentIdFrom");
@@ -92,6 +102,11 @@ public class ContentJsonEvents {
final String contentAssocTypeId =
request.getParameter("contentAssocTypeId");
final Timestamp fromDate =
Timestamp.valueOf(request.getParameter("fromDate"));
+ // moving a content association modifies both the old and the new
parent, so both need
+ // the same UPDATE permission that
createContentAssoc/removeContentAssoc each enforce
+ checkUpdateContentPermission(dispatcher, userLogin, locale,
contentIdFrom);
+ checkUpdateContentPermission(dispatcher, userLogin, locale,
contentIdFromNew);
+
final Timestamp now = UtilDateTime.nowTimestamp();
GenericValue assoc = TransactionUtil.inTransaction(() -> {
GenericValue oldAssoc =
EntityQuery.use(delegator).from("ContentAssoc")
@@ -120,6 +135,15 @@ public class ContentJsonEvents {
return "success";
}
+ private static void checkUpdateContentPermission(LocalDispatcher
dispatcher, GenericValue userLogin, Locale locale, String contentId)
+ throws GenericServiceException {
+ Map<String, Object> permSvcCtx = UtilMisc.toMap("userLogin",
userLogin, "locale", locale, "mainAction", "UPDATE", "contentId", contentId);
+ Map<String, Object> permSvcResp =
dispatcher.runSync("genericContentPermission", permSvcCtx);
+ if (ServiceUtil.isError(permSvcResp) ||
!Boolean.TRUE.equals(permSvcResp.get("hasPermission"))) {
+ throw new GenericServiceException("Permission denied to move
content [" + contentId + "]");
+ }
+ }
+
public static String deleteContent(HttpServletRequest request,
HttpServletResponse response) throws GenericEntityException {
Delegator delegator = (Delegator) request.getAttribute("delegator");
String contentId = request.getParameter("contentId");