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 <[email protected]> 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 <[email protected]> --- .../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");
