Lukasz Lenart created WW-5662:
---------------------------------
Summary: Core tests run with the OGNL allowlist disabled, hiding a
class of regression from CI
Key: WW-5662
URL: https://issues.apache.org/jira/browse/WW-5662
Project: Struts 2
Issue Type: Improvement
Reporter: Lukasz Lenart
Fix For: 7.3.0
h3. Problem
{{struts.allowlist.enable}} ships as {{true}}
({{core/src/main/resources/org/apache/struts2/default.properties:261}}), but
every test that
boots a {{Dispatcher}} through the shared helper gets it forced to {{false}}:
{code:java}
// StrutsTestCaseHelper.java:41-44
public static Dispatcher initDispatcher(ServletContext ctx, Map<String, String>
params) {
Map<String, String> finalParams = params != null ? new HashMap<>(params) :
new HashMap<>();
finalParams.putIfAbsent(STRUTS_ALLOWLIST_ENABLE, "false");
...
}
{code}
The result is that the core suite - 3104 tests - validates the framework under
a configuration
that no production deployment uses. Exactly two test classes in the whole
repository opt back
in: {{OgnlUtilTest}} and {{LazyParamsAllowlistTest}}.
Any framework code path that writes to an object via OGNL is therefore untested
against the
allowlist. If the target class is not allowlisted, the write is blocked at
runtime and no core
test can observe it.
h3. Concrete incident
WW-5659 moved lazily resolved interceptor params off the shared interceptor
singleton and into
a per-invocation holder ({{UploadPolicy}}). The old write target - the
interceptor - is
allowlisted at configuration time via
{{XmlDocConfigurationProvider.verifyInterceptor}}; the
new holder was registered nowhere.
Consequences under the shipped default:
* {{SecurityMemberAccess}} blocked the setter
* {{OgnlUtil}} threw {{ReflectionException}}
* the fail-closed path marked the policy unusable
* *every file upload was rejected*
The full core suite passed - 3104 tests, zero failures - because the allowlist
was off. The
break was caught by {{it.org.apache.struts2.showcase.DynamicFileUploadTest}} (4
of 7 tests
failing), after it had already failed every "Build and Test" job on the pull
request. The
showcase integration tests were the only thing standing between this and a
release.
h3. Why the default is off, and why that is not simply reversible
Turning the flag on for the existing suite would require allowlisting every
test fixture class
reachable from an OGNL expression - {{TestBean}}, {{TestBean2}} and many
others. That is
presumably why it was disabled wholesale in the first place. A naive flip would
produce a large
volume of unrelated failures, so this needs a deliberate approach rather than a
one-line change.
h3. Options
Worth weighing during design; not a settled decision.
# *A dedicated allowlist-enabled slice.* Keep the default off, and add a test
base class (or
surefire execution) that boots with the allowlist enabled, used by any test
covering a code
path that writes to a framework-internal object via OGNL. Cheapest, and
matches what
{{LazyParamsAllowlistTest}} already does by hand.
# *Flip the default in {{StrutsTestCaseHelper}} and fix the fallout.* Highest
value - it makes
the whole suite exercise the shipped configuration - and the largest effort.
Could be staged
package by package.
# *Treat the showcase integration tests as the canary and extend them.* Weakest
option: it
catches breakage late, and only for features the showcase happens to
demonstrate.
Option 1 plus a documented convention ("if your change writes via OGNL to a
framework class,
add an allowlist-enabled test") would have caught the WW-5659 regression at the
point it was
introduced.
h3. Non-goals
* Not a change to the shipped {{struts.allowlist.enable}} default, which is
already {{true}}
and correct.
* Not a rewrite of the allowlist mechanism itself.
h3. References
* {{StrutsTestCaseHelper.java:41-44}} - where the flag is forced off
* {{core/src/main/resources/org/apache/struts2/default.properties:261}} - the
shipped default
*
{{core/src/test/java/org/apache/struts2/interceptor/LazyParamsAllowlistTest.java}}
- the
pattern a slice could generalise
* WW-5659 - the regression that motivated this issue
--
This message was sent by Atlassian Jira
(v8.20.10#820010)