Lukasz Lenart created WW-5725:
---------------------------------
Summary: AuthorizingSettableBeanProperty does not authorize the
buffered set() path in the REST plugin
Key: WW-5725
URL: https://issues.apache.org/jira/browse/WW-5725
Project: Struts 2
Issue Type: Bug
Reporter: Lukasz Lenart
Fix For: 7.4.0
h2. Summary
{{AuthorizingSettableBeanProperty}} authorizes a property in
{{deserializeAndSet}} and {{deserializeSetAndReturn}}, and wraps the value
deserializer for creator-bound properties. It does not override {{set(Object,
Object)}} or {{setAndReturn(Object, Object)}}, which is the path Jackson takes
for a non-creator property it has buffered during property-based creation. That
property is then assigned without an authorization check.
h2. Current behaviour
On a type that mixes a property-based creator ({{@JsonCreator}} constructor or
a record) with an ordinary setter, jackson-databind buffers a setter property
that appears in the JSON before the last creator parameter, constructs the
instance, and assigns the buffered value through
{{PropertyValue.Regular.assign}} → {{SettableBeanProperty.set()}}.
{{SettableBeanProperty.Delegating.set()}} forwards straight to the delegate, so
the authorization in {{AuthorizingSettableBeanProperty}} never runs for it.
{{withValueDeserializer}} is scoped to {{CreatorProperty}}, so the setter
property keeps its plain value deserializer, and
{{SettableBeanProperty.deserialize}} is {{final}} and cannot be intercepted.
The same property is rejected when it appears after the last creator parameter
(direct {{deserializeAndSet}} path), and on a setter-only type with the same
payload. The order of members in the request body alone decides whether the
check applies. Nothing is logged when the buffered assignment goes through.
Applies to JSON and XML bodies alike, since {{JacksonXmlHandler}} registers the
same module. 6.x is unaffected: the REST plugin there has no Jackson
authorization module.
h2. Proposed change
Override {{set(Object, Object)}} and {{setAndReturn(Object, Object)}} in
{{AuthorizingSettableBeanProperty}} and apply the same authorization used by
{{deserializeAndSet}}, dropping the value and logging the rejection the same
way. That closes the buffered path with no new configuration: the guard already
rejects the identical property in the other member order, so no legitimate
behaviour depends on the gap.
Add tests covering a creator-plus-setter type with the unauthorized setter
before and after the last creator parameter, top-level and nested, for both
handlers.
h2. Compatibility notes
No configuration or API change. A request that previously had an unauthorized
property assigned only because of its position in the body now has it dropped,
consistent with every other position.
Reported by 0xCc.zhang.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)