Gouri Sankar A created WW-5844:
----------------------------------

             Summary: HttpMethodInterceptor fails open for the implicit 
execute() method; restDefaultStack / beanValidationDefaultStack omit httpMethod 
entirely
                 Key: WW-5844
                 URL: https://issues.apache.org/jira/browse/WW-5844
             Project: Struts 2
          Issue Type: Bug
          Components: Core Interceptors
    Affects Versions: 7.4.0, 7.3.0, 7.0.0, 6.12.0
            Reporter: Gouri Sankar A


Two compounding gaps in the @HttpGet/@HttpPost verb-restriction control:

(a) HttpMethodInterceptor misses an @Http* annotation in four distinct, 
independent ways:
  - A method-level annotation on the implicit "execute" method: the 
method-level check only runs when proxy.isMethodSpecified() is true, which is 
false for an action invoked without an explicit method= -- so @HttpPost placed 
directly on execute() is never read for that case. (The separate, unconditional 
class-level check still runs regardless of isMethodSpecified(), so a 
class-level annotation on the same action is still enforced; this is narrower 
than it may first appear.)
  - A class-level annotation on a base class is not enforced on a subclass that 
doesn't repeat it, and a method-level annotation is lost the same way when a 
subclass overrides the annotated method without repeating the annotation -- 
plain Java annotation semantics, since none of the Http* annotations is 
@Inherited. This happens independently of isMethodSpecified(), including with 
an explicit method= configured.
  - The same loss happens one level further out: an annotation declared on an 
interface (a default method, or a class-level annotation on the interface 
itself) is not found by an action class that only implements that interface 
through an intermediate superclass, rather than directly.
  Any of the four reaching an unguarded action means any HTTP verb reaches it.

(b) restDefaultStack (plugins/rest) and beanValidationDefaultStack 
(plugins/bean-validation) are the only two bundled interceptor stacks anywhere 
in core or any plugin that carry params but omit httpMethod entirely -- every 
application extending rest-default or struts-bean-validation gets no verb 
rejection at all, regardless of annotations (RestActionMapper does read the 
verb to choose which method to route to, but nothing is ever rejected for using 
the "wrong" one). Every bundled stack in core and every plugin was enumerated 
to confirm this is exactly two gaps, not a wider pattern.

Prevalence: apps/showcase has 156 <action> tags and only 54 use an explicit 
method=, so roughly two-thirds rely on the implicit default -- gap (a) is 
realistic wherever a developer adds @HttpPost to an execute()-mapped action as 
defence-in-depth rather than naming the method.

Live-verified on a throwaway Struts Boot app, loopback only: two action shapes 
(implicit execute(), named method) crossed with two package types 
(rest-default-, bean-validation-derived) = 4 combinations. Before the patch, 
GET reached the action and ran it in all 4 cases (should have been rejected by 
@HttpPost in each). After, all 4 GETs returned 405 and the action never ran; 
POST was unaffected as a control.

Proposal:
- HttpMethodInterceptor always resolves the invoked method, including the 
implicit execute() case, and walks the full class/superclass/interface 
hierarchy for the nearest annotation at both the method and class level, 
checking every level's own implemented interfaces (not only the leaf class's) 
-- Class#getInterfaces() only returns interfaces a class declares itself, not 
ones a superclass further up implements. Mirrors the existing 
AnnotationUtils.findAnnotation walk shape used elsewhere in the convention 
plugin.
- httpMethod added to restDefaultStack and beanValidationDefaultStack.
- A new, generic AccStackInvariantsTest (core) walks every stack definition in 
struts-default.xml and asserts any stack carrying params also carries 
httpMethod -- a durable regression guard against a third stack developing the 
same gap.

Tests: full suites pass with the patch applied -- core 3749/0 failures (2 
skipped), rest 245/0, bean-validation 25/0, convention 94/0, json 177/0 -- 
including the existing HttpMethodInterceptorTest and the WW-5718 stack-ordering 
pins (RestDefaultStackTest/BeanValidationDefaultStackTest), both unaffected.

Affected versions: both gaps present, same code pattern, by source inspection, 
in the 6.12.0, 7.0.0, 7.3.0 and 7.4.0 tags.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to