This is an automated email from the ASF dual-hosted git repository.
ashishvijaywargiya 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 4bae54df46 Fixed: updateLayout authorizing under CONTENT_CREATE then
updating unrelated records unchecked (#1745) (#1746)
4bae54df46 is described below
commit 4bae54df463e21ecdc9aeb52297386cccef0862e
Author: Ashish Vijaywargiya <[email protected]>
AuthorDate: Wed Aug 26 23:10:08 2026 +0530
Fixed: updateLayout authorizing under CONTENT_CREATE then updating
unrelated records unchecked (#1745) (#1746)
The updateLayout event built a Content value from caller-supplied
parameters and checked permission for it under the CONTENT_CREATE
operation, then separately loaded the real Content identified by
parameters.contentId and the real DataResource identified by
parameters.dataResourceId and stored both directly, without checking
UPDATE permission on either record and without any check that the
DataResource actually belonged to the Content.
A user holding only view-level Content Manager permissions could use an
existing RESPONSE-purpose Content to pass the CONTENT_CREATE check, then
relink that Content to an arbitrary DataResource and convert it into a
template-bearing (FTL) OFBIZ_FILE resource - a path the normal
updateDataResource service already blocks for the same user, since it
requires CONTENTMGR_SUPER for template-bearing DataResources.
Route both updates through the existing updateContent/updateDataResource
services instead, so permission is checked (via
genericContentPermission/ genericDataResourcePermission, main-action
UPDATE) against the real target records, the same way every other update
path in this component already works.
Test coverage from the original commit is omitted here per request.
Thank you Krishna Uprit for your help in reviewing the changes.
(cherry picked from commit 4cc9848625cfe4d22765167b6476573752f74c82)
---
.../content/minilang/layout/LayoutEvents.xml | 43 ++++++++++------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/applications/content/minilang/layout/LayoutEvents.xml
b/applications/content/minilang/layout/LayoutEvents.xml
index c063808bd5..07441c969d 100644
--- a/applications/content/minilang/layout/LayoutEvents.xml
+++ b/applications/content/minilang/layout/LayoutEvents.xml
@@ -52,37 +52,34 @@ under the License.
<simple-method login-required="true" method-name="updateLayout"
short-description="Update Layout">
<log level="info" message="in updateLayout."/>
- <make-value entity-name="Content" value-field="currentContent"/>
- <set-pk-fields map="parameters" value-field="currentContent"/>
- <set-nonpk-fields map="parameters" value-field="currentContent"/>
- <set field="context.currentContent" from-field="currentContent"/>
+ <!-- Route the actual persistence through
updateContent/updateDataResource so permission is
+ checked (via
genericContentPermission/genericDataResourcePermission, main-action UPDATE)
+ against the real target Content and DataResource records
identified by parameters.contentId
+ and parameters.dataResourceId, instead of against an
attacker-constructed value under the
+ unrelated CONTENT_CREATE operation. This also ensures converting
the target DataResource
+ into a template-bearing (e.g. FTL) resource is gated behind
CONTENTMGR_SUPER, same as the
+ normal updateDataResource path. -->
+ <make-value entity-name="Content" value-field="content"/>
+ <set-pk-fields map="parameters" value-field="content"/>
+ <set-nonpk-fields map="parameters" value-field="content"/>
+ <log level="info" message="content: ${content}"/>
+ <map-to-map map="content" to-map="context"/>
<set field="context.contentPurposeTypeId"
from-field="parameters.contentPurposeTypeId"/>
- <string-to-list list="targetOperationList" string="CONTENT_CREATE"/>
- <set field="context.targetOperationList"
from-field="targetOperationList"/>
<session-to-field field="context.userLogin" session-name="userLogin"/>
- <call-service in-map-name="context"
service-name="checkContentPermission">
- <result-to-field result-name="permissionStatus"
field="permissionStatus"/>
- </call-service>
- <if-compare field="permissionStatus" operator="not-equals"
value="granted" type="String">
- <add-error>
- <fail-property resource="ContentUiLabels"
property="ContentPermissionNotGranted"/>
- </add-error>
- </if-compare>
+ <call-service in-map-name="context" service-name="updateContent"/>
<check-errors/>
- <set field="content.contentId" from-field="parameters.contentId"/>
- <find-by-primary-key entity-name="Content" value-field="content"
map="content"/>
- <set-nonpk-fields map="parameters" value-field="content"/>
- <log level="info" message="content: ${content}"/>
- <store-value value-field="content"/>
<field-to-request field="content.contentId" request-name="contentId"/>
- <set field="dataResource.dataResourceId"
from-field="parameters.dataResourceId"/>
- <find-by-primary-key entity-name="DataResource"
value-field="dataResource" map="dataResource"/>
+
+ <make-value entity-name="DataResource" value-field="dataResource"/>
+ <set-pk-fields map="parameters" value-field="dataResource"/>
<set-nonpk-fields map="parameters" value-field="dataResource"/>
<set field="dataResource.objectInfo"
from-field="parameters.drObjectInfo"/>
<log level="info" message="dataResource: ${dataResource}"/>
- <store-value value-field="dataResource"/>
- <field-to-request field="dataResource.dataResourceId"
request-name="drDataResourceId"/>
+ <map-to-map map="dataResource" to-map="context2"/>
+ <session-to-field field="context2.userLogin" session-name="userLogin"/>
+ <call-service in-map-name="context2"
service-name="updateDataResource"/>
<check-errors/>
+ <field-to-request field="dataResource.dataResourceId"
request-name="drDataResourceId"/>
</simple-method>
<simple-method login-required="true" method-name="createLayoutText"
short-description="Create Layout Text">