This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 1b43f48c24d85a92e60936312d00a1753b9659bf Author: Robert Lazarski <[email protected]> AuthorDate: Sun Oct 11 06:14:00 2026 -1000 Test that json field filter dot paths cannot reach excluded fields The nested walker selects fields separately from the top-level prune, so cover this$0 and @Json(ignore = true) fields reached through dot notation (items.this$0, this$0.dbPassword, creds.apiToken) as well. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- .../FieldFilteringMessageFormatterTest.java | 36 ++++++++++++++++++++++ .../MoshiStreamingMessageFormatterTest.java | 30 ++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/modules/json/test/org/apache/axis2/json/streaming/FieldFilteringMessageFormatterTest.java b/modules/json/test/org/apache/axis2/json/streaming/FieldFilteringMessageFormatterTest.java index 7a215ce51e..bc104cab48 100644 --- a/modules/json/test/org/apache/axis2/json/streaming/FieldFilteringMessageFormatterTest.java +++ b/modules/json/test/org/apache/axis2/json/streaming/FieldFilteringMessageFormatterTest.java @@ -293,6 +293,35 @@ public class FieldFilteringMessageFormatterTest { raw.contains("db-password-123")); } + @Test + public void testSyntheticFieldsNotReachableThroughDotNotation() throws Exception { + // The nested walker enumerates fields separately from the top-level + // prune, so a dot path must not reach this$0 either -- directly on + // the return object or on elements of a nested collection. + EnclosingService svc = new EnclosingService("db-password-123"); + List<EnclosingService.Result> items = new ArrayList<>(); + items.add(svc.new Result("ok")); + setReturnObject(new ResultHolder("SUCCESS", items)); + outMsgContext.setProperty(JsonConstant.FIELD_FILTER, + setOf("status", "items.status", "items.this$0")); + + formatter.writeTo(outMsgContext, outputFormat, outputStream, false); + Assert.assertFalse("enclosing instance state must not leak via items.this$0", + outputStream.toString("UTF-8").contains("db-password-123")); + JsonElement item = parseResponse().getAsJsonObject() + .getAsJsonArray("items").get(0); + Assert.assertEquals("ok", item.getAsJsonObject().get("status").getAsString()); + Assert.assertFalse(item.getAsJsonObject().has("this$0")); + + outputStream.reset(); + setReturnObject(svc.new Result("ok")); + outMsgContext.setProperty(JsonConstant.FIELD_FILTER, + setOf("status", "this$0.dbPassword")); + formatter.writeTo(outMsgContext, outputFormat, outputStream, false); + Assert.assertFalse("enclosing instance state must not leak via this$0.dbPassword", + outputStream.toString("UTF-8").contains("db-password-123")); + } + // ── parseFieldsCsv / parseFieldsFromUrl tests ───────────────────────── @Test @@ -470,6 +499,13 @@ public class FieldFilteringMessageFormatterTest { } } + /** Holds a collection of inner-class results for nested filtering tests. */ + public static class ResultHolder { + public String status; + public List<EnclosingService.Result> items; + public ResultHolder(String s, List<EnclosingService.Result> i) { status = s; items = i; } + } + /** POJO with static and transient fields for modifier filtering test. */ public static class StaticTransientData { public static final String CONSTANT = "should-never-serialize"; diff --git a/modules/json/test/org/apache/axis2/json/streaming/MoshiStreamingMessageFormatterTest.java b/modules/json/test/org/apache/axis2/json/streaming/MoshiStreamingMessageFormatterTest.java index e66f342104..8065c4ce6d 100644 --- a/modules/json/test/org/apache/axis2/json/streaming/MoshiStreamingMessageFormatterTest.java +++ b/modules/json/test/org/apache/axis2/json/streaming/MoshiStreamingMessageFormatterTest.java @@ -192,6 +192,29 @@ public class MoshiStreamingMessageFormatterTest { result.contains("secret-token-xyz")); } + /** + * Same as above for an ignored field on elements of a nested + * collection, which go through the nested walker rather than the + * top-level prune. + */ + @Test + public void testDotNotationDoesNotExposeIgnoredField() throws Exception { + CredentialHolder holder = new CredentialHolder(java.util.List.of( + new CredentialData("public-label", "secret-token-xyz"))); + outMsgContext.setProperty(JsonConstant.RETURN_OBJECT, holder); + outMsgContext.setProperty(JsonConstant.RETURN_TYPE, CredentialHolder.class); + outMsgContext.setProperty(JsonConstant.FIELD_FILTER, + new LinkedHashSet<>(Arrays.asList("creds.label", "creds.apiToken"))); + + new MoshiStreamingMessageFormatter().writeTo( + outMsgContext, outputFormat, outputStream, false); + + String result = outputStream.toString("UTF-8"); + Assert.assertTrue(result.contains("\"label\":\"public-label\"")); + Assert.assertFalse("@Json(ignore = true) field must not be exposed via dot notation", + result.contains("secret-token-xyz")); + } + /** * Test content type passthrough. */ @@ -219,6 +242,13 @@ public class MoshiStreamingMessageFormatterTest { return fault; } + /** Wraps CredentialData in a collection for the nested filtering test. */ + public static class CredentialHolder { + public java.util.List<CredentialData> creds; + public CredentialHolder() {} + public CredentialHolder(java.util.List<CredentialData> c) { creds = c; } + } + /** POJO with a field opted out of serialization via {@code @Json(ignore = true)}. */ public static class CredentialData { public String label;
