Niklas Neesen created WW-5771:
---------------------------------

             Summary: StrutsParameterAuthorizer only matches naively 
capitalized setters, rejecting annotated JavaBeans-compliant setters like 
setuRange
                 Key: WW-5771
                 URL: https://issues.apache.org/jira/browse/WW-5771
             Project: Struts 2
          Issue Type: Bug
          Components: Core Interceptors
    Affects Versions: 7.4.0
            Reporter: Niklas Neesen


Since 7.4.0, {{StrutsParameterAuthorizer.findBindableAccessor}} resolves the 
setter for a depth-0 parameter by building the name itself:

{code:java}
String setterName = "set" + Character.toUpperCase(property.charAt(0)) + 
property.substring(1);
{code}

For a property whose name starts with a lowercase letter followed by an 
uppercase letter (e.g. {{eMail}}), this only finds the naively capitalized 
{{setEMail}}. Per the JavaBeans specification (the inverse of 
{{Introspector.decapitalize}}), the accessor for property {{eMail}} is 
{{seteMail}} — which is what 7.3.0 found via 
{{PropertyDescriptor#getWriteMethod}} and what developers annotated with 
{{@StrutsParameter}}.

The result: an action with a correctly annotated, spec-compliant setter

{code:java}
private String eMail;

@StrutsParameter
public void seteMail(String eMail) { this.eMail = eMail; }
{code}

passes authorization on 7.3.0 but is rejected on 7.4.0 — the parameter is 
silently dropped (in production mode nothing is logged above debug level), the 
field stays null, and the regression surfaces only as downstream application 
errors.

The Javadoc on {{findBindableAccessor}} says the setter is "matched the way 
OGNL matches it". That was true for OGNL 3.4.0-3.4.13, which had exactly this 
naive-capitalization bug — but it was fixed in OGNL 3.4.14 
([https://github.com/orphan-oss/ognl/issues/643], 
[https://github.com/orphan-oss/ognl/pull/644]): OGNL now resolves both base 
names, spec-compliant first. So on current Struts 7.4.0 + OGNL 3.4.14+, the 
authorizer and the binder it guards disagree in both directions:

* The authorizer inspects {{setEMail}} (and requires the annotation there), 
while OGNL binds through {{seteMail}}.
* An annotation on the spec-compliant setter — the method OGNL actually invokes 
— is invisible to the authorizer.

h3. Standalone reproducer

Only struts2-core and ognl on the classpath:

{code:java}
public class Repro {
    public static class SpecCompliantAction {
        private String eMail;
        @StrutsParameter
        public void seteMail(String v) { this.eMail = v; }
    }

    public static void main(String[] args) {
        StrutsParameterAuthorizer auth = new StrutsParameterAuthorizer();
        auth.setRequireAnnotations("true");
        auth.setOgnlUtil(/* OgnlUtil with default caches */);
        auth.setProxyService(/* no-op ProxyService */);

        SpecCompliantAction a = new SpecCompliantAction();
        // 7.3.0: true — 7.4.0: false
        System.out.println(auth.isAuthorized("eMail", a, a));
    }
}
{code}

Observed matrix:

|| ||annotated {{seteMail}} only||annotated {{seteMail}} + annotated alias 
{{setEMail}}||
||7.3.0|authorized|authorized|
||7.4.0|*rejected*|authorized|

h3. Suggested fix

Derive the candidate base names the same way OGNL >= 3.4.14 does 
({{OgnlRuntime.accessorBaseNames}}): for a lowercase-then-uppercase property 
name, look up both {{set<property>}} and {{set<Capitalized property>}}, 
spec-compliant name first, and accept an annotation on whichever method 
qualifies. The same applies to the getter lookup for nested parameters if it 
ever moves away from {{PropertyDescriptor}}s.

Found while upgrading 7.3.0 → 7.4.0: parameters bound to properties of this 
naming pattern were silently dropped despite annotated, spec-compliant setters, 
and only annotating a naively capitalized alias setter restores them.




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

Reply via email to