[
https://issues.apache.org/jira/browse/WW-5747?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Lukasz Lenart reassigned WW-5747:
---------------------------------
Assignee: Lukasz Lenart
> RedactionAwareDeserializer leaves the parser mid-object when it drops a REST
> body object
> ----------------------------------------------------------------------------------------
>
> Key: WW-5747
> URL: https://issues.apache.org/jira/browse/WW-5747
> Project: Struts 2
> Issue Type: Bug
> Components: Plugin - REST
> Reporter: Lukasz Lenart
> Assignee: Lukasz Lenart
> Priority: Major
> Fix For: 7.4.0
>
>
> h2. Summary
> {{RedactionAwareDeserializer}} wraps every bean deserializer in the REST
> plugin's Jackson authorization and, when construction fails after a
> {{@StrutsParameter}} redaction marked its scope, catches the
> {{JsonMappingException}} and returns {{null}} so the whole object is dropped
> rather than partially exposed. It returns without moving the parser: whatever
> tokens of the dropped object remain unread are then consumed by the
> _enclosing_ bean's property loop.
> h2. Current behaviour
> Any failure that fires before the dropped object's last field desyncs the
> read. Two shapes reach it:
> * a creator-bound bean whose construction fails when its last creator
> parameter arrives (a redacted primitive under
> {{FAIL_ON_NULL_FOR_PRIMITIVES}}, a compact constructor rejecting {{null}})
> while non-creator fields follow it in the body;
> * a bean whose property-based {{@JsonIdentityInfo}} id is a bean that itself
> failed to construct on a redacted member: the {{null}} id fails Jackson's
> binding at the {{id}} property (WW-5746).
> Reproduced with this fixture, {{child.id.k}} denied and every other path
> granted:
> {code:java}public record StrictKey(String k) {
> public StrictKey {
> Objects.requireNonNull(k);
> }
> }
> @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
> property = "id")
> public class StrictIdentified {
> public StrictKey id;
> public String name;
> }
> public class StrictHolder {
> public StrictIdentified child;
> public String other;
> public String name;
> }
> {code}
> {code:json}{"child": {"id": {"k": "a"}, "name": "x"}, "other": "o"}
> {code}
> {{child}} is {{null}} as intended, but the child's {{name}} value {{x}} was
> bound to the _holder's_ {{name}}, and the holder's own {{other}} was lost
> because its object read ended at the child's closing brace. Without a
> same-named property on the parent the stray field raises "Unrecognized
> field", which — the parent's scope being marked redacted — silently drops the
> whole root object instead.
> The misplaced value still passes the parent property's own
> {{@StrutsParameter}} check at its own path, so this is data landing in the
> wrong property, not an authorization bypass.
> h2. Proposed change
> Resync before returning {{null}}: record the parser's nesting depth (and
> whether the entry token was {{START_OBJECT}}, {{START_ARRAY}} or a
> {{FIELD_NAME}} inside the object) when the wrapper is entered, and on a
> swallowed failure skip tokens — {{skipChildren()}} on any nested start token
> — until the matching {{END_OBJECT}} or {{END_ARRAY}} at that depth has been
> consumed. A scalar entry token needs no resync. Cover both shapes above with
> tests, asserting the parent's later properties still bind and the dropped
> object's fields never reach the parent.
> h2. Compatibility notes
> No configuration or API change. Only bodies that already trigger an object
> drop are affected, and only in that the enclosing object is now read
> correctly afterwards.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)