From dc96c257d4198f1b255728f878c48840de13a3f4 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Wed, 17 Jan 2024 13:22:09 +0100 Subject: [PATCH 1/3] WW-5374 Allows to prepend reportUri with Servlet context --- .../interceptor/csp/CspInterceptor.java | 42 ++++++++++++++----- .../interceptor/CspInterceptorTest.java | 37 +++++++++++----- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java index 8e4356646a..aca583a324 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java @@ -43,7 +43,8 @@ public final class CspInterceptor extends AbstractInterceptor { private static final Logger LOG = LogManager.getLogger(CspInterceptor.class); - private Boolean enforcingMode; + private boolean prependServletContext = true; + private boolean enforcingMode; private String reportUri; @Override @@ -60,17 +61,22 @@ public String intercept(ActionInvocation invocation) throws Exception { } private void applySettings(ActionInvocation invocation, CspSettings cspSettings) { - if (enforcingMode != null) { - LOG.trace("Applying: {} to enforcingMode", enforcingMode); - cspSettings.setEnforcingMode(enforcingMode); - } + HttpServletRequest request = invocation.getInvocationContext().getServletRequest(); + HttpServletResponse response = invocation.getInvocationContext().getServletResponse(); + + LOG.trace("Applying: {} to enforcingMode", enforcingMode); + cspSettings.setEnforcingMode(enforcingMode); + if (reportUri != null) { LOG.trace("Applying: {} to reportUri", reportUri); - cspSettings.setReportUri(reportUri); - } + String finalReportUri = reportUri; - HttpServletRequest request = invocation.getInvocationContext().getServletRequest(); - HttpServletResponse response = invocation.getInvocationContext().getServletResponse(); + if (prependServletContext && (request.getContextPath() != null) && (!request.getContextPath().isEmpty())) { + finalReportUri = request.getContextPath() + finalReportUri; + } + + cspSettings.setReportUri(finalReportUri); + } invocation.addPreResultListener((actionInvocation, resultCode) -> { LOG.trace("Applying CSP header: {} to the request", cspSettings); @@ -99,8 +105,22 @@ private Optional buildUri(String reportUri) { } } - public void setEnforcingMode(String value) { - this.enforcingMode = Boolean.parseBoolean(value); + /** + * Enables enforcing mode, by default all exceptions are only reported + * + * @param enforcingMode true to enable enforcing mode, false to keep reporting mode. + */ + public void setEnforcingMode(boolean enforcingMode) { + this.enforcingMode = enforcingMode; + } + + /** + * Sets whether to prepend the servlet context path to the {@link #reportUri}. + * + * @param prependServletContext true to prepend the location with the servlet context path, false otherwise. + */ + public void setPrependServletContext(boolean prependServletContext) { + this.prependServletContext = prependServletContext; } } diff --git a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java index 2811b289f2..38ef25b823 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java @@ -22,6 +22,7 @@ import com.opensymphony.xwork2.mock.MockActionInvocation; import org.apache.logging.log4j.util.Strings; import org.apache.struts2.StrutsInternalTestCase; +import org.apache.struts2.TestAction; import org.apache.struts2.action.CspSettingsAware; import org.apache.struts2.dispatcher.SessionMap; import org.apache.struts2.interceptor.csp.CspInterceptor; @@ -45,7 +46,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase { public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContainsIt() throws Exception { String reportUri = "/barfoo"; - String reporting = "false"; + boolean reporting = false; interceptor.setReportUri(reportUri); interceptor.setEnforcingMode(reporting); @@ -58,7 +59,7 @@ public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContain public void test_whenNonceAlreadySetInSession_andRequestReceived_thenNewNonceIsSet() throws Exception { String reportUri = "https://www.google.com/"; - String enforcingMode = "true"; + boolean enforcingMode = true; interceptor.setReportUri(reportUri); interceptor.setEnforcingMode(enforcingMode); session.setAttribute("nonce", "foo"); @@ -73,7 +74,7 @@ public void test_whenNonceAlreadySetInSession_andRequestReceived_thenNewNonceIsS public void testEnforcingCspHeadersSet() throws Exception { String reportUri = "/csp-reports"; - String enforcingMode = "true"; + boolean enforcingMode = true; interceptor.setReportUri(reportUri); interceptor.setEnforcingMode(enforcingMode); session.setAttribute("nonce", "foo"); @@ -88,7 +89,7 @@ public void testEnforcingCspHeadersSet() throws Exception { public void testReportingCspHeadersSet() throws Exception { String reportUri = "/csp-reports"; - String enforcingMode = "false"; + boolean enforcingMode = false; interceptor.setReportUri(reportUri); interceptor.setEnforcingMode(enforcingMode); session.setAttribute("nonce", "foo"); @@ -101,7 +102,7 @@ public void testReportingCspHeadersSet() throws Exception { } public void test_uriSetOnlyWhenSetIsCalled() throws Exception { - String enforcingMode = "false"; + boolean enforcingMode = false; interceptor.setEnforcingMode(enforcingMode); interceptor.intercept(mai); @@ -115,7 +116,7 @@ public void test_uriSetOnlyWhenSetIsCalled() throws Exception { } public void testCannotParseUri() { - String enforcingMode = "false"; + boolean enforcingMode = false; interceptor.setEnforcingMode(enforcingMode); try { @@ -127,7 +128,7 @@ public void testCannotParseUri() { } public void testCannotParseRelativeUri() { - String enforcingMode = "false"; + boolean enforcingMode = false; interceptor.setEnforcingMode(enforcingMode); try { @@ -139,13 +140,27 @@ public void testCannotParseRelativeUri() { } public void testCustomPreResultListener() throws Exception { + boolean enforcingMode = false; mai.setAction(new CustomerCspAction("/report-uri")); - interceptor.setEnforcingMode("false"); + interceptor.setEnforcingMode(enforcingMode); + interceptor.intercept(mai); + checkHeader("/report-uri", enforcingMode); + } + + public void testPrependContext() throws Exception { + boolean enforcingMode = true; + mai.setAction(new TestAction()); + request.setContextPath("/app"); + + interceptor.setEnforcingMode(enforcingMode); + interceptor.setReportUri("/report-uri"); + interceptor.intercept(mai); - checkHeader("/report-uri", "false"); + + checkHeader("/app/report-uri", enforcingMode); } - public void checkHeader(String reportUri, String enforcingMode) { + public void checkHeader(String reportUri, boolean enforcingMode) { String expectedCspHeader; if (Strings.isEmpty(reportUri)) { expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ", @@ -163,7 +178,7 @@ public void checkHeader(String reportUri, String enforcingMode) { } String header; - if (enforcingMode.equals("true")) { + if (enforcingMode) { header = response.getHeader(CspSettings.CSP_ENFORCE_HEADER); } else { header = response.getHeader(CspSettings.CSP_REPORT_HEADER); From d5932f82faf914fe16c680ba3479e55195fe5207 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 18 Jan 2024 11:24:08 +0100 Subject: [PATCH 2/3] WW-5374 Uses @code instead of --- .../org/apache/struts2/interceptor/csp/CspInterceptor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java index aca583a324..32d6777869 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/CspInterceptor.java @@ -108,7 +108,7 @@ private Optional buildUri(String reportUri) { /** * Enables enforcing mode, by default all exceptions are only reported * - * @param enforcingMode true to enable enforcing mode, false to keep reporting mode. + * @param enforcingMode {@code true} to enable enforcing mode, {@code false} to keep reporting mode. */ public void setEnforcingMode(boolean enforcingMode) { this.enforcingMode = enforcingMode; @@ -117,7 +117,8 @@ public void setEnforcingMode(boolean enforcingMode) { /** * Sets whether to prepend the servlet context path to the {@link #reportUri}. * - * @param prependServletContext true to prepend the location with the servlet context path, false otherwise. + * @param prependServletContext {@code true} to prepend the location with the servlet context path, + * {@code false} otherwise. */ public void setPrependServletContext(boolean prependServletContext) { this.prependServletContext = prependServletContext; From 790c663ddd625c20dbbc35796e28a1c93562d4b4 Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Thu, 18 Jan 2024 11:24:34 +0100 Subject: [PATCH 3/3] WW-5374 Adds additional test case to cover disabling prepending context --- .../struts2/interceptor/CspInterceptorTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java index 38ef25b823..0b03c6e54c 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java @@ -160,6 +160,20 @@ public void testPrependContext() throws Exception { checkHeader("/app/report-uri", enforcingMode); } + public void testNoPrependContext() throws Exception { + boolean enforcingMode = true; + mai.setAction(new TestAction()); + request.setContextPath("/app"); + + interceptor.setEnforcingMode(enforcingMode); + interceptor.setReportUri("/report-uri"); + interceptor.setPrependServletContext(false); + + interceptor.intercept(mai); + + checkHeader("/report-uri", enforcingMode); + } + public void checkHeader(String reportUri, boolean enforcingMode) { String expectedCspHeader; if (Strings.isEmpty(reportUri)) {