fix(core): enforce class-level HTTP method annotations for wildcard-resolved unannotated methods (#1690)

The WW-5535 fix (commit 4d2eb93) corrected isMethodSpecified() for wildcard-resolved
methods but introduced a structural gap in HttpMethodInterceptor.intercept().

The if/else-if structure made the class-level annotation check unreachable whenever
isMethodSpecified()=true and the resolved method carries no method-level annotation:

  if (isMethodSpecified()) {
      if (isAnnotatedBy(method)) { ... }
      // falls through silently
  } else if (isAnnotatedBy(class)) { ... }  // never reached
  return invocation.invoke();               // no enforcement

Fix: convert else-if to standalone if so the class-level check is always evaluated
as a fallback when the method itself has no annotation. Method-level annotations
still take precedence (checked first).

Add two regression tests covering the wildcard-resolved unannotated method scenario.

Co-authored-by: g0w6y <g0w6y@users.noreply.github.com>
This commit is contained in:
ⳕⲛτⲉⲅⲥⲉⳏτⲟⲅ 🕵🏻
2026-05-19 11:35:21 +05:30
committed by GitHub
parent 7ea7911cf8
commit 213b83f64f
2 changed files with 47 additions and 1 deletions
@@ -90,7 +90,8 @@ public class HttpMethodInterceptor extends AbstractInterceptor {
invocation.getProxy().getMethod(), AllowedHttpMethod.class.getSimpleName(), request.getMethod());
return doIntercept(invocation, method);
}
} else if (AnnotationUtils.isAnnotatedBy(action.getClass(), HTTP_METHOD_ANNOTATIONS)) {
}
if (AnnotationUtils.isAnnotatedBy(action.getClass(), HTTP_METHOD_ANNOTATIONS)) {
LOG.debug("Action: {} annotated with: {}, checking if request: {} meets allowed methods!",
action, AllowedHttpMethod.class.getSimpleName(), request.getMethod());
return doIntercept(invocation, action.getClass());
@@ -273,6 +273,51 @@ public class HttpMethodInterceptorTest extends StrutsInternalTestCase {
invocation.setProxy(actionProxy);
}
/**
* Regression: wildcard-resolved method with NO method-level annotation on a class
* that has a class-level @AllowedHttpMethod(POST) — GET must be rejected.
* The WW-5535 fix introduced an if/else-if that made the class-level check
* unreachable when isMethodSpecified()=true and the method is unannotated.
*/
public void testWildcardResolvedUnannotatedMethodRespectsClassLevelAnnotation() throws Exception {
// given — HttpMethodsTestAction has @AllowedHttpMethod(POST) at class level
// execute() inherited from ActionSupport has no method-level HTTP annotation
HttpMethodsTestAction action = new HttpMethodsTestAction();
prepareActionInvocation(action);
actionProxy.setMethod("execute");
actionProxy.setMethodSpecified(true); // simulates wildcard-resolved, not default
prepareRequest("get");
// when
String resultName = interceptor.intercept(invocation);
// then — class-level @AllowedHttpMethod(POST) must still be enforced
assertEquals("bad-request", resultName);
}
/**
* Counterpart: POST on wildcard-resolved unannotated method must succeed
* when the class allows POST via class-level annotation.
*/
public void testWildcardResolvedUnannotatedMethodAllowsPostWithClassLevelAnnotation() throws Exception {
// given
HttpMethodsTestAction action = new HttpMethodsTestAction();
prepareActionInvocation(action);
actionProxy.setMethod("execute");
actionProxy.setMethodSpecified(true);
invocation.setResultCode("success");
prepareRequest("post");
// when
String resultName = interceptor.intercept(invocation);
// then
assertEquals("success", resultName);
}
private void prepareRequest(String httpMethod) {
MockHttpServletRequest request = new MockHttpServletRequest(httpMethod, "/action");
ActionContext.getContext().withServletRequest(request);