Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.struts2.interceptor;

import org.apache.struts2.ActionInvocation;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.interceptor.AbstractInterceptor;
import org.apache.struts2.interceptor.PreResultListener;
import org.apache.struts2.util.TextParseUtil;
Expand Down Expand Up @@ -58,7 +59,7 @@ public String intercept(ActionInvocation invocation) throws Exception {
@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
HttpServletRequest req = invocation.getInvocationContext().getServletRequest();
final String path = req.getContextPath();
final String path = RequestUtils.getUri(req);

if (exemptedPaths.contains(path)) {
// no need to add headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.struts2.interceptor;

import org.apache.struts2.ActionInvocation;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.interceptor.AbstractInterceptor;
import org.apache.struts2.interceptor.PreResultListener;
import org.apache.struts2.util.TextParseUtil;
Expand Down Expand Up @@ -60,7 +61,7 @@ public String intercept(ActionInvocation invocation) throws Exception {
@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
String path = request.getContextPath();
String path = RequestUtils.getUri(request);

if (isExempted(path)) {
// no need to add headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.interceptor.AbstractInterceptor;
import org.apache.struts2.util.TextParseUtil;
Expand Down Expand Up @@ -67,9 +68,9 @@ public String intercept(ActionInvocation invocation) throws Exception {

addVaryHeaders(invocation);

String contextPath = request.getContextPath();
String path = RequestUtils.getUri(request);
// Apply exemptions: paths/endpoints meant to be served cross-origin
if (exemptedPaths.contains(contextPath)) {
if (exemptedPaths.contains(path)) {
return invocation.invoke();
}

Expand All @@ -78,7 +79,7 @@ public String intercept(ActionInvocation invocation) throws Exception {
return invocation.invoke();
}

LOG.warn("Fetch metadata rejected cross-origin request to: {}", contextPath);
LOG.warn("Fetch metadata rejected cross-origin request to: {}", path);
return SC_FORBIDDEN;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ public void testEnforcingHeader() throws Exception {
}

public void testExemptedPath() throws Exception{
request.setContextPath("/foo");
request.setServletPath("/foo");
interceptor.setEnforcingMode("true");

interceptor.intercept(mai);

String header = response.getHeader(COEP_ENFORCING_HEADER);
assertTrue("COEP applied to exempted path", Strings.isEmpty(header));
}

public void testExemptedPathInfo() throws Exception {
interceptor.setExemptedPaths("/rest/orders");
request.setServletPath("/rest");
request.setPathInfo("/orders");
interceptor.setEnforcingMode("true");

interceptor.intercept(mai);
Expand All @@ -61,6 +73,16 @@ public void testExemptedPath() throws Exception{
assertTrue("COEP applied to exempted path", Strings.isEmpty(header));
}

public void testHeaderSetWhenOnlyContextPathIsExempted() throws Exception {
request.setContextPath("/foo");
request.setServletPath("/index.action");
interceptor.setEnforcingMode("true");

interceptor.intercept(mai);

assertEquals("COEP header value is incorrect", HEADER_CONTENT, response.getHeader(COEP_ENFORCING_HEADER));
}

public void testReportingHeader() throws Exception {
interceptor.setEnforcingMode("false");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class CoopInterceptorTest extends StrutsInternalTestCase {
String COOP_HEADER = "Cross-Origin-Opener-Policy";

public void testHeaderIsSetNonExemptedPath() throws Exception {
request.setContextPath("/some");
request.setServletPath("/some.action");
interceptor.intercept(mai);

String header = response.getHeader(COOP_HEADER);
Expand All @@ -47,16 +47,34 @@ public void testHeaderIsSetNonExemptedPath() throws Exception {
}

public void testHeaderIsNotSetExemptedPath() throws Exception {
request.setContextPath("/foo");
request.setServletPath("/foo");
interceptor.intercept(mai);

String header = response.getHeader(COOP_HEADER);
assertTrue("Coop header exists in exempted path", Strings.isEmpty(header));
}

public void testHeaderIsNotSetExemptedPathInfo() throws Exception {
interceptor.setExemptedPaths("/rest/orders");
request.setServletPath("/rest");
request.setPathInfo("/orders");
interceptor.intercept(mai);

String header = response.getHeader(COOP_HEADER);
assertTrue("Coop header exists in exempted path", Strings.isEmpty(header));
}

public void testHeaderIsSetWhenOnlyContextPathIsExempted() throws Exception {
request.setContextPath("/foo");
request.setServletPath("/index.action");
interceptor.intercept(mai);

assertEquals("Coop header is not same-origin", SAME_ORIGIN, response.getHeader(COOP_HEADER));
}

public void testChangeDefaultMode() throws Exception {
interceptor.setMode("unsafe-none");
request.setContextPath("/some");
request.setServletPath("/some.action");
interceptor.intercept(mai);

String header = response.getHeader(COOP_HEADER);
Expand All @@ -65,7 +83,7 @@ public void testChangeDefaultMode() throws Exception {
}

public void testErrorNotRecognizedMode() {
request.setContextPath("/some");
request.setServletPath("/some.action");

try{
interceptor.setMode("foobar");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -151,21 +152,46 @@ public void testInvalidTopLevelNavigation() throws Exception {

public void testPathInExemptedPaths() throws Exception {
request.addHeader(SEC_FETCH_SITE_HEADER, "foo");
request.setContextPath("/foo");
request.setServletPath("/foo");

assertNotEquals("Expected interceptor to accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
}

public void testPathNotInExemptedPaths() throws Exception {
request.addHeader(SEC_FETCH_SITE_HEADER, "foo");
request.setContextPath("/foobar");
request.setServletPath("/foobar");

assertEquals("Expected interceptor to NOT accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
}

public void testPathInfoInExemptedPaths() throws Exception {
interceptor.setExemptedPaths("/rest/orders");
request.addHeader(SEC_FETCH_SITE_HEADER, SITE_CROSS_SITE);
request.setServletPath("/rest");
request.setPathInfo("/orders");

assertNotEquals("Expected interceptor to accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
}

public void testContextPathInExemptedPathsDoesNotExempt() throws Exception {
request.addHeader(SEC_FETCH_SITE_HEADER, SITE_CROSS_SITE);
request.setContextPath("/foo");
request.setServletPath("/index.action");

assertEquals("Expected interceptor to NOT accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
}

public void testIncludedPathInExemptedPaths() throws Exception {
request.addHeader(SEC_FETCH_SITE_HEADER, SITE_CROSS_SITE);
request.setServletPath("/outer.action");
request.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, "/foo");

assertNotEquals("Expected interceptor to accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
}

public void testVaryHeaderAcceptedReq() throws Exception {
request.addHeader(SEC_FETCH_SITE_HEADER, "foo");
request.setContextPath("/foo");
request.setServletPath("/foo");

interceptor.intercept(mai);

Expand Down Expand Up @@ -223,11 +249,11 @@ public void testSetExemptedPathsInjectionIndirectly() throws Exception {
FetchMetadataInterceptor configuredFetchMetadataInterceptor = (FetchMetadataInterceptor) configuredFetchMetadataInterceptorMapping.getInterceptor();
request.removeHeader(SEC_FETCH_SITE_HEADER);
request.addHeader(SEC_FETCH_SITE_HEADER, "foo");
request.setContextPath("/foo");
request.setServletPath("/foo");
assertEquals("Expected interceptor to NOT accept this request [/foo]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
request.setContextPath("/fetchMetadataExemptedGlobal");
request.setServletPath("/fetchMetadataExemptedGlobal.action");
assertNotEquals("Expected interceptor to accept this request [/fetchMetadataExemptedGlobal]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
request.setContextPath("/someOtherPath");
request.setServletPath("/someOtherPath.action");
assertNotEquals("Expected interceptor to accept this request [/someOtherPath]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));

// The test configuration in "struts-testing.xml" should also contain three actions configured differently for the "fetchMetadata" interceptor.
Expand Down Expand Up @@ -258,8 +284,8 @@ public void testSetExemptedPathsInjectionIndirectly() throws Exception {
configuredFetchMetadataInterceptor = (FetchMetadataInterceptor) configuredFetchMetadataInterceptorMapping.getInterceptor();
request.removeHeader(SEC_FETCH_SITE_HEADER);
request.addHeader(SEC_FETCH_SITE_HEADER, fetchMetadataExemptedActionConfig.getName());
request.setContextPath("/" + fetchMetadataExemptedActionConfig.getName());
assertNotEquals("Expected interceptor to accept this request [" + "/" + fetchMetadataExemptedActionConfig.getName() + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
request.setServletPath("/" + fetchMetadataExemptedActionConfig.getName() + ".action");
assertNotEquals("Expected interceptor to accept this request [" + "/" + fetchMetadataExemptedActionConfig.getName() + ".action" + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));

// Test fetchMetadata interceptor for the "fetchMetadataNotExempted" action.
currentActionInterceptors = fetchMetadataNotExemptedActionConfig.getInterceptors();
Expand All @@ -278,8 +304,8 @@ public void testSetExemptedPathsInjectionIndirectly() throws Exception {
configuredFetchMetadataInterceptor = (FetchMetadataInterceptor) configuredFetchMetadataInterceptorMapping.getInterceptor();
request.removeHeader(SEC_FETCH_SITE_HEADER);
request.addHeader(SEC_FETCH_SITE_HEADER, fetchMetadataNotExemptedActionConfig.getName());
request.setContextPath("/" + fetchMetadataNotExemptedActionConfig.getName());
assertEquals("Expected interceptor to NOT accept this request [" + "/" + fetchMetadataNotExemptedActionConfig.getName() + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
request.setServletPath("/" + fetchMetadataNotExemptedActionConfig.getName() + ".action");
assertEquals("Expected interceptor to NOT accept this request [" + "/" + fetchMetadataNotExemptedActionConfig.getName() + ".action" + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));

// Test fetchMetadata interceptor for the "fetchMetadataExemptedGlobal" action.
currentActionInterceptors = fetchMetadataExemptedGlobalActionConfig.getInterceptors();
Expand All @@ -298,8 +324,8 @@ public void testSetExemptedPathsInjectionIndirectly() throws Exception {
configuredFetchMetadataInterceptor = (FetchMetadataInterceptor) configuredFetchMetadataInterceptorMapping.getInterceptor();
request.removeHeader(SEC_FETCH_SITE_HEADER);
request.addHeader(SEC_FETCH_SITE_HEADER, fetchMetadataExemptedGlobalActionConfig.getName());
request.setContextPath("/" + fetchMetadataExemptedGlobalActionConfig.getName());
assertNotEquals("Expected interceptor to accept this request [" + "/" + fetchMetadataExemptedGlobalActionConfig.getName() + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
request.setServletPath("/" + fetchMetadataExemptedGlobalActionConfig.getName() + ".action");
assertNotEquals("Expected interceptor to accept this request [" + "/" + fetchMetadataExemptedGlobalActionConfig.getName() + ".action" + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
}

}
6 changes: 3 additions & 3 deletions core/src/test/resources/struts-testing.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@
<interceptors>
<interceptor-stack name="defaultInterceptorStack">
<interceptor-ref name="defaultStack">
<param name="fetchMetadata.setExemptedPaths">/fetchMetadataExemptedGlobal,/someOtherPath</param>
<param name="fetchMetadata.setExemptedPaths">/fetchMetadataExemptedGlobal.action,/someOtherPath.action</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>

<action name="fetchMetadataExempted" class="org.apache.struts2.SimpleAction">
<interceptor-ref name="defaultInterceptorStack">
<param name="fetchMetadata.setExemptedPaths">/fetchMetadataExempted</param>
<param name="fetchMetadata.setExemptedPaths">/fetchMetadataExempted.action</param>
</interceptor-ref>
<result name="success">hello.jsp</result>
</action>

<action name="fetchMetadataNotExempted" class="org.apache.struts2.SimpleAction">
<interceptor-ref name="defaultInterceptorStack">
<param name="fetchMetadata.setExemptedPaths">/nonMatchingActionPath</param>
<param name="fetchMetadata.setExemptedPaths">/nonMatchingActionPath.action</param>
</interceptor-ref>
<result name="success">hello.jsp</result>
</action>
Expand Down
Loading