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)

Reply via email to