[
https://issues.apache.org/jira/browse/WW-5745?focusedWorklogId=1041580&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1041580
]
ASF GitHub Bot logged work on WW-5745:
--------------------------------------
Author: ASF GitHub Bot
Created on: 15/Sep/26 07:38
Start Date: 15/Sep/26 07:38
Worklog Time Spent: 10m
Work Description: lukaszlenart opened a new pull request, #1944:
URL: https://github.com/apache/struts/pull/1944
Fixes [WW-5745](https://issues.apache.org/jira/browse/WW-5745)
## Problem
When a property refers to an object by `@JsonIdentityInfo` id before that
object has appeared in the body, Jackson defers the assignment:
`ObjectIdReferenceProperty` registers a referring on the id and, once the
object is deserialized, assigns it through the property's `set()` from wherever
in the body the object turned up. `AuthorizingSettableBeanProperty` authorized
that write with `pathFor(memberName)` against the path prefix and dynamic-key
scope current *at that moment* — the target object's location, not the
referring property's. The property had already been authorized under its own
path when it was read, so the second check could only reject: a correctly
granted forward reference across nesting depths (`people[0].friend` → `boss`,
checked as `boss.friend`), or one resolved inside an `allowDynamicKeys`
subtree, was dropped with a WARN naming the target's path.
Surfaced by the WW-5727 reviews; pre-existing and independent of that fix.
## Change
- `AuthorizingValueDeserializer` catches the `UnresolvedForwardReference`
after the property has been authorized and, before rethrowing, records the
verdict in the new `AuthorizedForwardReferences` (thread-local) against the
awaited id and the member name.
- `AuthorizingSettableBeanProperty.set`/`setAndReturn` find that entry by
the object the id resolved to — the one they receive — and skip the second
check. The deferred write is the read completing, not a new assignment to
authorize. Keying by the id rather than the referring bean also covers a
creator-bound referrer, which is not constructed yet when the reference is read.
- `ParameterAuthorizingModule.clearAuthorizationContext()` clears the
entries with the dynamic-key state; `ContentTypeInterceptor` now calls the new
static `clearRequestState()` when it unbinds the context as well, so a
third-party handler that registers the module without clearing cannot leave
verdicts on the thread.
Not affected: collection/map element forward references (resolved inside
their own deserializers, never reach the property wrapper); a custom
`ObjectIdResolver` that does not hand back the bound object leaves the write on
today's check (fail-closed, documented on the class).
Two earlier shapes were rejected in review: re-authorizing under a recorded
*path* still used the bind-time dynamic-key scope, and a `Referring` registered
on the id duplicated every unresolved id in Jackson's error report; keying by
`JsonParser.currentValue()` mis-attributed to the parent bean for a
creator-bound referrer in one ordering.
## Security review
Two independent passes over the final mechanism, both clean: every `set()`
of a bean value is preceded by the read-time gate under the property's own
path, so the skip only removes the redundant second check and a stale entry can
never grant what the read denied.
## Tests
`ParameterAuthorizingModuleTest`: nested referrer → root target resolves
under its own path; referrer not granted at its own path stays null;
creator-bound referrer; target resolved inside an any-setter dynamic-key scope;
no-context pass-through; request-boundary clear.
`ContentTypeInterceptorIntegrationTest`: the interceptor clears state a handler
left behind.
`mvn test -DskipAssembly -pl plugins/rest`: 199 tests, 0 failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Issue Time Tracking
-------------------
Worklog Id: (was: 1041580)
Remaining Estimate: 0h
Time Spent: 10m
> REST plugin authorizes a forward-referenced object-id property at the depth
> where the reference resolves
> --------------------------------------------------------------------------------------------------------
>
> Key: WW-5745
> URL: https://issues.apache.org/jira/browse/WW-5745
> Project: Struts 2
> Issue Type: Bug
> Components: Plugin - REST
> Reporter: Lukasz Lenart
> Assignee: Lukasz Lenart
> Priority: Minor
> Fix For: 7.4.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> h2. Summary
> When a property refers to an object by {{@JsonIdentityInfo}} id before that
> object has appeared in the body, Jackson defers the assignment:
> {{ObjectIdReferenceProperty}} registers a {{PropertyReferring}} and, once the
> referenced object is deserialized, calls the referring property's {{set()}}
> from {{handleResolvedForwardReference}}. That call happens wherever the
> referenced object turns up in the document, which can be at a different
> nesting depth than the referring property.
> {{AuthorizingSettableBeanProperty.set()}} authorizes with
> {{ParameterAuthorizationContext.pathFor(memberName)}}, i.e. the member name
> appended to whatever path prefix is on the stack _at the time of the call_.
> For a deferred assignment that prefix belongs to the object being
> deserialized when the reference resolves, not to the bean that owns the
> referring property, so the path checked is wrong.
> Surfaced by the WW-5727 reviews; pre-existing and independent of that fix.
> h2. Current behaviour
> The mis-computed path can only add a rejection (the wrong prefix is unlikely
> to be granted), so this fails closed: a correctly annotated forward reference
> may be dropped with a WARN naming a path the developer never wrote. The
> first, non-deferred read of the referring property is authorized at the
> correct path through {{AuthorizingValueDeserializer}}, so no unauthorized
> value is assigned.
> h2. Proposed change
> Capture the path prefix when the referring property is first read and use it
> when the deferred {{set()}} runs — e.g. wrap the {{Referring}} Jackson
> registers, or record the prefix on the wrapper before the reference is
> deferred. Add a test with two identified objects where the reference appears
> before its target at a different depth, asserting the referring property
> binds under its own path when granted and is rejected when not.
> h2. Compatibility notes
> No configuration or API change. Only forward references across nesting depths
> are affected, and only in the direction of a spurious rejection.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)