diff options
author | Dimitris Kavvathas <dimitris.kavvathas@sonarsource.com> | 2022-09-14 15:21:47 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-09-15 20:03:03 +0000 |
commit | 01350017dd20b13f0b1f3c82325d1426afeb95b2 (patch) | |
tree | 034f6ad863bfd38e0b589aa5de693168ab2af8dd /server/sonar-webserver-auth | |
parent | 37226c00747bddecc291f56ec1b208984527931a (diff) | |
download | sonarqube-01350017dd20b13f0b1f3c82325d1426afeb95b2.tar.gz sonarqube-01350017dd20b13f0b1f3c82325d1426afeb95b2.zip |
SONAR-17296 Add SamlValidationRedirectionFilter and SamlValidationCallbackFilter to show SAML validation status page.
Diffstat (limited to 'server/sonar-webserver-auth')
4 files changed, 148 insertions, 1 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationError.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationError.java index f16dc2772f0..6fa2420fdd7 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationError.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationError.java @@ -46,7 +46,7 @@ public final class AuthenticationError { redirectToUnauthorized(request, response); } - static void handleError(HttpServletRequest request, HttpServletResponse response, String message) { + public static void handleError(HttpServletRequest request, HttpServletResponse response, String message) { LOGGER.warn(message); redirectToUnauthorized(request, response); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationModule.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationModule.java index 2c2ca0edba4..5beed48ec0c 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationModule.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/AuthenticationModule.java @@ -43,6 +43,7 @@ public class AuthenticationModule extends Module { JwtHttpHandler.class, JwtSerializer.class, OAuth2AuthenticationParametersImpl.class, + SamlValidationRedirectionFilter.class, OAuth2CallbackFilter.class, OAuth2ContextFactory.class, OAuthCsrfVerifier.class, diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SamlValidationRedirectionFilter.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SamlValidationRedirectionFilter.java new file mode 100644 index 00000000000..d28daf1b72a --- /dev/null +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/SamlValidationRedirectionFilter.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.authentication; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.sonar.api.platform.Server; +import org.sonar.api.web.ServletFilter; + +import static org.sonar.server.authentication.AuthenticationFilter.CALLBACK_PATH; + +public class SamlValidationRedirectionFilter extends ServletFilter { + + public static final String VALIDATION_RELAY_STATE = "validation-query"; + public static final String SAML_VALIDATION_URL = "/saml/validation_callback"; + private final Server server; + + public SamlValidationRedirectionFilter(Server server) { + this.server = server; + } + + @Override + public UrlPattern doGetPattern() { + return UrlPattern.create(CALLBACK_PATH + "saml"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + if (isSamlValidation(httpRequest)) { + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); + httpResponse.setHeader("Location", server.getContextPath() + SAML_VALIDATION_URL); + return; + } + chain.doFilter(request, response); + } + + private static boolean isSamlValidation(HttpServletRequest request) { + return VALIDATION_RELAY_STATE.equals(request.getParameter("RelayState")); + } +} diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/SamlValidationRedirectionFilterTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/SamlValidationRedirectionFilterTest.java new file mode 100644 index 00000000000..ba54dddc33a --- /dev/null +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/SamlValidationRedirectionFilterTest.java @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.authentication; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.platform.Server; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +public class SamlValidationRedirectionFilterTest { + + SamlValidationRedirectionFilter underTest; + + @Before + public void setup() { + Server server = mock(Server.class); + doReturn("").when(server).getContextPath(); + underTest = new SamlValidationRedirectionFilter(server); + } + + @Test + public void do_get_pattern() { + assertThat(underTest.doGetPattern().matches("/oauth2/callback/saml")).isTrue(); + assertThat(underTest.doGetPattern().matches("/oauth2/callback/")).isFalse(); + assertThat(underTest.doGetPattern().matches("/oauth2/callback/test")).isFalse(); + assertThat(underTest.doGetPattern().matches("/oauth2/")).isFalse(); + } + + @Test + public void do_filter_validation_relay_state() throws ServletException, IOException { + HttpServletRequest servletRequest = mock(HttpServletRequest.class); + HttpServletResponse servletResponse = mock(HttpServletResponse.class); + FilterChain filterChain = mock(FilterChain.class); + + doReturn("validation-query").when(servletRequest).getParameter("RelayState"); + underTest.doFilter(servletRequest, servletResponse, filterChain); + + verify(servletResponse).setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT); + verify(servletResponse).setHeader("Location", "/saml/validation_callback"); + } + + @Test + public void do_filter_no_validation_relay_state() throws ServletException, IOException { + HttpServletRequest servletRequest = mock(HttpServletRequest.class); + HttpServletResponse servletResponse = mock(HttpServletResponse.class); + FilterChain filterChain = mock(FilterChain.class); + + doReturn("random_query").when(servletRequest).getParameter("RelayState"); + underTest.doFilter(servletRequest, servletResponse, filterChain); + + verifyNoInteractions(servletResponse); + } +} |