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)