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

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

commit 25dfaec580a2c4a595e59da88e3dbce6ba51db58
Author: Jacopo Cappellato <[email protected]>
AuthorDate: Wed Apr 8 10:48:18 2026 +0200

    Improved: Move file path validation to SecurityUtil
    
    (cherry picked from commit 05fbeb5c2c4991550d9d99207531308796befeef)
---
 .../ofbiz/content/data/DataResourceWorker.java     | 79 ++--------------------
 .../org/apache/ofbiz/security/SecurityUtil.java    | 74 ++++++++++++++++++++
 2 files changed, 79 insertions(+), 74 deletions(-)

diff --git 
a/applications/content/src/main/java/org/apache/ofbiz/content/data/DataResourceWorker.java
 
b/applications/content/src/main/java/org/apache/ofbiz/content/data/DataResourceWorker.java
index 01400c8067..1b749d0326 100644
--- 
a/applications/content/src/main/java/org/apache/ofbiz/content/data/DataResourceWorker.java
+++ 
b/applications/content/src/main/java/org/apache/ofbiz/content/data/DataResourceWorker.java
@@ -84,6 +84,7 @@ import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.entity.util.EntityUtilProperties;
 import org.apache.ofbiz.service.GenericServiceException;
 import org.apache.ofbiz.service.LocalDispatcher;
+import org.apache.ofbiz.security.SecurityUtil;
 import org.apache.ofbiz.service.ServiceUtil;
 import org.apache.ofbiz.widget.model.FormFactory;
 import org.apache.ofbiz.widget.model.ModelForm;
@@ -468,76 +469,6 @@ public class DataResourceWorker implements 
org.apache.ofbiz.widget.content.DataR
         return prefix;
     }
 
-    /**
-     * Checks that the given file is within one of the directories listed in
-     * {@code content.data.local.file.allowed.paths} (security.properties).
-     * Use {@code ${ofbiz.home}} as a portable placeholder for the OFBiz home 
directory.
-     */
-    private static void checkLocalFileAllowList(File file) throws 
GeneralException {
-        try {
-            String canonicalFilePath = file.getCanonicalPath();
-            String ofbizHome = System.getProperty("ofbiz.home");
-            String allowedPathsStr = 
UtilProperties.getPropertyValue("security",
-                    "content.data.local.file.allowed.paths", "${ofbiz.home}");
-            if (UtilValidate.isNotEmpty(allowedPathsStr)) {
-                boolean inAllowedPath = false;
-                for (String allowedPath : allowedPathsStr.split(",")) {
-                    allowedPath = allowedPath.trim().replace("${ofbiz.home}", 
ofbizHome);
-                    if (UtilValidate.isEmpty(allowedPath)) {
-                        continue;
-                    }
-                    String canonicalAllowedDir = new 
File(allowedPath).getCanonicalPath();
-                    if (canonicalFilePath.startsWith(canonicalAllowedDir + 
File.separator)
-                            || canonicalFilePath.equals(canonicalAllowedDir)) {
-                        inAllowedPath = true;
-                        break;
-                    }
-                }
-                if (!inAllowedPath) {
-                    throw new GeneralException("Access to file denied: path is 
not within an allowed directory");
-                }
-            }
-        } catch (IOException e) {
-            throw new GeneralException("Unable to validate file path: " + 
e.getMessage());
-        }
-    }
-
-    /**
-     * Checks that the given file is within the OFBiz home directory and 
within one of the
-     * subdirectories listed in {@code content.data.ofbiz.file.allowed.paths} 
(security.properties).
-     */
-    private static void checkOfbizFileAllowList(File file) throws 
GeneralException {
-        try {
-            String canonicalHome = new 
File(System.getProperty("ofbiz.home")).getCanonicalPath();
-            String canonicalFilePath = file.getCanonicalPath();
-            if (!canonicalFilePath.startsWith(canonicalHome + File.separator)) 
{
-                throw new GeneralException("Access to file denied: path 
resolves outside of the OFBiz home directory");
-            }
-            String allowedPathsStr = 
UtilProperties.getPropertyValue("security",
-                    "content.data.ofbiz.file.allowed.paths", 
"applications/,themes/,plugins/,runtime/");
-            if (UtilValidate.isNotEmpty(allowedPathsStr)) {
-                boolean inAllowedPath = false;
-                for (String relPath : allowedPathsStr.split(",")) {
-                    relPath = relPath.trim().replaceAll("^/+", "");
-                    if (UtilValidate.isEmpty(relPath)) {
-                        continue;
-                    }
-                    String canonicalAllowedDir = new File(canonicalHome, 
relPath).getCanonicalPath();
-                    if (canonicalFilePath.startsWith(canonicalAllowedDir + 
File.separator)
-                            || canonicalFilePath.equals(canonicalAllowedDir)) {
-                        inAllowedPath = true;
-                        break;
-                    }
-                }
-                if (!inAllowedPath) {
-                    throw new GeneralException("Access to file denied: path is 
not within an allowed directory");
-                }
-            }
-        } catch (IOException e) {
-            throw new GeneralException("Unable to validate file path: " + 
e.getMessage());
-        }
-    }
-
     /**
      * Checks that the given file is within the provided context root 
directory.
      */
@@ -692,7 +623,7 @@ public class DataResourceWorker implements 
org.apache.ofbiz.widget.content.DataR
             if (!file.isAbsolute()) {
                 throw new GeneralException("File (" + objectInfo + ") is not 
absolute");
             }
-            checkLocalFileAllowList(file);
+            SecurityUtil.checkLocalFileAllowList(file);
         } else if ("OFBIZ_FILE".equals(dataResourceTypeId) || 
"OFBIZ_FILE_BIN".equals(dataResourceTypeId)) {
             String prefix = System.getProperty("ofbiz.home");
 
@@ -704,7 +635,7 @@ public class DataResourceWorker implements 
org.apache.ofbiz.widget.content.DataR
             if (!file.exists()) {
                 throw new FileNotFoundException("No file found: " + (prefix + 
sep + objectInfo));
             }
-            checkOfbizFileAllowList(file);
+            SecurityUtil.checkOfbizFileAllowList(file);
         } else if ("CONTEXT_FILE".equals(dataResourceTypeId) || 
"CONTEXT_FILE_BIN".equals(dataResourceTypeId)) {
             if (UtilValidate.isEmpty(contextRoot)) {
                 throw new GeneralException("Cannot find CONTEXT_FILE with an 
empty context root!");
@@ -1257,7 +1188,7 @@ public class DataResourceWorker implements 
org.apache.ofbiz.widget.content.DataR
             if (!file.exists()) {
                 throw new FileNotFoundException("No file found: " + 
file.getAbsolutePath());
             }
-            checkLocalFileAllowList(file);
+            SecurityUtil.checkLocalFileAllowList(file);
             try (InputStreamReader in = new InputStreamReader(new 
FileInputStream(file), StandardCharsets.UTF_8)) {
                 UtilIO.copy(in, out);
             }
@@ -1271,7 +1202,7 @@ public class DataResourceWorker implements 
org.apache.ofbiz.widget.content.DataR
             if (!file.exists()) {
                 throw new FileNotFoundException("No file found: " + 
file.getAbsolutePath());
             }
-            checkOfbizFileAllowList(file);
+            SecurityUtil.checkOfbizFileAllowList(file);
             try (InputStreamReader in = new InputStreamReader(new 
FileInputStream(file), StandardCharsets.UTF_8)) {
                 UtilIO.copy(in, out);
             }
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/SecurityUtil.java 
b/framework/security/src/main/java/org/apache/ofbiz/security/SecurityUtil.java
index 0f6adbd14f..ce61571985 100644
--- 
a/framework/security/src/main/java/org/apache/ofbiz/security/SecurityUtil.java
+++ 
b/framework/security/src/main/java/org/apache/ofbiz/security/SecurityUtil.java
@@ -19,12 +19,16 @@
 package org.apache.ofbiz.security;
 
 
+import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
 import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.GeneralException;
+import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilValidate;
@@ -135,6 +139,76 @@ public final class SecurityUtil {
         return false;
     }
 
+    /**
+     * Checks that the given file is within one of the directories listed in
+     * {@code content.data.local.file.allowed.paths} (security.properties).
+     * Use {@code ${ofbiz.home}} as a portable placeholder for the OFBiz home 
directory.
+     */
+    public static void checkLocalFileAllowList(File file) throws 
GeneralException {
+        try {
+            String canonicalFilePath = file.getCanonicalPath();
+            String ofbizHome = System.getProperty("ofbiz.home");
+            String allowedPathsStr = 
UtilProperties.getPropertyValue("security",
+                    "content.data.local.file.allowed.paths", "${ofbiz.home}");
+            if (UtilValidate.isNotEmpty(allowedPathsStr)) {
+                boolean inAllowedPath = false;
+                for (String allowedPath : allowedPathsStr.split(",")) {
+                    allowedPath = allowedPath.trim().replace("${ofbiz.home}", 
ofbizHome);
+                    if (UtilValidate.isEmpty(allowedPath)) {
+                        continue;
+                    }
+                    String canonicalAllowedDir = new 
File(allowedPath).getCanonicalPath();
+                    if (canonicalFilePath.startsWith(canonicalAllowedDir + 
File.separator)
+                            || canonicalFilePath.equals(canonicalAllowedDir)) {
+                        inAllowedPath = true;
+                        break;
+                    }
+                }
+                if (!inAllowedPath) {
+                    throw new GeneralException("Access to file denied: path is 
not within an allowed directory");
+                }
+            }
+        } catch (IOException e) {
+            throw new GeneralException("Unable to validate file path: " + 
e.getMessage());
+        }
+    }
+
+    /**
+     * Checks that the given file is within the OFBiz home directory and 
within one of the
+     * subdirectories listed in {@code content.data.ofbiz.file.allowed.paths} 
(security.properties).
+     */
+    public static void checkOfbizFileAllowList(File file) throws 
GeneralException {
+        try {
+            String canonicalHome = new 
File(System.getProperty("ofbiz.home")).getCanonicalPath();
+            String canonicalFilePath = file.getCanonicalPath();
+            if (!canonicalFilePath.startsWith(canonicalHome + File.separator)) 
{
+                throw new GeneralException("Access to file denied: path 
resolves outside of the OFBiz home directory");
+            }
+            String allowedPathsStr = 
UtilProperties.getPropertyValue("security",
+                    "content.data.ofbiz.file.allowed.paths", 
"applications/,themes/,plugins/,runtime/");
+            if (UtilValidate.isNotEmpty(allowedPathsStr)) {
+                boolean inAllowedPath = false;
+                for (String relPath : allowedPathsStr.split(",")) {
+                    relPath = relPath.trim().replaceAll("^/+", "");
+                    if (UtilValidate.isEmpty(relPath)) {
+                        continue;
+                    }
+                    String canonicalAllowedDir = new File(canonicalHome, 
relPath).getCanonicalPath();
+                    if (canonicalFilePath.startsWith(canonicalAllowedDir + 
File.separator)
+                            || canonicalFilePath.equals(canonicalAllowedDir)) {
+                        inAllowedPath = true;
+                        break;
+                    }
+                }
+                if (!inAllowedPath) {
+                    throw new GeneralException("Access to file denied: path is 
not within an allowed directory");
+                }
+            }
+        } catch (IOException e) {
+            throw new GeneralException("Unable to validate file path: " + 
e.getMessage());
+        }
+    }
+
     /**
      * Return a JWToken for authenticate a userLogin with salt the token by 
userLoginId and currentPassword
      */

Reply via email to