/* * SonarQube * Copyright (C) 2009-2017 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 it.user; import com.sonar.orchestrator.Orchestrator; import java.net.URLEncoder; import java.util.List; import javax.annotation.Nullable; import okhttp3.Response; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import util.user.UserRule; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.call; /** * Test SSO authentication (using HTTP headers). * <p> * It starts its own server as it's using a different authentication system */ public class SsoAuthenticationTest { private static final String LOGIN_HEADER = "H-Login"; private static final String NAME_HEADER = "H-Name"; private static final String EMAIL_HEADER = "H-Email"; private static final String GROUPS_HEADER = "H-Groups"; static final String USER_LOGIN = "tester"; static final String USER_NAME = "Tester"; static final String USER_EMAIL = "tester@email.com"; static final String GROUP_1 = "group-1"; static final String GROUP_2 = "group-2"; static final String GROUP_3 = "group-3"; @ClassRule public static final Orchestrator orchestrator = Orchestrator.builderEnv() .setServerProperty("sonar.web.sso.enable", "true") .setServerProperty("sonar.web.sso.loginHeader", LOGIN_HEADER) .setServerProperty("sonar.web.sso.nameHeader", NAME_HEADER) .setServerProperty("sonar.web.sso.emailHeader", EMAIL_HEADER) .setServerProperty("sonar.web.sso.groupsHeader", GROUPS_HEADER) .build(); @ClassRule public static UserRule USER_RULE = UserRule.from(orchestrator); @Before public void resetData() throws Exception { USER_RULE.resetUsers(); } @Test public void authenticate() { doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); USER_RULE.verifyUserExists(USER_LOGIN, USER_NAME, USER_EMAIL); } @Test public void authenticate_with_only_login() throws Exception { doCall(USER_LOGIN, null, null, null); USER_RULE.verifyUserExists(USER_LOGIN, USER_LOGIN, null); } @Test public void update_user_when_headers_are_updated() { doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); USER_RULE.verifyUserExists(USER_LOGIN, USER_NAME, USER_EMAIL); // As we don't keep the JWT token is the test, the user is updated doCall(USER_LOGIN, "new name", "new email", null); USER_RULE.verifyUserExists(USER_LOGIN, "new name", "new email"); } @Test public void authenticate_with_groups() { doCall(USER_LOGIN, null, null, GROUP_1); USER_RULE.verifyUserGroupMembership(USER_LOGIN, GROUP_1, "sonar-users"); } @Test public void synchronize_groups_when_authenticating_existing_user() throws Exception { USER_RULE.createGroup(GROUP_1); USER_RULE.createGroup(GROUP_2); USER_RULE.createGroup(GROUP_3); USER_RULE.createUser(USER_LOGIN, "password"); USER_RULE.associateGroupsToUser(USER_LOGIN, GROUP_1, GROUP_2); doCall(USER_LOGIN, null, null, GROUP_2 + "," + GROUP_3); USER_RULE.verifyUserGroupMembership(USER_LOGIN, GROUP_2, GROUP_3, "sonar-users"); } @Test public void authentication_with_local_user_is_possible_when_no_header() throws Exception { USER_RULE.createUser(USER_LOGIN, "password"); checkLocalAuthentication(USER_LOGIN, "password"); } @Test public void display_message_in_ui_but_not_in_log_when_unauthorized_exception() throws Exception { Response response = doCall("invalid login $", null, null, null); assertThat(response.code()).isEqualTo(200); assertThat(response.request().url().toString()).contains("sessions/unauthorized"); List<String> logsLines = FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8); assertThat(logsLines).doesNotContain("org.sonar.server.exceptions.BadRequestException: Use only letters, numbers, and .-_@ please."); USER_RULE.verifyUserDoesNotExist(USER_LOGIN); } @Test public void fail_when_email_already_exists() throws Exception { USER_RULE.createUser("another", "Another", USER_EMAIL, "another"); Response response = doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); String expectedError = "You can't sign up because email 'tester@email.com' is already used by an existing user. This means that you probably already registered with another account"; assertThat(response.code()).isEqualTo(200); assertThat(response.request().url().toString()).contains(URLEncoder.encode(expectedError, UTF_8.name())); assertThat(FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8)).doesNotContain(expectedError); } private static Response doCall(String login, @Nullable String name, @Nullable String email, @Nullable String groups) { return call(orchestrator.getServer().getUrl(), LOGIN_HEADER, login, NAME_HEADER, name, EMAIL_HEADER, email, GROUPS_HEADER, groups); } private boolean checkLocalAuthentication(String login, String password) { String result = orchestrator.getServer().wsClient(login, password).get("/api/authentication/validate"); return result.contains("{\"valid\":true}"); } }