diff --git a/core/src/main/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptor.java index c0afca1c31..4d033d338d 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptor.java @@ -90,7 +90,8 @@ public String intercept(ActionInvocation invocation) throws Exception { 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()); diff --git a/core/src/test/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptorTest.java index f68b01df3f..edbf565542 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/httpmethod/HttpMethodInterceptorTest.java @@ -19,13 +19,17 @@ package org.apache.struts2.interceptor.httpmethod; import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionProxy; import com.opensymphony.xwork2.mock.MockActionInvocation; import com.opensymphony.xwork2.mock.MockActionProxy; import org.apache.struts2.HttpMethodsTestAction; import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.TestAction; +import org.apache.struts2.config.StrutsXmlConfigurationProvider; import org.springframework.mock.web.MockHttpServletRequest; +import java.util.Map; + public class HttpMethodInterceptorTest extends StrutsInternalTestCase { private HttpMethodInterceptor interceptor; @@ -254,6 +258,73 @@ public void testWildcardResolvedMethodWithPostAnnotationAllowsPost() throws Exce assertEquals(HttpMethod.POST, action.getHttpMethod()); } + /** + * Regression for wildcard-resolved methods with no method-level HTTP annotation: + * a class-level {@code @AllowedHttpMethod(POST)} must still cause GET to be rejected. + * Previously the interceptor's {@code if/else-if} structure made the class-level + * branch unreachable when {@code isMethodSpecified()=true} and the resolved method + * carried no annotation of its own. + */ + public void testWildcardResolvedUnannotatedMethodRespectsClassLevelAnnotation() throws Exception { + HttpMethodsTestAction action = new HttpMethodsTestAction(); + prepareActionInvocation(action); + actionProxy.setMethod("execute"); + actionProxy.setMethodSpecified(true); + + prepareRequest("get"); + + String resultName = interceptor.intercept(invocation); + + assertEquals("bad-request", resultName); + } + + /** + * Counterpart to the above: POST against a wildcard-resolved unannotated method must succeed + * when the class allows POST via {@code @AllowedHttpMethod(POST)}. + */ + public void testWildcardResolvedUnannotatedMethodAllowsPostWithClassLevelAnnotation() throws Exception { + HttpMethodsTestAction action = new HttpMethodsTestAction(); + prepareActionInvocation(action); + actionProxy.setMethod("execute"); + actionProxy.setMethodSpecified(true); + invocation.setResultCode("success"); + + prepareRequest("post"); + + String resultName = interceptor.intercept(invocation); + + assertEquals("success", resultName); + } + + /** + * Exercises the full wildcard resolution path through a real {@link com.opensymphony.xwork2.DefaultActionProxy}. + *

+ * Config (from xwork-test-allowed-methods.xml): + * {@code }. + * URL {@code Wild-execute} resolves to {@code ActionSupport.execute()} — no method-level + * HTTP annotation. {@code HttpMethodsTestAction} carries class-level + * {@code @AllowedHttpMethod(POST)}, so GET must be rejected end-to-end. + */ + public void testWildcardResolvedExecuteRejectsGetThroughRealProxy() throws Exception { + loadConfigurationProviders(new StrutsXmlConfigurationProvider( + "com/opensymphony/xwork2/config/providers/xwork-test-allowed-methods.xml")); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/Wild-execute"); + Map extraContext = ActionContext.of() + .withServletRequest(request) + .getContextMap(); + + ActionProxy proxy = actionProxyFactory.createActionProxy("", "Wild-execute", null, extraContext); + + assertEquals("execute", proxy.getMethod()); + assertTrue("Wildcard-resolved method must report isMethodSpecified()=true", proxy.isMethodSpecified()); + + HttpMethodInterceptor realInterceptor = new HttpMethodInterceptor(); + String result = realInterceptor.intercept(proxy.getInvocation()); + + assertEquals("bad-request", result); + } + private void prepareActionInvocation(Object action) { interceptor = new HttpMethodInterceptor(); invocation = new MockActionInvocation();