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

kusal pushed a commit to branch WW-5428-allowlist-hibernate
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 1c25b0537f63a28ca25db39d146b4595487fb032
Author: Kusal Kithul-Godage <g...@kusal.io>
AuthorDate: Mon Jun 17 21:02:49 2024 +1000

    WW-5428 Allowlist capability should resolve Hibernate proxies when 
disableProxyObjects is not set
---
 .../xwork2/ognl/SecurityMemberAccess.java          | 10 +++++++
 .../com/opensymphony/xwork2/util/ProxyUtil.java    | 33 ++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git 
a/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java 
b/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
index f882b2c58..db0598541 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/SecurityMemberAccess.java
@@ -209,6 +209,16 @@ public class SecurityMemberAccess implements MemberAccess {
      * @return {@code true} if member access is allowed
      */
     protected boolean checkAllowlist(Object target, Member member) {
+        if (!disallowProxyObjectAccess && ProxyUtil.isProxy(target)) {
+            // If disallowProxyObjectAccess is not set, allow resolving 
Hibernate entities to their underlying classes/members
+            // This allows the allowlist capability to function in 
applications where the developer has accepted this risk
+            Object newTarget = ProxyUtil.getHibernateProxyTarget(target);
+            if (newTarget != target) {
+                target = newTarget;
+                member = ProxyUtil.resolveTargetMember(member, newTarget);
+            }
+        }
+
         Class<?> memberClass = member.getDeclaringClass();
         if (!enforceAllowlistEnabled) {
             return true;
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java 
b/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
index c169af20b..895cfb7ee 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/ProxyUtil.java
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.ognl.OgnlCacheFactory;
 import org.apache.commons.lang3.reflect.ConstructorUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.commons.lang3.reflect.MethodUtils;
+import org.hibernate.Hibernate;
 import org.hibernate.proxy.HibernateProxy;
 
 import java.lang.reflect.Constructor;
@@ -33,6 +34,8 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
 
+import static java.lang.reflect.Modifier.isPublic;
+
 /**
  * <code>ProxyUtil</code>
  * <p>
@@ -255,4 +258,34 @@ public class ProxyUtil {
 
         return false;
     }
+
+    /**
+     * @return the target instance of the given object if it is a Hibernate 
proxy object, otherwise the given object
+     */
+    public static Object getHibernateProxyTarget(Object object) {
+        try {
+            return Hibernate.unproxy(object);
+        } catch (NoClassDefFoundError ignored) {
+            return object;
+        }
+    }
+
+    /**
+     * @return matching member on target object if one exists, otherwise the 
same member
+     */
+    public static Member resolveTargetMember(Member proxyMember, Object 
target) {
+        int mod = proxyMember.getModifiers();
+        if (proxyMember instanceof Method) {
+            if (isPublic(mod)) {
+                return 
MethodUtils.getMatchingAccessibleMethod(target.getClass(), 
proxyMember.getName(), ((Method) proxyMember).getParameterTypes());
+            } else {
+                return MethodUtils.getMatchingMethod(target.getClass(), 
proxyMember.getName(), ((Method) proxyMember).getParameterTypes());
+            }
+        } else if (proxyMember instanceof Field) {
+            return FieldUtils.getField(target.getClass(), 
proxyMember.getName(), isPublic(mod));
+        } else if (proxyMember instanceof Constructor && isPublic(mod)) {
+            return 
ConstructorUtils.getMatchingAccessibleConstructor(target.getClass(), 
((Constructor<?>) proxyMember).getParameterTypes());
+        }
+        return proxyMember;
+    }
 }

Reply via email to