You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "Lukasz Lenart (Jira)" <ji...@apache.org> on 2026/08/31 18:36:00 UTC

[jira] [Created] (WW-5712) ParameterAuthorizingModule does not wrap the Jackson any-setter in the REST plugin

Lukasz Lenart created WW-5712:
---------------------------------

             Summary: ParameterAuthorizingModule does not wrap the Jackson any-setter in the REST plugin
                 Key: WW-5712
                 URL: https://issues.apache.org/jira/browse/WW-5712
             Project: Struts 2
          Issue Type: Bug
            Reporter: Lukasz Lenart
             Fix For: 7.4.0


{{ParameterAuthorizingModule.updateBuilder}} wraps the properties returned by {{BeanDeserializerBuilder.getProperties()}} with {{AuthorizingSettableBeanProperty}}, but it never consults {{BeanDeserializerBuilder.getAnySetter()}}. The {{SettableAnyProperty}} is therefore left unwrapped, so unknown keys dispatched to a Jackson {{@JsonAnySetter}} are set without passing through the {{@StrutsParameter}} authorization context — while an ordinary unannotated setter on the same class, in the same request body, is correctly rejected.

All three any-setter forms are affected (method, field and {{@JsonCreator}} parameter). Both {{JacksonJsonHandler}} and {{JacksonXmlHandler}} register the module, so JSON and XML bodies behave the same. {{@JsonUnwrapped}} is not affected, and an any-setter beneath a rejected parent is already skipped through {{skipChildren()}}.

The obvious fix does not work: path-based authorization resolves a parameter's root name against declared members of the target, so {{pathFor(key)}} matches nothing for a dynamic key by construction. Routing any-setter keys through the existing check would reject every key and break every existing {{@JsonAnySetter}} user. Consent has to be expressed at the sink rather than at the key.

Proposed shape:
* A new annotation member, {{@StrutsParameter(allowDynamicKeys = true)}}, marking one any-setter as permitted to receive arbitrary keys. A plain {{@StrutsParameter}} is deliberately not sufficient — arbitrary-key access should have to be typed out, not granted by accident.
* Enforcement behind a plugin-local constant, {{struts.rest.anySetter.requireAnnotations}}, defaulting to {{false}}, so nothing changes for existing applications until they opt in. Same shape as {{struts.chaining.requireAnnotations}}; the default can be revisited in a major release.
* {{depth()}} keeps its current meaning, counted beneath the dynamic key. The default {{depth = 0}} accepts a scalar value under any key and rejects a nested object under it; {{depth = 1}} permits one level of nesting. That is the rule an annotated {{Map}} property already follows.
* {{@Target}} stays {{METHOD, FIELD}}. A {{@JsonCreator}}-parameter any-setter has nowhere to carry the marker and is rejected with a warning when enforcement is on. Narrowing that rare form now is preferable to advertising an annotation placement the framework does not honour elsewhere, and {{@Target}} can be widened later but never narrowed.
* The wrapper mirrors {{AuthorizingSettableBeanProperty}}: delegate untouched when the authorization context is inactive; on rejection log a warning, mark the context redacted and call {{skipChildren()}} so nested graphs are never constructed.

Test coverage should include default-off compatibility, the method and field forms, missing and explicit consent, depth 0/1/2, creator parameters, unauthorized parents, {{@JsonUnwrapped}}, both the JSON and XML handlers, and context cleanup.

Documentation follow-up: the {{@StrutsParameter}} page states that the JSON and REST plugins authorize each property during deserialization "so that unauthorized fields are never set". That is not accurate as written — correct the wording and document the any-setter behaviour explicitly.

Reported by Darren Carreras (GitHub: carrerasdarren-cell), who has a patch implementing the above and will open the pull request.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)