This is an automated email from the ASF dual-hosted git repository.

mridulpathak pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release24.09 by this push:
     new 62cf17aee9 Fixed: moveContentJson lets a caller without UPDATE 
permission re-parent content associations
62cf17aee9 is described below

commit 62cf17aee90b73e6d913f4746f394fde38d697c2
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 b75ffd9c95..2bd644f810 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 javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.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");

Reply via email to