You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2026/07/08 19:49:25 UTC

(struts) 08/08: WW-4858 test(json): cover nested and list-element paths; clarify filter comments

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

lukaszlenart pushed a commit to branch WW-4858-json-parameter-filtering
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c4335c68d2cf5c05282200c47ed744df83ea3609
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Wed Jul 8 20:58:25 2026 +0200

    WW-4858 test(json): cover nested and list-element paths; clarify filter comments
    
    Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
 .../org/apache/struts2/json/JSONInterceptor.java   |  3 +-
 .../apache/struts2/json/JSONInterceptorTest.java   | 39 ++++++++++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java
index 0d584d830..b1c172388 100644
--- a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java
+++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java
@@ -144,7 +144,7 @@ public class JSONInterceptor extends AbstractInterceptor {
                 if (rootObject == null) // model overrides action
                     rootObject = invocation.getStack().peek();
 
-                // enforce @StrutsParameter authorization on JSON body keys
+                // enforce name/value acceptability (patterns, length, *Aware) and @StrutsParameter authorization on JSON body keys
                 filterUnacceptableKeys(json, rootObject, invocation.getAction());
 
                 // populate fields
@@ -263,6 +263,7 @@ public class JSONInterceptor extends AbstractInterceptor {
                 filterUnacceptableKeysRecursive((Map) item, elementPrefix, target, action);
             } else if (item instanceof java.util.List) {
                 filterUnacceptableList((java.util.List) item, elementPrefix, target, action);
+            // Scalar list elements are value-checked only; their parent key already passed name/authorization checks.
             } else if (!isAcceptableValue(elementPrefix, item, action)) {
                 it.remove();
             }
diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
index 89ec91dfb..e1aed361b 100644
--- a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
+++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java
@@ -749,6 +749,45 @@ public class JSONInterceptorTest extends StrutsTestCase {
         assertNull(action.getBar());
     }
 
+    public void testExcludedNamePatternRejectsNestedKey() throws Exception {
+        this.request.setContent("{\"bean\": {\"stringField\": \"keep\", \"intField\": 42}}".getBytes());
+        this.request.addHeader("Content-Type", "application/json");
+
+        JSONInterceptor interceptor = createInterceptor();
+        org.apache.struts2.security.DefaultExcludedPatternsChecker excluded =
+                new org.apache.struts2.security.DefaultExcludedPatternsChecker();
+        excluded.setExcludedPatterns("bean\\.intField");
+        interceptor.setExcludedPatterns(excluded);
+        TestAction action = new TestAction();
+
+        this.invocation.setAction(action);
+        this.invocation.getStack().push(action);
+
+        interceptor.intercept(this.invocation);
+
+        assertNotNull(action.getBean());
+        assertEquals("keep", action.getBean().getStringField());
+        assertEquals(0, action.getBean().getIntField());
+    }
+
+    public void testExcludedValuePatternRejectsListElement() throws Exception {
+        this.request.setContent("{\"list\": [\"good\", \"badvalue\"]}".getBytes());
+        this.request.addHeader("Content-Type", "application/json");
+
+        JSONInterceptor interceptor = createInterceptor();
+        interceptor.setExcludedValuePatterns("badvalue");
+        TestAction action = new TestAction();
+
+        this.invocation.setAction(action);
+        this.invocation.getStack().push(action);
+
+        interceptor.intercept(this.invocation);
+
+        assertNotNull(action.getList());
+        assertEquals(1, action.getList().size());
+        assertEquals("good", action.getList().get(0));
+    }
+
     public void testParamNameMaxLengthRejectsLongKey() throws Exception {
         this.request.setContent("{\"foo\":\"a\"}".getBytes());
         this.request.addHeader("Content-Type", "application/json");