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 16517b20de Improved: Validate tenant ID before creating a per-tenant
delegator (#1663)
16517b20de is described below
commit 16517b20de79ea0563181b7b52be07ba01fb173a
Author: Mridul Pathak <[email protected]>
AuthorDate: Mon Aug 17 12:22:58 2026 +0530
Improved: Validate tenant ID before creating a per-tenant delegator (#1663)
Backported from trunk (#1647).
---
.../org/apache/ofbiz/entity/DelegatorFactory.java | 5 +++-
.../java/org/apache/ofbiz/webapp/WebAppUtil.java | 27 ++++++++++++++++++++++
.../apache/ofbiz/webapp/control/ContextFilter.java | 3 +++
.../apache/ofbiz/webapp/control/LoginWorker.java | 4 ++++
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
index c810e0798f..1bc38ed436 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/DelegatorFactory.java
@@ -39,10 +39,13 @@ public abstract class DelegatorFactory implements
Factory<Delegator, String> {
Runtime.getRuntime().availableProcessors(), 10, true);
public static Delegator getDelegator(String delegatorName) {
- Future<Delegator> future = getDelegatorFuture(delegatorName);
+ String cacheKey = delegatorName == null ? "default" : delegatorName;
+ Future<Delegator> future = getDelegatorFuture(cacheKey);
try {
return future.get();
} catch (ExecutionException | InterruptedException e) {
+ // do not let a failed lookup permanently occupy the cache under
its (possibly caller-supplied) key
+ DELEGATORS.remove(cacheKey, future);
Debug.logError(e, MODULE);
return null;
}
diff --git
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppUtil.java
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppUtil.java
index 07f87a7b9d..c0827744d9 100644
--- a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppUtil.java
+++ b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppUtil.java
@@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
@@ -41,6 +42,9 @@ import org.apache.ofbiz.base.util.UtilXml.LocalResolver;
import org.apache.ofbiz.base.util.cache.UtilCache;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.DelegatorFactory;
+import org.apache.ofbiz.entity.GenericEntityException;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.security.Security;
import org.apache.ofbiz.security.SecurityConfigurationException;
import org.apache.ofbiz.security.SecurityFactory;
@@ -68,6 +72,8 @@ public final class WebAppUtil {
public static final String CONTROL_MOUNT_POINT = "control";
private static final Path WEB_APP_FILE_NAME = Paths.get("WEB-INF",
"web.xml");
private static final UtilCache<Path, WebXml> WEB_XML_CACHE =
UtilCache.createUtilCache("webapp.WebXml");
+ // matches the "id" field type's VARCHAR(20) column width used by the
Tenant entity's primary key
+ private static final Pattern TENANT_ID_PATTERN =
Pattern.compile("[A-Za-z0-9_-]{1,20}");
/**
* Returns the control servlet path. The path consists of the web
application's mount-point
@@ -219,6 +225,27 @@ public final class WebAppUtil {
return delegator;
}
+ /**
+ * Returns true if the given tenant ID belongs to an enabled
<code>Tenant</code> record, as looked up through
+ * the given base (non-tenant-specific) delegator. Callers must check this
before building a per-tenant
+ * delegator name from request-supplied input, since {@link
DelegatorFactory} caches every delegator name it is
+ * asked for, including ones that fail to resolve.
+ * @param baseDelegator
+ * @param tenantId
+ */
+ public static boolean isValidTenantId(Delegator baseDelegator, String
tenantId) {
+ if (UtilValidate.isEmpty(tenantId) ||
!TENANT_ID_PATTERN.matcher(tenantId).matches()) {
+ return false;
+ }
+ try {
+ GenericValue tenant =
EntityQuery.use(baseDelegator).from("Tenant").where("tenantId",
tenantId).queryOne();
+ return tenant != null && !"Y".equals(tenant.getString("disabled"));
+ } catch (GenericEntityException e) {
+ Debug.logError(e, "Error looking up tenant ID " + tenantId,
MODULE);
+ return false;
+ }
+ }
+
public static Security getSecurity(ServletContext servletContext) {
Security security = (Security) servletContext.getAttribute("security");
if (security == null) {
diff --git
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ContextFilter.java
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ContextFilter.java
index ae140866d1..a8ef72f1c3 100644
---
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ContextFilter.java
+++
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ContextFilter.java
@@ -139,6 +139,9 @@ public class ContextFilter implements Filter {
if (UtilValidate.isEmpty(tenantId)) {
tenantId = httpRequest.getParameter("userTenantId");
}
+ if (UtilValidate.isNotEmpty(tenantId) &&
!WebAppUtil.isValidTenantId(baseDelegator, tenantId)) {
+ tenantId = null;
+ }
if (UtilValidate.isNotEmpty(tenantId)) {
// if the request path is a root mount then redirect to
the initial path
if ("".equals(httpRequest.getContextPath()) &&
"".equals(httpRequest.getServletPath())) {
diff --git
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
index bb83d26ddb..40f5842105 100644
---
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
+++
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
@@ -474,8 +474,12 @@ public final class LoginWorker {
if (delegatorNameHashIndex == -1 || (currentDelegatorTenantId !=
null && !tenantId.equals(currentDelegatorTenantId))) {
// make that tenant active, setup a new delegator and a new
dispatcher
String delegatorName = delegator.getDelegatorBaseName() + "#"
+ tenantId;
+ Delegator baseDelegator =
DelegatorFactory.getDelegator(delegator.getDelegatorBaseName());
try {
+ if (!WebAppUtil.isValidTenantId(baseDelegator, tenantId)) {
+ throw new NullPointerException("Tenant [" + tenantId +
"] not found");
+ }
// after this line the delegator is replaced with the new
per-tenant delegator
delegator = DelegatorFactory.getDelegator(delegatorName);
dispatcher =
WebAppUtil.makeWebappDispatcher(servletContext, delegator);