success?: boolean;
}
-const CONFIG_TEST_PATH = '/api/saml/validation_init';
+const CONFIG_TEST_PATH = '/saml/validation_init';
const SAML_ENABLED_FIELD = 'sonar.auth.saml.enabled';
import com.google.common.io.Resources;
import java.io.IOException;
+import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import javax.servlet.FilterChain;
public class SamlValidationRedirectionFilter extends ServletFilter {
public static final String VALIDATION_RELAY_STATE = "validation-query";
- public static final String SAML_VALIDATION_URL = "/saml/validation_callback";
+ public static final String SAML_VALIDATION_CONTROLLER_CONTEXT = "saml";
+ public static final String SAML_VALIDATION_KEY = "validation";
private String redirectionPageTemplate;
private final Server server;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String samlResponse = StringEscapeUtils.escapeHtml(request.getParameter("SAMLResponse"));
+ URI redirectionEndpointUrl = URI.create(server.getContextPath() + "/")
+ .resolve(SAML_VALIDATION_CONTROLLER_CONTEXT + "/")
+ .resolve(SAML_VALIDATION_KEY);
String template = StringUtils.replaceEachRepeatedly(redirectionPageTemplate,
new String[]{"%VALIDATION_URL%", "%SAML_RESPONSE%"},
- new String[]{server.getContextPath() + SAML_VALIDATION_URL, samlResponse});
+ new String[]{redirectionEndpointUrl.toString(), samlResponse});
httpResponse.setContentType("text/html");
httpResponse.getWriter().print(template);
ArgumentCaptor<String> htmlProduced = ArgumentCaptor.forClass(String.class);
verify(pw).print(htmlProduced.capture());
assertThat(htmlProduced.getValue()).doesNotContain("<script>/*hack website*/</script>");
+ assertThat(htmlProduced.getValue()).contains("action=\"/saml/validation\"");
}
@Test
+++ /dev/null
-/*
- * 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));
- }
-}
+++ /dev/null
-/*
- * 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.HttpServletResponse;
-import org.sonar.api.server.ws.WebService;
-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.exceptions.ForbiddenException;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.ws.ServletFilterHandler;
-
-public class SamlValidationInitAction extends ServletFilter implements SamlAction {
-
- public static final String VALIDATION_RELAY_STATE = "validation-query";
- private final SamlAuthenticator samlAuthenticator;
-
- private final OAuth2ContextFactory oAuth2ContextFactory;
- private final UserSession userSession;
-
- public SamlValidationInitAction(SamlAuthenticator samlAuthenticator, OAuth2ContextFactory oAuth2ContextFactory, UserSession userSession) {
- this.samlAuthenticator = samlAuthenticator;
- this.oAuth2ContextFactory = oAuth2ContextFactory;
- this.userSession = userSession;
- }
-
- @Override
- public UrlPattern doGetPattern() {
- return UrlPattern.create("/api/saml/validation_init");
- }
-
- @Override
- public void define(WebService.NewController controller) {
- controller
- .createAction("validation_init")
- .setInternal(true)
- .setPost(false)
- .setHandler(ServletFilterHandler.INSTANCE)
- .setDescription("Initiate a SAML request to the identity Provider for configuration validation purpose.")
- .setSince("9.7");
- }
-
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- HttpServletResponse response = (HttpServletResponse) servletResponse;
-
- try {
- userSession.checkIsSystemAdministrator();
- } catch (ForbiddenException e) {
- AuthenticationError.handleError(request, response, "User needs to be logged in as system administrator to access this page.");
- return;
- }
-
- samlAuthenticator.initLogin(oAuth2ContextFactory.generateCallbackUrl(SamlIdentityProvider.KEY),
- VALIDATION_RELAY_STATE, request, response);
- }
-}
protected void configureModule() {
add(
SamlValidationWs.class,
- SamlValidationInitAction.class,
- SamlValidationCallbackFilter.class
+ ValidationInitAction.class,
+ ValidationAction.class
);
}
}
import java.util.List;
import org.sonar.api.server.ws.WebService;
+import org.sonar.server.authentication.SamlValidationRedirectionFilter;
public class SamlValidationWs implements WebService {
- public static final String SAML_VALIDATION_CONTROLLER = "api/saml";
+ public static final String SAML_VALIDATION_CONTROLLER = SamlValidationRedirectionFilter.SAML_VALIDATION_CONTROLLER_CONTEXT;
private final List<SamlAction> actions;
public SamlValidationWs(List<SamlAction> actions) {
--- /dev/null
+/*
+ * 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.server.ws.WebService;
+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.authentication.SamlValidationRedirectionFilter;
+import org.sonar.server.user.ThreadLocalUserSession;
+import org.sonar.server.ws.ServletFilterHandler;
+
+public class ValidationAction extends ServletFilter implements SamlAction {
+
+ static final String VALIDATION_CALLBACK_KEY = SamlValidationRedirectionFilter.SAML_VALIDATION_KEY;
+ private final ThreadLocalUserSession userSession;
+ private final SamlAuthenticator samlAuthenticator;
+ private final OAuth2ContextFactory oAuth2ContextFactory;
+
+ public ValidationAction(ThreadLocalUserSession userSession, SamlAuthenticator samlAuthenticator, OAuth2ContextFactory oAuth2ContextFactory) {
+ this.samlAuthenticator = samlAuthenticator;
+ this.userSession = userSession;
+ this.oAuth2ContextFactory = oAuth2ContextFactory;
+ }
+
+ @Override
+ public UrlPattern doGetPattern() {
+ return UrlPattern.create("/" + SamlValidationWs.SAML_VALIDATION_CONTROLLER + "/" + VALIDATION_CALLBACK_KEY);
+ }
+
+ @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));
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller
+ .createAction(VALIDATION_CALLBACK_KEY)
+ .setInternal(true)
+ .setPost(true)
+ .setHandler(ServletFilterHandler.INSTANCE)
+ .setDescription("Handle the callback of a SAML assertion from the identity Provider and produces " +
+ "a HTML page with all information available in the assertion.")
+ .setSince("9.7");
+ action.createParam("SAMLResponse")
+ .setDescription("SAML assertion value")
+ .setRequired(true);
+ }
+}
--- /dev/null
+/*
+ * 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.HttpServletResponse;
+import org.sonar.api.server.ws.WebService;
+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.exceptions.ForbiddenException;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.ServletFilterHandler;
+
+public class ValidationInitAction extends ServletFilter implements SamlAction {
+
+ public static final String VALIDATION_RELAY_STATE = "validation-query";
+ public static final String VALIDATION_INIT_KEY = "validation_init";
+ private final SamlAuthenticator samlAuthenticator;
+
+ private final OAuth2ContextFactory oAuth2ContextFactory;
+ private final UserSession userSession;
+
+ public ValidationInitAction(SamlAuthenticator samlAuthenticator, OAuth2ContextFactory oAuth2ContextFactory, UserSession userSession) {
+ this.samlAuthenticator = samlAuthenticator;
+ this.oAuth2ContextFactory = oAuth2ContextFactory;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public UrlPattern doGetPattern() {
+ return UrlPattern.create("/" + SamlValidationWs.SAML_VALIDATION_CONTROLLER + "/" + VALIDATION_INIT_KEY);
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ controller
+ .createAction(VALIDATION_INIT_KEY)
+ .setInternal(true)
+ .setPost(false)
+ .setHandler(ServletFilterHandler.INSTANCE)
+ .setDescription("Initiate a SAML request to the identity Provider for configuration validation purpose.")
+ .setSince("9.7");
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ try {
+ userSession.checkIsSystemAdministrator();
+ } catch (ForbiddenException e) {
+ AuthenticationError.handleError(request, response, "User needs to be logged in as system administrator to access this page.");
+ return;
+ }
+
+ samlAuthenticator.initLogin(oAuth2ContextFactory.generateCallbackUrl(SamlIdentityProvider.KEY),
+ VALIDATION_RELAY_STATE, request, response);
+ }
+}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.auth.saml.SamlAuthenticator;
-import org.sonar.server.authentication.OAuth2ContextFactory;
-import org.sonar.server.tester.UserSessionRule;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.matches;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.when;
-
-public class SamlValidationInitActionTest {
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- private SamlValidationInitAction underTest;
- private SamlAuthenticator samlAuthenticator;
- private OAuth2ContextFactory oAuth2ContextFactory;
-
- @Before
- public void setUp() throws Exception {
- samlAuthenticator = mock(SamlAuthenticator.class);
- oAuth2ContextFactory = mock(OAuth2ContextFactory.class);
- underTest = new SamlValidationInitAction(samlAuthenticator, oAuth2ContextFactory, userSession);
- }
-
- @Test
- public void do_get_pattern() {
- assertThat(underTest.doGetPattern().matches("/api/saml/validation_init")).isTrue();
- assertThat(underTest.doGetPattern().matches("/api/saml")).isFalse();
- assertThat(underTest.doGetPattern().matches("/api/saml/validation_init2")).isFalse();
- }
-
- @Test
- public void do_filter_as_admin() throws IOException, ServletException {
- userSession.logIn().setSystemAdministrator();
- HttpServletRequest servletRequest = mock(HttpServletRequest.class);
- HttpServletResponse servletResponse = mock(HttpServletResponse.class);
- FilterChain filterChain = mock(FilterChain.class);
- String callbackUrl = "http://localhost:9000/api/validation_test";
- when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
- .thenReturn(callbackUrl);
-
- underTest.doFilter(servletRequest, servletResponse, filterChain);
-
- verify(samlAuthenticator).initLogin(matches(callbackUrl),
- matches(SamlValidationInitAction.VALIDATION_RELAY_STATE),
- any(), any());
- }
-
- @Test
- public void do_filter_as_not_admin() throws IOException, ServletException {
- userSession.logIn();
- HttpServletRequest servletRequest = mock(HttpServletRequest.class);
- HttpServletResponse servletResponse = mock(HttpServletResponse.class);
- FilterChain filterChain = mock(FilterChain.class);
- String callbackUrl = "http://localhost:9000/api/validation_test";
- when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
- .thenReturn(callbackUrl);
-
- underTest.doFilter(servletRequest, servletResponse, filterChain);
-
- verifyNoInteractions(samlAuthenticator);
- verify(servletResponse).sendRedirect(anyString());
- }
-
- @Test
- public void do_filter_as_anonymous() throws IOException, ServletException {
- userSession.anonymous();
- HttpServletRequest servletRequest = mock(HttpServletRequest.class);
- HttpServletResponse servletResponse = mock(HttpServletResponse.class);
- FilterChain filterChain = mock(FilterChain.class);
- String callbackUrl = "http://localhost:9000/api/validation_test";
- when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
- .thenReturn(callbackUrl);
-
- underTest.doFilter(servletRequest, servletResponse, filterChain);
-
- verifyNoInteractions(samlAuthenticator);
- verify(servletResponse).sendRedirect(anyString());
- }
-
- @Test
- public void verify_definition() {
- String controllerKey = "foo";
- WebService.Context context = new WebService.Context();
- WebService.NewController newController = context.createController(controllerKey);
- underTest.define(newController);
- newController.done();
-
- WebService.Action validationInitAction = context.controller(controllerKey).action("validation_init");
- assertThat(validationInitAction).isNotNull();
- assertThat(validationInitAction.description()).isNotEmpty();
- assertThat(validationInitAction.handler()).isNotNull();
- }
-}
--- /dev/null
+/*
+ * 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.api.server.ws.WebService;
+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 ValidationActionTest {
+
+ private ValidationAction 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 ValidationAction(userSession, samlAuthenticator, oAuth2ContextFactory);
+ }
+
+ @Test
+ public void do_get_pattern() {
+ assertThat(underTest.doGetPattern().matches("/saml/validation")).isTrue();
+ assertThat(underTest.doGetPattern().matches("/saml/validation2")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/api/saml/validation")).isFalse();
+ 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);
+ }
+
+ @Test
+ public void verify_definition() {
+ String controllerKey = "foo";
+ WebService.Context context = new WebService.Context();
+ WebService.NewController newController = context.createController(controllerKey);
+ underTest.define(newController);
+ newController.done();
+
+ WebService.Action validationInitAction = context.controller(controllerKey)
+ .action(ValidationAction.VALIDATION_CALLBACK_KEY);
+ assertThat(validationInitAction).isNotNull();
+ assertThat(validationInitAction.description()).isNotEmpty();
+ assertThat(validationInitAction.handler()).isNotNull();
+ }
+}
--- /dev/null
+/*
+ * 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.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.auth.saml.SamlAuthenticator;
+import org.sonar.server.authentication.OAuth2ContextFactory;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+public class ValidationInitActionTest {
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ private ValidationInitAction underTest;
+ private SamlAuthenticator samlAuthenticator;
+ private OAuth2ContextFactory oAuth2ContextFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ samlAuthenticator = mock(SamlAuthenticator.class);
+ oAuth2ContextFactory = mock(OAuth2ContextFactory.class);
+ underTest = new ValidationInitAction(samlAuthenticator, oAuth2ContextFactory, userSession);
+ }
+
+ @Test
+ public void do_get_pattern() {
+ assertThat(underTest.doGetPattern().matches("/saml/validation_init")).isTrue();
+ assertThat(underTest.doGetPattern().matches("/api/saml")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/api/saml/validation_init")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/saml/validation_init2")).isFalse();
+ }
+
+ @Test
+ public void do_filter_as_admin() throws IOException, ServletException {
+ userSession.logIn().setSystemAdministrator();
+ HttpServletRequest servletRequest = mock(HttpServletRequest.class);
+ HttpServletResponse servletResponse = mock(HttpServletResponse.class);
+ FilterChain filterChain = mock(FilterChain.class);
+ String callbackUrl = "http://localhost:9000/api/validation_test";
+ when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
+ .thenReturn(callbackUrl);
+
+ underTest.doFilter(servletRequest, servletResponse, filterChain);
+
+ verify(samlAuthenticator).initLogin(matches(callbackUrl),
+ matches(ValidationInitAction.VALIDATION_RELAY_STATE),
+ any(), any());
+ }
+
+ @Test
+ public void do_filter_as_not_admin() throws IOException, ServletException {
+ userSession.logIn();
+ HttpServletRequest servletRequest = mock(HttpServletRequest.class);
+ HttpServletResponse servletResponse = mock(HttpServletResponse.class);
+ FilterChain filterChain = mock(FilterChain.class);
+ String callbackUrl = "http://localhost:9000/api/validation_test";
+ when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
+ .thenReturn(callbackUrl);
+
+ underTest.doFilter(servletRequest, servletResponse, filterChain);
+
+ verifyNoInteractions(samlAuthenticator);
+ verify(servletResponse).sendRedirect(anyString());
+ }
+
+ @Test
+ public void do_filter_as_anonymous() throws IOException, ServletException {
+ userSession.anonymous();
+ HttpServletRequest servletRequest = mock(HttpServletRequest.class);
+ HttpServletResponse servletResponse = mock(HttpServletResponse.class);
+ FilterChain filterChain = mock(FilterChain.class);
+ String callbackUrl = "http://localhost:9000/api/validation_test";
+ when(oAuth2ContextFactory.generateCallbackUrl(anyString()))
+ .thenReturn(callbackUrl);
+
+ underTest.doFilter(servletRequest, servletResponse, filterChain);
+
+ verifyNoInteractions(samlAuthenticator);
+ verify(servletResponse).sendRedirect(anyString());
+ }
+
+ @Test
+ public void verify_definition() {
+ String controllerKey = "foo";
+ WebService.Context context = new WebService.Context();
+ WebService.NewController newController = context.createController(controllerKey);
+ underTest.define(newController);
+ newController.done();
+
+ WebService.Action validationInitAction = context.controller(controllerKey).action("validation_init");
+ assertThat(validationInitAction).isNotNull();
+ assertThat(validationInitAction.description()).isNotEmpty();
+ assertThat(validationInitAction.handler()).isNotNull();
+ }
+}