<version>3.0.1</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>17.0</version>
+ <exclusions>
+ <exclusion>
+ <!-- should be declared with scope provided -->
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
<build>
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";
}
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) {
*/
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;
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
}
@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
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");
- }
-
}
--- /dev/null
+/*
+ * 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<Group> groups;
+
+ private Groups(List<Group> groups) {
+ this.groups = groups;
+ }
+
+ public List<Group> 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;
+ }
+ }
+}
*/
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;
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;
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;
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();
}
}
- private WsClient adminWsClient() {
- if (adminWsClient == null) {
- adminWsClient = newAdminWsClient(orchestrator);
- }
- return adminWsClient;
- }
-
public Users.User verifyUserExists(String login, String name, @Nullable String email) {
Optional<Users.User> 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) {
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());
}
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<String> 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<Groups.Group> 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<String> 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<Users.User> {
private final String login;
return login != null && login.equals(this.login) && user.isActive();
}
}
+
+ private class MatchGroupName implements Predicate<Groups.Group> {
+ 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<Groups.Group, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(@Nonnull Groups.Group group) {
+ return group.getName();
+ }
+ }
}