From 0958d15fb30f976e53dfc7492f2f361aaa412f47 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 22 Mar 2016 12:48:42 +0100 Subject: [PATCH] SONAR-7448 Add ITs --- it/it-plugins/base-auth-plugin/pom.xml | 12 ++ .../src/main/java/FakeBaseIdProvider.java | 15 ++- .../it/user/BaseIdentityProviderTest.java | 70 ++++++++++- .../src/test/java/util/user/Groups.java | 53 ++++++++ .../src/test/java/util/user/UserRule.java | 119 ++++++++++++++++-- 5 files changed, 248 insertions(+), 21 deletions(-) create mode 100644 it/it-tests/src/test/java/util/user/Groups.java diff --git a/it/it-plugins/base-auth-plugin/pom.xml b/it/it-plugins/base-auth-plugin/pom.xml index 7c1077d65da..4e2f631194d 100644 --- a/it/it-plugins/base-auth-plugin/pom.xml +++ b/it/it-plugins/base-auth-plugin/pom.xml @@ -28,6 +28,18 @@ 3.0.1 provided + + com.google.guava + guava + 17.0 + + + + com.google.code.findbugs + jsr305 + + + diff --git a/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java b/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java index a7d897b137f..6a915d32b65 100644 --- a/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java +++ b/it/it-plugins/base-auth-plugin/src/main/java/FakeBaseIdProvider.java @@ -24,10 +24,15 @@ import org.sonar.api.server.authentication.Display; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; +import static com.google.common.collect.Sets.newHashSet; + public class FakeBaseIdProvider implements BaseIdentityProvider { private static final String ENABLED = "sonar.auth.fake-base-id-provider.enabled"; private static final String ALLOWS_USERS_TO_SIGN_UP = "sonar.auth.fake-base-id-provider.allowsUsersToSignUp"; + private static final String ENABLED_GROUPS_SYNC = "sonar.auth.fake-base-id-provider.enabledGroupsSync"; + private static final String GROUPS = "sonar.auth.fake-base-id-provider.groups"; + private static final String USER_INFO = "sonar.auth.fake-base-id-provider.user"; private static final String THROW_UNAUTHORIZED_EXCEPTION = "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage"; @@ -50,13 +55,17 @@ public class FakeBaseIdProvider implements BaseIdentityProvider { } String[] userInfos = userInfoProperty.split(","); - context.authenticate(UserIdentity.builder() + UserIdentity.Builder builder = UserIdentity.builder() .setLogin(userInfos[0]) .setProviderLogin(userInfos[1]) .setName(userInfos[2]) - .setEmail(userInfos[3]) - .build()); + .setEmail(userInfos[3]); + + if (settings.getBoolean(ENABLED_GROUPS_SYNC)) { + builder.setGroups(newHashSet(settings.getStringArray(GROUPS))); + } + context.authenticate(builder.build()); try { context.getResponse().sendRedirect("/"); } catch (IOException e) { diff --git a/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java b/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java index 734cda3c3a2..0c30d4471b6 100644 --- a/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java +++ b/it/it-tests/src/test/java/it/user/BaseIdentityProviderTest.java @@ -19,6 +19,7 @@ */ package it.user; +import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.selenium.Selenese; @@ -66,6 +67,10 @@ public class BaseIdentityProviderTest { static String USER_NAME_UPDATED = "John Doe"; static String USER_EMAIL_UPDATED = "john.doe@email.com"; + static String GROUP1 = "group1"; + static String GROUP2 = "group2"; + static String GROUP3 = "group3"; + static WsClient adminWsClient; @BeforeClass @@ -75,11 +80,14 @@ public class BaseIdentityProviderTest { } @After - public void removeUserAndCleanPluginProperties() throws Exception { + public void cleanUpUsersAndGroupsAndProperties() throws Exception { userRule.deactivateUsers(USER_LOGIN); + userRule.removeGroups(GROUP1, GROUP2, GROUP3); setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", null); setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.user", null); setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage", null); + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabledGroupsSync", null); + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.groups", null); } @Test @@ -200,18 +208,70 @@ public class BaseIdentityProviderTest { userRule.verifyUserDoesNotExist(USER_LOGIN); } + @Test + public void synchronize_groups_for_new_user() throws Exception { + enablePlugin(); + userRule.createGroup(GROUP1); + userRule.createGroup(GROUP2); + setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_NAME, USER_EMAIL); + // Group3 doesn't exist in DB, user won't belong to this group + setGroupsReturnedByAuthPlugin(GROUP1, GROUP2, GROUP3); + + authenticateWithFakeAuthProvider(); + + userRule.verifyUserGroupMembership(USER_LOGIN, GROUP1, GROUP2); + } + + @Test + public void synchronize_groups_for_existing_user() throws Exception { + enablePlugin(); + userRule.createGroup(GROUP1); + userRule.createGroup(GROUP2); + userRule.createGroup(GROUP3); + userRule.createUser(USER_LOGIN, "password"); + userRule.associateGroupsToUser(USER_LOGIN, GROUP1, GROUP2); + setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_NAME, USER_EMAIL); + // Group1 is not returned by the plugin, user won't belong anymore to this group + setGroupsReturnedByAuthPlugin(GROUP2, GROUP3); + + authenticateWithFakeAuthProvider(); + + userRule.verifyUserGroupMembership(USER_LOGIN, GROUP2, GROUP3); + } + + @Test + public void remove_user_groups_when_groups_provided_by_plugin_are_empty() throws Exception { + enablePlugin(); + userRule.createGroup(GROUP1); + userRule.createUser(USER_LOGIN, "password"); + userRule.associateGroupsToUser(USER_LOGIN, GROUP1); + setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_NAME, USER_EMAIL); + // No group is returned by the plugin + setGroupsReturnedByAuthPlugin(); + + authenticateWithFakeAuthProvider(); + + // User is not member to any group + userRule.verifyUserGroupMembership(USER_LOGIN); + } + + private static void enablePlugin() { + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", "true"); + } + private static void setUserCreatedByAuthPlugin(String login, String providerId, String name, String email) { setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.user", login + "," + providerId + "," + name + "," + email); } + private static void setGroupsReturnedByAuthPlugin(String... groups) { + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabledGroupsSync", "true"); + setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.groups", Joiner.on(",").join(groups)); + } + private static void authenticateWithFakeAuthProvider() { WsResponse response = adminWsClient.wsConnector().call( new GetRequest(("/sessions/init/" + FAKE_PROVIDER_KEY))); assertThat(response.code()).isEqualTo(200); } - private static void enablePlugin() { - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", "true"); - } - } diff --git a/it/it-tests/src/test/java/util/user/Groups.java b/it/it-tests/src/test/java/util/user/Groups.java new file mode 100644 index 00000000000..34f64b9c2c1 --- /dev/null +++ b/it/it-tests/src/test/java/util/user/Groups.java @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 util.user; + +import com.google.gson.Gson; +import java.util.List; + +public class Groups { + + private List groups; + + private Groups(List groups) { + this.groups = groups; + } + + public List getGroups() { + return groups; + } + + public static Groups parse(String json) { + Gson gson = new Gson(); + return gson.fromJson(json, Groups.class); + } + + public static class Group { + private final String name; + + private Group(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } +} diff --git a/it/it-tests/src/test/java/util/user/UserRule.java b/it/it-tests/src/test/java/util/user/UserRule.java index c1560a2c0f4..422863bc099 100644 --- a/it/it-tests/src/test/java/util/user/UserRule.java +++ b/it/it-tests/src/test/java/util/user/UserRule.java @@ -19,6 +19,7 @@ */ package util.user; +import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; @@ -26,7 +27,6 @@ import com.sonar.orchestrator.Orchestrator; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.assertj.core.api.Assertions; import org.junit.rules.ExternalResource; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.PostRequest; @@ -35,6 +35,7 @@ import org.sonarqube.ws.client.WsResponse; import static java.util.Arrays.asList; import static java.util.Objects.requireNonNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; import static util.ItUtils.newAdminWsClient; @@ -52,6 +53,10 @@ public class UserRule extends ExternalResource { return new UserRule(requireNonNull(orchestrator, "Orchestrator instance can not be null")); } + // ***************** + // Users + // ***************** + public void resetUsers() { for (Users.User user : getUsers().getUsers()) { String userLogin = user.getLogin(); @@ -61,25 +66,18 @@ public class UserRule extends ExternalResource { } } - private WsClient adminWsClient() { - if (adminWsClient == null) { - adminWsClient = newAdminWsClient(orchestrator); - } - return adminWsClient; - } - public Users.User verifyUserExists(String login, String name, @Nullable String email) { Optional user = getUserByLogin(login); assertThat(user).as("User with login '%s' hasn't been found", login).isPresent(); - Assertions.assertThat(user.get().getLogin()).isEqualTo(login); - Assertions.assertThat(user.get().getName()).isEqualTo(name); - Assertions.assertThat(user.get().getEmail()).isEqualTo(email); + assertThat(user.get().getLogin()).isEqualTo(login); + assertThat(user.get().getName()).isEqualTo(name); + assertThat(user.get().getEmail()).isEqualTo(email); return user.get(); } public void verifyUserExists(String login, String name, @Nullable String email, boolean local) { Users.User user = verifyUserExists(login, name, email); - Assertions.assertThat(user.isLocal()).isEqualTo(local); + assertThat(user.isLocal()).isEqualTo(local); } public void verifyUserDoesNotExist(String login) { @@ -106,7 +104,7 @@ public class UserRule extends ExternalResource { public Users getUsers() { WsResponse response = adminWsClient().wsConnector().call( new GetRequest("api/users/search")); - Assertions.assertThat(response.code()).isEqualTo(200); + assertThat(response.code()).isEqualTo(200); return Users.parse(response.content()); } @@ -124,6 +122,78 @@ public class UserRule extends ExternalResource { deactivateUsers(asList(userLogins)); } + // ***************** + // User groups + // ***************** + + public void createGroup(String name) { + createGroup(name, null); + } + + public void createGroup(String name, @Nullable String description) { + adminWsClient().wsConnector().call( + new PostRequest("api/user_groups/create") + .setParam("name", name) + .setParam("description", description)); + } + + public void removeGroups(List groupNames) { + for (String groupName : groupNames) { + if (getGroupByName(groupName).isPresent()) { + adminWsClient().wsConnector().call( + new PostRequest("api/user_groups/delete") + .setParam("name", groupName)); + } + } + } + + public void removeGroups(String... groupNames) { + removeGroups(asList(groupNames)); + } + + public Optional getGroupByName(String name) { + return FluentIterable.from(getGroups().getGroups()).firstMatch(new MatchGroupName(name)); + } + + public Groups getGroups() { + WsResponse response = adminWsClient().wsConnector().call( + new GetRequest("api/user_groups/search")); + assertThat(response.code()).isEqualTo(200); + return Groups.parse(response.content()); + } + + public void verifyUserGroupMembership(String userLogin, String... groups) { + Groups userGroup = getUserGroups(userLogin); + List userGroupName = FluentIterable.from(userGroup.getGroups()).transform(ToGroupName.INSTANCE).toList(); + assertThat(userGroupName).containsOnly(groups); + } + + public Groups getUserGroups(String userLogin) { + WsResponse response = adminWsClient().wsConnector().call( + new GetRequest("api/users/groups") + .setParam("login", userLogin) + .setParam("selected", "selected")); + assertThat(response.code()).isEqualTo(200); + return Groups.parse(response.content()); + } + + public void associateGroupsToUser(String userLogin, String... groups) { + for (String group : groups) { + WsResponse response = adminWsClient().wsConnector().call( + new PostRequest("api/user_groups/add_user") + .setParam("login", userLogin) + .setParam("name", group)); + assertThat(response.code()).isEqualTo(204); + } + } + + private WsClient adminWsClient() { + if (adminWsClient == null) { + adminWsClient = newAdminWsClient(orchestrator); + } + return adminWsClient; + } + private class MatchUserLogin implements Predicate { private final String login; @@ -137,4 +207,27 @@ public class UserRule extends ExternalResource { return login != null && login.equals(this.login) && user.isActive(); } } + + private class MatchGroupName implements Predicate { + private final String groupName; + + private MatchGroupName(String groupName) { + this.groupName = groupName; + } + + @Override + public boolean apply(@Nonnull Groups.Group group) { + String groupName = group.getName(); + return groupName != null && groupName.equals(this.groupName); + } + } + + private enum ToGroupName implements Function { + INSTANCE; + + @Override + public String apply(@Nonnull Groups.Group group) { + return group.getName(); + } + } } -- 2.39.5