From: Alain Kermis Date: Mon, 11 Mar 2024 14:48:26 +0000 (+0100) Subject: SONAR-21780 Add Cross-Origin related HTTP security headers X-Git-Tag: 10.5.0.89998~130 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4f2cb04c5da8b5b07c459afdb6d777b29db779b5;p=sonarqube.git SONAR-21780 Add Cross-Origin related HTTP security headers --- diff --git a/server/sonar-web/public/WEB-INF/web.xml b/server/sonar-web/public/WEB-INF/web.xml index 91e874831eb..0a1414eab7a 100644 --- a/server/sonar-web/public/WEB-INF/web.xml +++ b/server/sonar-web/public/WEB-INF/web.xml @@ -62,7 +62,12 @@ org.sonar.server.platform.web.CspFilter true - + + CrossOriginFilter + org.sonar.server.platform.web.CrossOriginFilter + true + + EndpointPathFilter org.sonar.server.platform.web.EndpointPathFilter true @@ -101,6 +106,10 @@ CspFilter /* + + CrossOriginFilter + /* + UserSessionFilter /* diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CrossOriginFilter.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CrossOriginFilter.java new file mode 100644 index 00000000000..73cb9bac8f3 --- /dev/null +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CrossOriginFilter.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.web; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +public class CrossOriginFilter implements Filter { + + private final Map crossOriginHeaders = new HashMap<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + crossOriginHeaders.put("Cross-Origin-Embedder-Policy", "require-corp"); + crossOriginHeaders.put("Cross-Origin-Opener-Policy", "same-origin"); + crossOriginHeaders.put("Cross-Origin-Resource-Policy", "same-origin"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + // Add policies to all HTTP headers + for (Map.Entry entry : crossOriginHeaders.entrySet()) { + ((HttpServletResponse) response).setHeader(entry.getKey(), entry.getValue()); + } + + chain.doFilter(request, response); + } + + @Override + public void destroy() { + // Not used + } + +} diff --git a/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CrossOriginFilterTest.java b/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CrossOriginFilterTest.java new file mode 100644 index 00000000000..ae307b5b2ed --- /dev/null +++ b/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CrossOriginFilterTest.java @@ -0,0 +1,73 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.web; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.RETURNS_MOCKS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class CrossOriginFilterTest { + + private static final String TEST_CONTEXT = "/sonarqube"; + private final ServletContext servletContext = mock(ServletContext.class, RETURNS_MOCKS); + private final HttpServletResponse response = mock(HttpServletResponse.class); + private final FilterChain chain = mock(FilterChain.class); + private final CrossOriginFilter underTest = new CrossOriginFilter(); + FilterConfig config = mock(FilterConfig.class); + + @Before + public void setUp() throws ServletException { + when(servletContext.getContextPath()).thenReturn(TEST_CONTEXT); + } + + @Test + public void doInit_whenCalled_shouldSetHeaders() throws Exception { + doInit(); + HttpServletRequest request = newRequest("/"); + underTest.doFilter(request, response, chain); + verify(response).setHeader("Cross-Origin-Embedder-Policy", "require-corp"); + verify(response).setHeader("Cross-Origin-Opener-Policy", "same-origin"); + verify(response).setHeader("Cross-Origin-Resource-Policy", "same-origin"); + verify(chain).doFilter(request, response); + } + + private void doInit() throws ServletException { + underTest.init(config); + } + + private HttpServletRequest newRequest(String path) { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getMethod()).thenReturn("GET"); + when(req.getRequestURI()).thenReturn(path); + when(req.getContextPath()).thenReturn(""); + when(req.getServletContext()).thenReturn(this.servletContext); + return req; + } +}