Skip to content

WW-5697 Restrict the indexed-access fast path in XWorkMethodAccessor to real indexed properties - #1871

Open
lukaszlenart wants to merge 3 commits into
mainfrom
feature/WW-5697-indexed-access-fast-path
Open

WW-5697 Restrict the indexed-access fast path in XWorkMethodAccessor to real indexed properties#1871
lukaszlenart wants to merge 3 commits into
mainfrom
feature/WW-5697-indexed-access-fast-path

Conversation

@lukaszlenart

Copy link
Copy Markdown
Member

Fixes WW-5697

Problem

XWorkMethodAccessor.callMethod(...) skipped the denyMethodExecution check for any method whose name began with get and took one argument, or set and took two:

//HACK - we pass indexed method access i.e. setXXX(A,B) pattern
if ((objects.length == 2 && string.startsWith("set")) || (objects.length == 1 && string.startsWith("get"))) {

That is a name prefix plus an argument count, not a property check. An ordinary method such as getSomething(String) is not a JavaBeans property, but it matches, so it was executed during parameter binding with the argument taken from the parameter name — a parameter name of getSomething('value').property calls getSomething("value").

The flag the branch consults, DENY_INDEXED_ACCESS_EXECUTION, is never written anywhere in main source, so exec is always null and the fast path is unconditional.

Change

The fast path now applies only where the target type genuinely declares an indexed property accessor, determined with OgnlRuntime.getIndexedPropertyType(...). Everything else falls through to the existing denyMethodExecution check.

Note the check is keyed on the property name while callMethod receives the method name, hence the prefix strip and Introspector.decapitalize.

DENY_INDEXED_ACCESS_EXECUTION is public API, so it is deprecated here rather than deleted; removal in 8.0.0 is tracked as WW-5699.

Scope of the behaviour change

Confined to parameter binding. The fast path only matters when the deny flag is set, and that flag is set only by ParametersInterceptor, AliasInterceptor and StaticParametersInterceptor — with it unset, such a call already fell through to the check below and executed. JSP and tag rendering are unaffected.

Both kinds of indexed accessor keep working. Worth knowing for review: a classic getItem(int) / setItem(int, String) pair reports as INDEXED_PROPERTY_OBJECT, not INDEXED_PROPERTY_INT, so the predicate has to be != INDEXED_PROPERTY_NONE — an INT-only rule would break the very case the original hack exists to serve.

Tests

XWorkMethodAccessorTest is new and covers four behaviours:

  • an argument-taking getter that is not an indexed property is not executed while method execution is denied (this failed before the change)
  • an int-indexed accessor still executes while denied
  • an object-indexed accessor still executes while denied
  • with the deny flag unset, an argument-taking getter still executes, as before

The two indexed-property tests were mutation-checked: forcing the new predicate to always reject fails exactly those two, so they are not passing vacuously.

Full core suite green: 3201 tests, 0 failures, 0 errors.

Related

WW-5698 covers a separate issue found alongside this one — the ModelDriven exemption in StrutsParameterAuthorizer also exempting the action's own members. Different cause, different fix, not addressed here. An end-to-end ModelDriven binding test was deliberately left out of this PR because it would couple these tests to the exemption WW-5698 is expected to change.

🤖 Generated with Claude Code

lukaszlenart and others added 3 commits August 27, 2026 07:14
…xed properties

XWorkMethodAccessor.callMethod skipped the denyMethodExecution check for any
method whose name began with "get" and took one argument, or "set" and took two.
That test is a name prefix plus an argument count, not a property check, so an
ordinary method such as getSomething(String) qualified and was executed during
parameter binding with the argument supplied in the parameter name.

The fast path now applies only where the target type genuinely declares an
indexed property accessor, determined with OgnlRuntime.getIndexedPropertyType.
Anything else falls through to the existing denyMethodExecution check.

Both int-indexed and object-indexed accessors continue to work. The new tests
cover those two, the argument-taking method that must now be blocked while
method execution is denied, and the unset-flag path where methods still execute
as before, so the change is confined to parameter binding.

DENY_INDEXED_ACCESS_EXECUTION is left in place for now; it is public API and is
never set anywhere, so its removal is handled separately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing in the framework has ever written this key, so the check it guarded in
XWorkMethodAccessor never fired. Now that indexed property access is identified
from the target type rather than from a method name prefix, the flag has nothing
left to guard.

It is public API, so it is deprecated here rather than deleted, and removal is
tracked for 8.0.0 in WW-5699.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merge the nested indexed-property check into the enclosing condition (S1066)
and give the deprecation its since/forRemoval arguments (S6355).

Also cover the branch that rejects a method with nothing left after the "get"
prefix, using a map style get(String) accessor. That is worth asserting in its
own right: such a method is not an indexed property accessor, so it must not be
executed while method execution is denied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant