aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-webapi
diff options
context:
space:
mode:
authorDimitris Kavvathas <dimitris.kavvathas@sonarsource.com>2022-09-14 15:21:47 +0200
committersonartech <sonartech@sonarsource.com>2022-09-15 20:03:03 +0000
commit01350017dd20b13f0b1f3c82325d1426afeb95b2 (patch)
tree034f6ad863bfd38e0b589aa5de693168ab2af8dd /server/sonar-webserver-webapi
parent37226c00747bddecc291f56ec1b208984527931a (diff)
downloadsonarqube-01350017dd20b13f0b1f3c82325d1426afeb95b2.tar.gz
sonarqube-01350017dd20b13f0b1f3c82325d1426afeb95b2.zip
SONAR-17296 Add SamlValidationRedirectionFilter and SamlValidationCallbackFilter to show SAML validation status page.
Diffstat (limited to 'server/sonar-webserver-webapi')
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationCallbackFilter.java76
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationModule.java3
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java12
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/SamlValidationCallbackFilterTest.java97
4 files changed, 181 insertions, 7 deletions
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationCallbackFilter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationCallbackFilter.java
new file mode 100644
index 00000000000..439a1b312ca
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationCallbackFilter.java
@@ -0,0 +1,76 @@
+/*
+ * 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.saml.ws;
+
+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.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import org.sonar.api.web.ServletFilter;
+import org.sonar.auth.saml.SamlAuthenticator;
+import org.sonar.auth.saml.SamlIdentityProvider;
+import org.sonar.server.authentication.AuthenticationError;
+import org.sonar.server.authentication.OAuth2ContextFactory;
+import org.sonar.server.user.ThreadLocalUserSession;
+
+import static org.sonar.server.authentication.SamlValidationRedirectionFilter.SAML_VALIDATION_URL;
+
+public class SamlValidationCallbackFilter extends ServletFilter {
+
+ private final ThreadLocalUserSession userSession;
+ private final SamlAuthenticator samlAuthenticator;
+ private final OAuth2ContextFactory oAuth2ContextFactory;
+
+ public SamlValidationCallbackFilter(ThreadLocalUserSession userSession, SamlAuthenticator samlAuthenticator, OAuth2ContextFactory oAuth2ContextFactory) {
+ this.samlAuthenticator = samlAuthenticator;
+ this.userSession = userSession;
+ this.oAuth2ContextFactory = oAuth2ContextFactory;
+ }
+
+ @Override
+ public UrlPattern doGetPattern() {
+ return UrlPattern.create(SAML_VALIDATION_URL);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ if (!userSession.hasSession() || !userSession.isSystemAdministrator()) {
+ AuthenticationError.handleError(httpRequest, httpResponse, "User needs to be logged in as system administrator to access this page.");
+ return;
+ }
+
+ httpRequest = new HttpServletRequestWrapper(httpRequest) {
+ @Override
+ public StringBuffer getRequestURL() {
+ return new StringBuffer(oAuth2ContextFactory.generateCallbackUrl(SamlIdentityProvider.KEY));
+ }
+ };
+
+ httpResponse.setContentType("text/html");
+ httpResponse.getWriter().print(samlAuthenticator.getAuthenticationStatusPage(httpRequest, httpResponse));
+ }
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationModule.java
index 2baff89a489..602ed55959a 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationModule.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/saml/ws/SamlValidationModule.java
@@ -26,7 +26,8 @@ public class SamlValidationModule extends Module {
protected void configureModule() {
add(
SamlValidationWs.class,
- SamlValidationInitAction.class
+ SamlValidationInitAction.class,
+ SamlValidationCallbackFilter.class
);
}
}
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
index d0bc2bd9e8a..704fe8f7571 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java
@@ -87,7 +87,7 @@ public class QProfileBackuperImplTest {
StringWriter writer = new StringWriter();
underTest.backup(db.getSession(), profile, writer);
- assertThat(writer).hasToString("<?xml version='1.0' encoding='UTF-8'?>" +
+ assertThat(writer).hasToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<profile><name>" + profile.getName() + "</name>" +
"<language>" + profile.getLanguage() + "</language>" +
"<rules>" +
@@ -96,7 +96,7 @@ public class QProfileBackuperImplTest {
"<key>" + rule.getRuleKey() + "</key>" +
"<type>" + RuleType.valueOf(rule.getType()).name() + "</type>" +
"<priority>" + activeRule.getSeverityString() + "</priority>" +
- "<parameters/>" +
+ "<parameters></parameters>" +
"</rule>" +
"</rules>" +
"</profile>");
@@ -133,10 +133,10 @@ public class QProfileBackuperImplTest {
StringWriter writer = new StringWriter();
underTest.backup(db.getSession(), profile, writer);
- assertThat(writer).hasToString("<?xml version='1.0' encoding='UTF-8'?>" +
+ assertThat(writer).hasToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<profile><name>" + profile.getName() + "</name>" +
"<language>" + profile.getLanguage() + "</language>" +
- "<rules/>" +
+ "<rules></rules>" +
"</profile>");
}
@@ -156,7 +156,7 @@ public class QProfileBackuperImplTest {
StringWriter writer = new StringWriter();
underTest.backup(db.getSession(), profile, writer);
- assertThat(writer).hasToString("<?xml version='1.0' encoding='UTF-8'?>" +
+ assertThat(writer).hasToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<profile>" +
"<name>" + profile.getName() + "</name>" +
"<language>" + profile.getLanguage() + "</language>" +
@@ -186,7 +186,7 @@ public class QProfileBackuperImplTest {
StringWriter writer = new StringWriter();
underTest.backup(db.getSession(), profile, writer);
- assertThat(writer).hasToString("<?xml version='1.0' encoding='UTF-8'?>" +
+ assertThat(writer).hasToString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<profile>" +
"<name>" + profile.getName() + "</name>" +
"<language>" + profile.getLanguage() + "</language>" +
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/SamlValidationCallbackFilterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/SamlValidationCallbackFilterTest.java
new file mode 100644
index 00000000000..27fd9764302
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/saml/ws/SamlValidationCallbackFilterTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.saml.ws;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+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.auth.saml.SamlAuthenticator;
+import org.sonar.server.authentication.OAuth2ContextFactory;
+import org.sonar.server.user.ThreadLocalUserSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+public class SamlValidationCallbackFilterTest {
+
+ private SamlValidationCallbackFilter underTest;
+ private SamlAuthenticator samlAuthenticator;
+ private ThreadLocalUserSession userSession;
+
+ @Before
+ public void setup() {
+ samlAuthenticator = mock(SamlAuthenticator.class);
+ userSession = mock(ThreadLocalUserSession.class);
+ var oAuth2ContextFactory = mock(OAuth2ContextFactory.class);
+ underTest = new SamlValidationCallbackFilter(userSession, samlAuthenticator, oAuth2ContextFactory);
+ }
+
+ @Test
+ public void do_get_pattern() {
+ assertThat(underTest.doGetPattern().matches("/saml/validation_callback")).isTrue();
+ assertThat(underTest.doGetPattern().matches("/saml/validation_callback2")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/saml/")).isFalse();
+ }
+
+ @Test
+ public void do_filter_admin() throws ServletException, IOException {
+ HttpServletRequest servletRequest = mock(HttpServletRequest.class);
+ HttpServletResponse servletResponse = mock(HttpServletResponse.class);
+ StringWriter stringWriter = new StringWriter();
+ doReturn(new PrintWriter(stringWriter)).when(servletResponse).getWriter();
+ FilterChain filterChain = mock(FilterChain.class);
+
+ doReturn(true).when(userSession).hasSession();
+ doReturn(true).when(userSession).isSystemAdministrator();
+
+ underTest.doFilter(servletRequest, servletResponse, filterChain);
+
+ verify(samlAuthenticator).getAuthenticationStatusPage(any(), any());
+ verify(servletResponse).getWriter();
+ }
+
+ @Test
+ public void do_filter_not_authorized() throws ServletException, IOException {
+ HttpServletRequest servletRequest = spy(HttpServletRequest.class);
+ HttpServletResponse servletResponse = mock(HttpServletResponse.class);
+ StringWriter stringWriter = new StringWriter();
+ doReturn(new PrintWriter(stringWriter)).when(servletResponse).getWriter();
+ FilterChain filterChain = mock(FilterChain.class);
+
+ doReturn(true).when(userSession).hasSession();
+ doReturn(false).when(userSession).isSystemAdministrator();
+
+ underTest.doFilter(servletRequest, servletResponse, filterChain);
+
+ verifyNoInteractions(samlAuthenticator);
+ }
+}