Skip to content

Commit 8fe1342

Browse files
Do not compute CSP header if disabled (#26255)
* Do not compute CSP header if disabled * Replace waiting with counting invocations * Replace waiting with counting --------- Co-authored-by: Daniel Beck <daniel-beck@users.noreply.github.com> Co-authored-by: Kris Stern <88480540+krisstern@users.noreply.github.com> (cherry picked from commit 6227cd1)
1 parent ece5920 commit 8fe1342

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

core/src/main/java/jenkins/security/csp/impl/CspFilter.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
6363
final String headerName = cspDecorator.getContentSecurityPolicyHeaderName();
6464
final boolean headerShouldBeSet = headerName != null;
6565

66-
// This is the preliminary value outside Stapler request handling (and providing a context object)
67-
final String headerValue = cspDecorator.getContentSecurityPolicyHeaderValue(req);
68-
6966
final boolean isResourceRequest = ResourceDomainConfiguration.isResourceRequest(req);
7067

68+
String headerValue = "";
69+
7170
if (headerShouldBeSet && !isResourceRequest) {
71+
// This is the preliminary value outside Stapler request handling (and providing a context object)
72+
headerValue = cspDecorator.getContentSecurityPolicyHeaderValue(req);
73+
7274
// The Filter/Decorator approach needs us to "set" headers rather than "add", so no additional endpoints are supported at the moment.
7375
final String reportingEndpoints = cspDecorator.getReportingEndpointsHeaderValue(req);
7476
if (reportingEndpoints != null) {
@@ -80,10 +82,10 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
8082
try {
8183
chain.doFilter(req, rsp);
8284
} finally {
83-
if (headerShouldBeSet) {
85+
if (headerShouldBeSet && !isResourceRequest) {
8486
try {
8587
final String actualHeader = rsp.getHeader(headerName);
86-
if (!isResourceRequest && hasUnexpectedDifference(headerValue, actualHeader)) {
88+
if (hasUnexpectedDifference(headerValue, actualHeader)) {
8789
LOGGER.log(Level.FINE, "CSP header has unexpected differences: Expected '" + headerValue + "' but got '" + actualHeader + "'");
8890
}
8991
} catch (RuntimeException e) {

test/src/test/java/jenkins/security/csp/impl/CspFilterTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@
44
import static org.hamcrest.Matchers.allOf;
55
import static org.hamcrest.Matchers.endsWith;
66
import static org.hamcrest.Matchers.equalTo;
7+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
8+
import static org.hamcrest.Matchers.is;
79
import static org.hamcrest.Matchers.nullValue;
810
import static org.hamcrest.Matchers.startsWith;
911
import static org.jvnet.hudson.test.LoggerRule.recorded;
1012

13+
import hudson.ExtensionList;
1114
import hudson.security.csrf.CrumbExclusion;
1215
import jakarta.servlet.FilterChain;
1316
import jakarta.servlet.ServletException;
1417
import jakarta.servlet.http.HttpServletRequest;
1518
import jakarta.servlet.http.HttpServletResponse;
1619
import java.io.IOException;
1720
import java.net.URL;
21+
import java.util.concurrent.atomic.AtomicInteger;
1822
import java.util.logging.Level;
1923
import jenkins.model.JenkinsLocationConfiguration;
24+
import jenkins.security.csp.Contributor;
25+
import jenkins.security.csp.CspBuilder;
2026
import jenkins.util.HttpServletFilter;
2127
import org.hamcrest.Matcher;
2228
import org.htmlunit.HttpMethod;
@@ -27,6 +33,7 @@
2733
import org.jvnet.hudson.test.LoggerRule;
2834
import org.jvnet.hudson.test.TestExtension;
2935
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
36+
import org.xml.sax.SAXException;
3037

3138
@WithJenkins
3239
public class CspFilterTest {
@@ -99,6 +106,44 @@ void testFilterWithoutCsp(JenkinsRule j) throws Exception {
99106
endsWith(":YW5vbnltb3Vz::L3Rlc3QtZmlsdGVyLXdpdGhvdXQtY3NwL3NvbWUtcGF0aA==' but got 'null'"))));
100107
}
101108

109+
@Test
110+
void testCspBuilderNotCalledWithHeaderDisabled(JenkinsRule j) throws IOException, SAXException {
111+
try (JenkinsRule.WebClient webClient = j.createWebClient().withJavaScriptEnabled(false)) {
112+
final AtomicInteger counter = ExtensionList.lookupSingleton(CountingContributor.class).counter;
113+
{
114+
int start = counter.get();
115+
webClient.goTo("");
116+
int end = counter.get();
117+
118+
final int difference = end - start;
119+
assertThat(difference, greaterThanOrEqualTo(1));
120+
}
121+
122+
System.setProperty(SystemPropertyHeaderDecider.SYSTEM_PROPERTY_NAME, "");
123+
try {
124+
int start = counter.get();
125+
webClient.goTo("");
126+
int end = counter.get();
127+
128+
// no calls expected
129+
final int difference = end - start;
130+
assertThat(difference, is(0));
131+
} finally {
132+
System.clearProperty(SystemPropertyHeaderDecider.SYSTEM_PROPERTY_NAME);
133+
}
134+
}
135+
}
136+
137+
@TestExtension("testCspBuilderNotCalledWithHeaderDisabled")
138+
public static class CountingContributor implements Contributor {
139+
AtomicInteger counter = new AtomicInteger(0);
140+
141+
@Override
142+
public void apply(CspBuilder cspBuilder) {
143+
counter.incrementAndGet();
144+
}
145+
}
146+
102147
@TestExtension
103148
public static class TestFilter implements HttpServletFilter {
104149
@Override

0 commit comments

Comments
 (0)