Lukasz Lenart created WW-5761:
---------------------------------
Summary: Enforce @StrutsParameter on the member OGNL resolves
during parameter binding
Key: WW-5761
URL: https://issues.apache.org/jira/browse/WW-5761
Project: Struts 2
Issue Type: Improvement
Components: Core
Reporter: Lukasz Lenart
Fix For: 8.0.0
{{@StrutsParameter}} is enforced once, before OGNL runs:
{{StrutsParameterAuthorizer}} takes the parameter name and predicts which
accessor or field OGNL will go through, then checks that member for the
annotation. {{SecurityMemberAccess}}, which OGNL consults for every member it
actually touches, does not know about the annotation at all.
Every time OGNL's resolution rules and the prediction drift apart, the
authorizer has to be taught again:
* WW-5709: fluent (non-void) setters, which {{java.beans}} does not treat as
write methods but OGNL binds through
* WW-5759: OGNL 3.4.14's JavaBeans-style accessor names ({{setuRange}} before
{{setURange}}), and getters whose {{java.beans}} property name differs from the
name OGNL reaches them by ({{getURL()}})
The prediction is a hand-written copy of OGNL internals ({{accessorBaseNames}},
set/is/get order, overload choice), so the next OGNL change to name resolution
needs the same follow-up.
h3. Proposal
Enforce the annotation where OGNL resolves the member, during parameter binding
only.
Binding already runs on its own value stack
({{ParametersInterceptor.toNewStack}}). Its {{SecurityMemberAccess}} already
receives binding-only settings ({{useAcceptProperties}} /
{{useExcludeProperties}} via {{MemberAccessValueStack}}). A binding mode on
that instance could require {{@StrutsParameter}} on the actual
{{Method}}/{{Field}} OGNL is about to use on the action, whatever name it was
reached by. The authorizer's prediction would remain a fast pre-check and would
no longer be the only gate.
h3. Open design questions
* *Depth*: {{isAccessible}} sees one member at a time, not its position in the
expression. The required {{depth}} of the root getter is known only to the
caller, so it has to be tracked per binding (e.g. the authorizer records the
authorized root and depth in the binding context).
* *ModelDriven*: model members are exempt, so {{SecurityMemberAccess}} needs to
know which object is the model, by identity, as
{{StrutsParameterAuthorizer.resolveTarget}} already does.
* *Paths that never call {{isAccessible}}*: Map-backed models and custom
{{PropertyAccessor}}s keep relying on the authorizer.
* *Transition mode, {{ParameterNameAware}}, the JSON/REST deserialization
paths* (WW-5624) and {{CookieInterceptor}} (WW-5627) share
{{ParameterAuthorizer}} and need a consistent story.
* *Cost*: an annotation lookup per member access during binding; cacheable per
{{Member}}.
Fits 8.0.0 together with the other {{SecurityMemberAccess}} changes (WW-5678)
and the OGNL 3.5 upgrade (WW-5326).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)