package org.sonar.server.permission.ws;
import java.util.Locale;
+import java.util.Optional;
import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsPermissions.Permission;
import org.sonarqube.ws.WsPermissions.WsSearchGlobalPermissionsResponse;
-import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
+import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdmin;
+import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createOrganizationParameter;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.WsPermissions.Permission.newBuilder;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
public class SearchGlobalPermissionsAction implements PermissionsWsAction {
+
+ public static final String ACTION = "search_global_permissions";
private static final String PROPERTY_PREFIX = "global_permissions.";
private static final String DESCRIPTION_SUFFIX = ".desc";
private final DbClient dbClient;
private final UserSession userSession;
private final I18n i18n;
+ private final PermissionWsSupport support;
- public SearchGlobalPermissionsAction(DbClient dbClient, UserSession userSession, I18n i18n) {
+ public SearchGlobalPermissionsAction(DbClient dbClient, UserSession userSession, I18n i18n, PermissionWsSupport support) {
this.dbClient = dbClient;
this.userSession = userSession;
this.i18n = i18n;
+ this.support = support;
}
@Override
public void define(WebService.NewController context) {
- context.createAction("search_global_permissions")
+ WebService.NewAction action = context.createAction(ACTION)
.setDescription("List global permissions. <br />" +
"It requires administration permissions to access.")
.setResponseExample(getClass().getResource("search_global_permissions-example.json"))
.setSince("5.2")
.setHandler(this);
+
+ createOrganizationParameter(action);
}
@Override
public void handle(Request wsRequest, Response wsResponse) throws Exception {
- checkGlobalAdminUser(userSession);
-
try (DbSession dbSession = dbClient.openSession(false)) {
- WsSearchGlobalPermissionsResponse response = buildResponse(dbSession);
+ OrganizationDto org = support.findOrganization(dbSession, wsRequest.param(PARAM_ORGANIZATION_KEY));
+ checkProjectAdmin(userSession, org.getUuid(), Optional.empty());
+
+ WsSearchGlobalPermissionsResponse response = buildResponse(dbSession, org);
writeProtobuf(response, wsRequest, wsResponse);
}
}
- private WsSearchGlobalPermissionsResponse buildResponse(DbSession dbSession) {
+ private WsSearchGlobalPermissionsResponse buildResponse(DbSession dbSession, OrganizationDto org) {
WsSearchGlobalPermissionsResponse.Builder response = WsSearchGlobalPermissionsResponse.newBuilder();
Permission.Builder permission = newBuilder();
.setKey(permissionKey)
.setName(i18nName(permissionKey))
.setDescription(i18nDescriptionMessage(permissionKey))
- .setUsersCount(countUsers(dbSession, permissionQuery))
- .setGroupsCount(countGroups(dbSession, permissionKey)));
+ .setUsersCount(countUsers(dbSession, org, permissionQuery))
+ .setGroupsCount(countGroups(dbSession, org, permissionKey)));
}
return response.build();
return i18n.message(Locale.ENGLISH, PROPERTY_PREFIX + permissionKey, permissionKey);
}
- private int countGroups(DbSession dbSession, String permissionKey) {
- return dbClient.groupPermissionDao().countGroups(dbSession, permissionKey, null);
+ private int countGroups(DbSession dbSession, OrganizationDto org, String permission) {
+ PermissionQuery query = PermissionQuery.builder().setPermission(permission).build();
+ return dbClient.groupPermissionDao().countGroupsByQuery(dbSession, org.getUuid(), query);
}
- private int countUsers(DbSession dbSession, PermissionQuery permissionQuery) {
- return dbClient.userPermissionDao().countUsers(dbSession, permissionQuery);
+ private int countUsers(DbSession dbSession, OrganizationDto org, PermissionQuery permissionQuery) {
+ return dbClient.userPermissionDao().countUsers(dbSession, org.getUuid(), permissionQuery);
}
private static PermissionQuery permissionQuery(String permissionKey) {
import org.sonar.api.utils.Paging;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.permission.ExtendedUserPermissionDto;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.permission.ProjectId;
import org.sonar.server.user.UserSession;
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdmin;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateGlobalPermission;
import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPermission;
+import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createOrganizationParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION_KEY;
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
public class UsersAction implements PermissionsWsAction {
.setDescription("Limit search to user names that contain the supplied string. Must have at least %d characters.<br/>" +
"When this parameter is not set, only users having at least one permission are returned.", SEARCH_QUERY_MIN_LENGTH)
.setExampleValue("eri");
+
+ createOrganizationParameter(action);
createPermissionParameter(action).setRequired(false);
createProjectParameters(action);
}
@Override
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
+ OrganizationDto org = support.findOrganization(dbSession, request.param(PARAM_ORGANIZATION_KEY));
Optional<ProjectId> projectId = support.findProject(dbSession, request);
- checkProjectAdmin(userSession, projectId);
+ checkProjectAdmin(userSession, org.getUuid(), projectId);
PermissionQuery query = buildPermissionQuery(request, projectId);
- List<UserDto> users = findUsers(dbSession, query);
- int total = dbClient.userPermissionDao().countUsers(dbSession, query);
- List<ExtendedUserPermissionDto> userPermissions = findUserPermissions(dbSession, users, projectId);
+ List<UserDto> users = findUsers(dbSession, org, query);
+ int total = dbClient.userPermissionDao().countUsers(dbSession, org.getUuid(), query);
+ List<UserPermissionDto> userPermissions = findUserPermissions(dbSession, org, users, projectId);
Paging paging = Paging.forPageIndex(request.mandatoryParamAsInt(Param.PAGE)).withPageSize(query.getPageSize()).andTotal(total);
UsersWsResponse usersWsResponse = buildResponse(users, userPermissions, paging);
writeProtobuf(usersWsResponse, request, response);
return permissionQuery.build();
}
- private static UsersWsResponse buildResponse(List<UserDto> users, List<ExtendedUserPermissionDto> userPermissions, Paging paging) {
+ private static UsersWsResponse buildResponse(List<UserDto> users, List<UserPermissionDto> userPermissions, Paging paging) {
Multimap<Long, String> permissionsByUserId = TreeMultimap.create();
userPermissions.forEach(userPermission -> permissionsByUserId.put(userPermission.getUserId(), userPermission.getPermission()));
return response.build();
}
- private List<UserDto> findUsers(DbSession dbSession, PermissionQuery query) {
- List<String> orderedLogins = dbClient.userPermissionDao().selectLogins(dbSession, query);
- return Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin).immutableSortedCopy(dbClient.userDao().selectByLogins(dbSession, orderedLogins));
+ private List<UserDto> findUsers(DbSession dbSession, OrganizationDto org, PermissionQuery query) {
+ List<Long> orderedIds = dbClient.userPermissionDao().selectUserIds(dbSession, org.getUuid(), query);
+ return Ordering.explicit(orderedIds).onResultOf(UserDto::getId).immutableSortedCopy(dbClient.userDao().selectByIds(dbSession, orderedIds));
}
- private List<ExtendedUserPermissionDto> findUserPermissions(DbSession dbSession, List<UserDto> users, Optional<ProjectId> project) {
+ private List<UserPermissionDto> findUserPermissions(DbSession dbSession, OrganizationDto org, List<UserDto> users, Optional<ProjectId> project) {
if (users.isEmpty()) {
return emptyList();
}
.setComponentUuid(project.isPresent() ? project.get().getUuid() : null)
.withAtLeastOnePermission()
.build();
- return dbClient.userPermissionDao().select(dbSession, query, logins);
+ return dbClient.userPermissionDao().select(dbSession, org.getUuid(), query, logins);
}
}
executeRequest(rootByUserPermissionUser, SYSTEM_ADMIN, otherOrganization);
db.rootFlag().verify(notRootUser, false);
- db.rootFlag().verifyUnchanged(rootByUserPermissionUser); // because already has specified permission
+ db.rootFlag().verify(rootByUserPermissionUser, true);
db.rootFlag().verifyUnchanged(rootByGroupPermissionUser);
executeRequest(rootByGroupPermissionUser, SYSTEM_ADMIN, otherOrganization);
db.rootFlag().verify(notRootUser, false);
- db.rootFlag().verifyUnchanged(rootByUserPermissionUser);
+ db.rootFlag().verify(rootByUserPermissionUser, true);
db.rootFlag().verify(rootByGroupPermissionUser, true);
}
loginAsAdmin(db.getDefaultOrganization());
}
- protected void loginAsAdmin(OrganizationDto org) {
+ protected void loginAsAdmin(OrganizationDto org, OrganizationDto... otherOrgs) {
userSession.login().addOrganizationPermission(org.getUuid(), SYSTEM_ADMIN);
+ for (OrganizationDto otherOrg : otherOrgs) {
+ userSession.addOrganizationPermission(otherOrg.getUuid(), SYSTEM_ADMIN);
+ }
}
protected PermissionTemplateDto selectTemplateInDefaultOrganization(String name) {
*/
package org.sonar.server.permission.ws;
-import java.io.IOException;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupTesting;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTesting;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.i18n.I18nRule;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.WsPermissions;
import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
+import static org.sonar.server.permission.ws.SearchGlobalPermissionsAction.ACTION;
import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.CONTROLLER;
-public class SearchGlobalPermissionsActionTest {
+public class SearchGlobalPermissionsActionTest extends BasePermissionWsTest<SearchGlobalPermissionsAction> {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- private WsActionTester ws;
private I18nRule i18n = new I18nRule();
+ @Override
+ protected SearchGlobalPermissionsAction buildWsAction() {
+ return new SearchGlobalPermissionsAction(db.getDbClient(), userSession, i18n, newPermissionWsSupport());
+ }
+
@Before
public void setUp() {
initI18nMessages();
-
- ws = new WsActionTester(new SearchGlobalPermissionsAction(db.getDbClient(), userSession, i18n));
- userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
}
@Test
- public void search() {
- GroupDto adminGroup = db.users().insertGroup(newGroupDto("sonar-admins", "Administrators"));
- GroupDto userGroup = db.users().insertGroup(newGroupDto("sonar-users", "Users"));
- db.users().insertPermissionOnAnyone(SCAN_EXECUTION);
+ public void search_in_organization() throws Exception {
+ OrganizationDto org = db.organizations().insert(newOrganizationDto());
+ loginAsAdmin(org);
+ GroupDto adminGroup = db.users().insertGroup(newGroup(org, "sonar-admins", "Administrators"));
+ GroupDto userGroup = db.users().insertGroup(newGroup(org, "sonar-users", "Users"));
+ db.users().insertPermissionOnAnyone(org, SCAN_EXECUTION);
db.users().insertPermissionOnGroup(userGroup, SCAN_EXECUTION);
db.users().insertPermissionOnGroup(userGroup, PROVISIONING);
db.users().insertPermissionOnGroup(adminGroup, SYSTEM_ADMIN);
UserDto user = db.users().insertUser(newUserDto("user", "user-name"));
UserDto adminUser = db.users().insertUser(newUserDto("admin", "admin-name"));
- db.users().insertPermissionOnUser(user, PROVISIONING);
- db.users().insertPermissionOnUser(user, QUALITY_PROFILE_ADMIN);
- db.users().insertPermissionOnUser(adminUser, QUALITY_PROFILE_ADMIN);
- db.users().insertPermissionOnUser(user, QUALITY_GATE_ADMIN);
- db.users().insertPermissionOnUser(adminUser, QUALITY_GATE_ADMIN);
+ db.users().insertPermissionOnUser(org, user, PROVISIONING);
+ db.users().insertPermissionOnUser(org, user, QUALITY_PROFILE_ADMIN);
+ db.users().insertPermissionOnUser(org, adminUser, QUALITY_PROFILE_ADMIN);
+ db.users().insertPermissionOnUser(org, user, QUALITY_GATE_ADMIN);
+ db.users().insertPermissionOnUser(org, adminUser, QUALITY_GATE_ADMIN);
- String result = ws.newRequest().execute().getInput();
+ // to be excluded, permission on another organization (the default one)
+ db.users().insertPermissionOnUser(db.getDefaultOrganization(), adminUser, QUALITY_GATE_ADMIN);
+
+ String result = wsTester.newPostRequest(CONTROLLER, ACTION)
+ .setParam("organization", org.getKey())
+ .execute()
+ .outputAsString();
assertJson(result).isSimilarTo(getClass().getResource("search_global_permissions-example.json"));
}
@Test
- public void protobuf_response() throws IOException {
+ public void search_in_default_organization_by_default() throws Exception {
+ OrganizationDto org = db.organizations().insert(newOrganizationDto());
+ loginAsAdmin(org, db.getDefaultOrganization());
+
+ UserDto user = db.users().insertUser();
+ db.users().insertPermissionOnUser(db.getDefaultOrganization(), user, SCAN_EXECUTION);
+
+ // to be ignored, by default organization is used when searching for permissions
+ db.users().insertPermissionOnUser(org, user, QUALITY_GATE_ADMIN);
+
WsPermissions.WsSearchGlobalPermissionsResponse result = WsPermissions.WsSearchGlobalPermissionsResponse.parseFrom(
- ws.newRequest()
+ wsTester.newPostRequest(CONTROLLER, ACTION)
.setMediaType(MediaTypes.PROTOBUF)
- .execute().getInputStream());
+ .execute()
+ .output());
+
+ assertThat(result.getPermissionsCount()).isEqualTo(GlobalPermissions.ALL.size());
+ for (WsPermissions.Permission permission : result.getPermissionsList()) {
+ if (permission.getKey().equals(SCAN_EXECUTION)) {
+ assertThat(permission.getUsersCount()).isEqualTo(1);
+ } else {
+ assertThat(permission.getUsersCount()).isEqualTo(0);
+ }
+ }
+ }
+
+ @Test
+ public void supports_protobuf_response() throws Exception {
+ loginAsAdminOnDefaultOrganization();
+
+ WsPermissions.WsSearchGlobalPermissionsResponse result = WsPermissions.WsSearchGlobalPermissionsResponse.parseFrom(
+ wsTester.newPostRequest(CONTROLLER, ACTION)
+ .setMediaType(MediaTypes.PROTOBUF)
+ .execute()
+ .output());
assertThat(result).isNotNull();
}
@Test
- public void fail_if_insufficient_privileges() {
- userSession.login("login");
+ public void fail_if_not_admin_of_default_organization() throws Exception {
+ userSession.login();
expectedException.expect(ForbiddenException.class);
- ws.newRequest().execute();
+ wsTester.newPostRequest(CONTROLLER, ACTION)
+ .execute();
}
@Test
- public void fail_if_not_logged_in() {
+ public void fail_if_not_admin_of_specified_organization() throws Exception {
+ OrganizationDto org = db.organizations().insert(newOrganizationDto());
+ loginAsAdminOnDefaultOrganization();
+
+ expectedException.expect(ForbiddenException.class);
+
+ wsTester.newPostRequest(CONTROLLER, ACTION)
+ .setParam("organization", org.getKey())
+ .execute();
+ }
+
+ @Test
+ public void fail_if_not_logged_in() throws Exception {
userSession.anonymous();
expectedException.expect(UnauthorizedException.class);
- ws.newRequest().execute();
+ wsTester.newPostRequest(CONTROLLER, ACTION).execute();
+ }
+
+ @Test
+ public void fail_if_organization_does_not_exist() throws Exception {
+ expectedException.expect(NotFoundException.class);
+
+ wsTester.newPostRequest(CONTROLLER, ACTION)
+ .setParam("organization", "does_not_exist")
+ .execute();
}
private void initI18nMessages() {
return UserTesting.newUserDto().setLogin(login).setName(name).setActive(true);
}
- private static GroupDto newGroupDto(String name, String description) {
- return GroupTesting.newGroupDto().setName(name).setDescription(description);
+ private static GroupDto newGroup(OrganizationDto org, String name, String description) {
+ return GroupTesting.newGroupDto().setName(name).setDescription(description).setOrganizationUuid(org.getUuid());
}
}
db.users().insertPermissionOnUser(user1, QUALITY_PROFILE_ADMIN);
db.users().insertPermissionOnUser(user2, SCAN_EXECUTION);
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest().execute().outputAsString();
assertJson(result).withStrictArrayOrder().isSimilarTo(getClass().getResource("users-example.json"));
public void search_for_users_with_one_permission() throws Exception {
insertUsersHavingGlobalPermissions();
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest().setParam("permission", "scan").execute().outputAsString();
assertJson(result).withStrictArrayOrder().isSimilarTo(getClass().getResource("UsersActionTest/users.json"));
// User has no permission
UserDto withoutPermission = db.users().insertUser(newUserDto());
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest()
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute()
}
@Test
- public void search_also_for_users_without_permission_when_search_query() throws Exception {
+ public void search_also_for_users_without_permission_when_filtering_name() throws Exception {
// User with permission on project
ComponentDto project = db.components().insertComponent(newProjectDto());
UserDto user = db.users().insertUser(newUserDto("with-permission", "with-permission", null));
UserDto withoutPermission = db.users().insertUser(newUserDto("without-permission", "without-permission", null));
UserDto anotherUser = db.users().insertUser(newUserDto("another-user", "another-user", null));
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest()
.setParam(PARAM_PROJECT_ID, project.uuid())
.setParam(TEXT_QUERY, "with")
.execute()
.outputAsString();
- assertThat(result).contains(user.getLogin())
+ assertThat(result)
+ .contains(user.getLogin())
.contains(withoutPermission.getLogin())
.doesNotContain(anotherUser.getLogin());
}
public void search_for_users_with_query_as_a_parameter() throws Exception {
insertUsersHavingGlobalPermissions();
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest()
.setParam("permission", "scan")
.setParam(TEXT_QUERY, "ame-1")
public void search_for_users_with_select_as_a_parameter() throws Exception {
insertUsersHavingGlobalPermissions();
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
String result = newRequest()
.execute()
.outputAsString();
@Test
public void fail_if_project_permission_without_project() throws Exception {
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
expectedException.expect(BadRequestException.class);
@Test
public void fail_if_project_uuid_and_project_key_are_provided() throws Exception {
db.components().insertComponent(newProjectDto("project-uuid").setKey("project-key"));
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Project id or project key can be provided, not both.");
@Test
public void fail_if_search_query_is_too_short() throws Exception {
- loginAsAdmin();
+ loginAsAdminOnDefaultOrganization();
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("The 'q' parameter must have at least 3 characters");
private WsTester.TestRequest newRequest() {
return wsTester.newPostRequest(CONTROLLER, "users");
}
-
- private void loginAsAdmin() {
- userSession.login("login").setGlobalPermissions(SYSTEM_ADMIN);
- }
}
assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
- assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getLogin());
- assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getLogin());
+ assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
+ assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
authorizationIndexerTester.verifyProjectExistsWithPermission(project.uuid(), singletonList(group2.getName()), Collections.emptyList());
}
return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), db.getDefaultOrganization().getUuid(), query);
}
- private List<String> selectProjectPermissionUsers(ComponentDto project, String permission) {
+ private List<Long> selectProjectPermissionUsers(ComponentDto project, String permission) {
PermissionQuery query = PermissionQuery.builder().setPermission(permission).setComponentUuid(project.uuid()).build();
- return db.getDbClient().userPermissionDao().selectLogins(db.getSession(), query);
+ return db.getDbClient().userPermissionDao().selectUserIds(db.getSession(), db.getDefaultOrganization().getUuid(), query);
}
}
assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
- assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getLogin());
- assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getLogin());
+ assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
+ assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
}
private void assertNoPermissionOnProject(ComponentDto project) throws Exception {
return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), db.getDefaultOrganization().getUuid(), query);
}
- private List<String> selectProjectPermissionUsers(ComponentDto project, String permission) {
+ private List<Long> selectProjectPermissionUsers(ComponentDto project, String permission) {
PermissionQuery query = PermissionQuery.builder().setPermission(permission).setComponentUuid(project.uuid()).build();
- return db.getDbClient().userPermissionDao().selectLogins(db.getSession(), query);
+ return db.getDbClient().userPermissionDao().selectUserIds(db.getSession(), db.getDefaultOrganization().getUuid(), query);
}
private WsTester.TestRequest newRequest() {
+++ /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 org.sonar.db.permission;
-
-import javax.annotation.CheckForNull;
-
-/**
- * Temporary replacement of {@link UserPermissionDto} as long as tables group_roles
- * and user_roles do not have project UUID/user login but project ID/user ID.
- */
-public class ExtendedUserPermissionDto {
-
- private long userId;
- private Long componentId;
- private String permission;
-
- // join columns
- private String userLogin;
- private String componentUuid;
-
- public long getUserId() {
- return userId;
- }
-
- @CheckForNull
- public Long getComponentId() {
- return componentId;
- }
-
- /**
- * Permission can be null when {@link PermissionQuery#withAtLeastOnePermission()} is false.
- */
- @CheckForNull
- public String getPermission() {
- return permission;
- }
-
- public String getUserLogin() {
- return userLogin;
- }
-
- @CheckForNull
- public String getComponentUuid() {
- return componentUuid;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("ExtendedUserPermissionDto{");
- sb.append("userId=").append(userId);
- sb.append(", componentId=").append(componentId);
- sb.append(", permission='").append(permission).append('\'');
- sb.append(", userLogin='").append(userLogin).append('\'');
- sb.append(", componentUuid='").append(componentUuid).append('\'');
- sb.append('}');
- return sb.toString();
- }
-}
public class GroupPermissionDao implements Dao {
- private static final String COMPONENT_ID_PARAMETER = "componentId";
private static final String ANYONE_GROUP_PARAMETER = "anyoneGroup";
- /**
- * @deprecated not compatible with organizations.
- */
- @Deprecated
- public int countGroups(DbSession session, String permission, @Nullable Long componentId) {
- Map<String, Object> parameters = new HashMap<>();
- parameters.put("permission", permission);
- parameters.put(ANYONE_GROUP_PARAMETER, DefaultGroups.ANYONE);
- parameters.put(COMPONENT_ID_PARAMETER, componentId);
-
- return mapper(session).countGroups(parameters);
- }
-
/**
* Returns the names of the groups that match the given query, for the given organization.
* The virtual group "Anyone" may be returned as the value {@link DefaultGroups#ANYONE}.
public interface GroupPermissionMapper {
- /**
- * @deprecated does not support organizations
- */
- @Deprecated
- int countGroups(Map<String, Object> parameters);
-
List<String> selectGroupNamesByQuery(@Param("organizationUuid") String organizationUuid, @Param("query") PermissionQuery query, RowBounds rowBounds);
int countGroupsByQuery(@Param("organizationUuid") String organizationUuid, @Param("query") PermissionQuery query);
import java.util.Collection;
import java.util.List;
-import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.ibatis.session.RowBounds;
+import org.sonar.core.util.stream.Collectors;
import org.sonar.db.Dao;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbSession;
public class UserPermissionDao implements Dao {
/**
- * @see UserPermissionMapper#selectByQuery(PermissionQuery, Collection, RowBounds)
+ * List of user permissions ordered by alphabetical order of user names
+ *
+ * @param query non-null query including optional filters.
+ * @param userLogins if null, then filter on all active users. If not null, then filter on logins, including disabled users.
+ * Must not be empty. If not null then maximum size is {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE}.
*/
- public List<ExtendedUserPermissionDto> select(DbSession dbSession, PermissionQuery query, @Nullable Collection<String> userLogins) {
+ public List<UserPermissionDto> select(DbSession dbSession, String organizationUuid, PermissionQuery query, @Nullable Collection<String> userLogins) {
if (userLogins != null) {
if (userLogins.isEmpty()) {
return emptyList();
}
RowBounds rowBounds = new RowBounds(query.getPageOffset(), query.getPageSize());
- return mapper(dbSession).selectByQuery(query, userLogins, rowBounds);
+ return mapper(dbSession).selectByQuery(organizationUuid, query, userLogins, rowBounds);
}
/**
- * Shortcut over {@link #select(DbSession, PermissionQuery, Collection)} to return only logins, in the same order.
+ * Shortcut over {@link #select(DbSession, String, PermissionQuery, Collection)} to return only distinct user
+ * ids, keeping the same order.
*/
- public List<String> selectLogins(DbSession dbSession, PermissionQuery query) {
- return select(dbSession, query, null).stream()
- .map(ExtendedUserPermissionDto::getUserLogin)
+ public List<Long> selectUserIds(DbSession dbSession, String organizationUuid, PermissionQuery query) {
+ List<UserPermissionDto> dtos = select(dbSession, organizationUuid, query, null);
+ return dtos.stream()
+ .map(UserPermissionDto::getUserId)
.distinct()
- .collect(Collectors.toList());
+ .collect(Collectors.toList(dtos.size()));
}
/**
- * @see UserPermissionMapper#countUsersByQuery(PermissionQuery, Collection)
+ * @see UserPermissionMapper#countUsersByQuery(String, PermissionQuery, Collection)
*/
- public int countUsers(DbSession dbSession, PermissionQuery query) {
- return mapper(dbSession).countUsersByQuery(query, null);
+ public int countUsers(DbSession dbSession, String organizationUuid, PermissionQuery query) {
+ return mapper(dbSession).countUsersByQuery(organizationUuid, query, null);
}
/**
public interface UserPermissionMapper {
- /**
- * List of user permissions ordered by alphabetical order of user names
- *
- * @param query non-null query including optional filters.
- * @param userLogins if null, then filter on all active users. If not null, then filter on logins, including disabled users.
- * Must not be empty. If not null then maximum size is {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE}.
- */
- List<ExtendedUserPermissionDto> selectByQuery(@Param("query") PermissionQuery query, @Nullable @Param("userLogins") Collection<String> userLogins, RowBounds rowBounds);
+ List<UserPermissionDto> selectByQuery(@Param("organizationUuid") String organizationUuid, @Param("query") PermissionQuery query, @Nullable @Param("userLogins") Collection<String> userLogins, RowBounds rowBounds);
/**
- * Count the number of distinct users returned by {@link #selectByQuery(PermissionQuery, Collection, RowBounds)}
+ * Count the number of distinct users returned by {@link #selectByQuery(String, PermissionQuery, Collection, RowBounds)}
* {@link PermissionQuery#getPageOffset()} and {@link PermissionQuery#getPageSize()} are ignored.
*
- * @param useNull must always be null. It is needed for using the sql of {@link #selectByQuery(PermissionQuery, Collection, RowBounds)}
+ * @param useNull must always be null. It is needed for using the sql of {@link #selectByQuery(String, PermissionQuery, Collection, RowBounds)}
*/
- int countUsersByQuery(@Param("query") PermissionQuery query, @Nullable @Param("userLogins") Collection<String> useNull);
+ int countUsersByQuery(@Param("organizationUuid") String organizationUuid, @Param("query") PermissionQuery query, @Nullable @Param("userLogins") Collection<String> useNull);
/**
* Count the number of users per permission for a given list of projects.
GROUP BY groups.permission, groups.componentId
</select>
- <select id="countGroups" parameterType="map" resultType="int">
- SELECT count(1)
- FROM
- (SELECT g.name as name
- FROM groups g
- INNER JOIN group_roles group_role ON group_role.group_id=g.id
- AND group_role.role=#{permission,jdbcType=VARCHAR}
- <if test="componentId != null">
- AND group_role.resource_id=#{componentId,jdbcType=BIGINT}
- </if>
- <if test="componentId == null">
- AND group_role.resource_id IS NULL
- </if>
- UNION
- -- Add Anyone group permission
- SELECT #{anyoneGroup} as name
- FROM group_roles group_role
- where
- group_role.role=#{permission,jdbcType=VARCHAR}
- AND group_role.group_id IS NULL
- <if test="componentId != null">
- AND group_role.resource_id=#{componentId,jdbcType=BIGINT}
- </if>
- <if test="componentId == null">
- AND group_role.resource_id IS NULL
- </if>
- ) groups
- </select>
-
<select id="selectGroupNamesByQuery" parameterType="map" resultType="string">
select distinct sub.name, lower(sub.name), sub.groupId
<include refid="groupsByQuery" />
<mapper namespace="org.sonar.db.permission.UserPermissionMapper">
- <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.permission.ExtendedUserPermissionDto">
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.permission.UserPermissionDto">
select
u.id as userId,
ur.organization_uuid as organizationUuid,
ur.resource_id as componentId,
- ur.role as permission,
- u.login as userLogin,
- p.uuid as componentUuid
+ ur.role as permission
<include refid="sqlQuery" />
order by lower(u.name), u.name, ur.role
</select>
</if>
<!-- filter rows with user permissions -->
<if test="query.withAtLeastOnePermission()">
+ and ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR}
and ur.role is not null
<if test="query.componentUuid==null">
and ur.resource_id is null
@Test
public void select_global_permissions() {
+ OrganizationDto org2 = dbTester.organizations().insert(newOrganizationDto());
UserPermissionDto global1 = addGlobalPermissionOnDefaultOrganization(SYSTEM_ADMIN, user1);
UserPermissionDto global2 = addGlobalPermissionOnDefaultOrganization(SYSTEM_ADMIN, user2);
UserPermissionDto global3 = addGlobalPermissionOnDefaultOrganization(PROVISIONING, user2);
UserPermissionDto project1Perm = addProjectPermissionOnDefaultOrganization(USER, user3, project1);
+ // permissions on another organization, to be excluded
+ UserPermissionDto org2Global1 = addGlobalPermission(org2, SYSTEM_ADMIN, user1);
+ UserPermissionDto org2Global2 = addGlobalPermission(org2, PROVISIONING, user2);
// global permissions of users who has at least one global permission, ordered by user name then permission
PermissionQuery query = PermissionQuery.builder().withAtLeastOnePermission().build();
expectPermissions(query, null, global2, global3, global1);
- // default query returns all permissions
+ // default query returns all users, whatever their permissions nor organizations
+ // (that's a non-sense, but still this is required for api/permissions/groups
+ // when filtering users by name)
query = PermissionQuery.builder().build();
- expectPermissions(query, null, project1Perm, global2, global3, global1);
+ expectPermissions(query, null, project1Perm, global2, global3, org2Global2, global1, org2Global1);
// return empty list if non-null but empty logins
expectPermissions(query, Collections.emptyList());
}
@Test
- public void selectLogins() {
- addProjectPermissionOnDefaultOrganization(USER, user1, project1);
- addProjectPermissionOnDefaultOrganization(USER, user2, project1);
- addProjectPermissionOnDefaultOrganization(ISSUE_ADMIN, user2, project1);
- addProjectPermissionOnDefaultOrganization(ISSUE_ADMIN, user2, project2);
+ public void selectUserIds() {
+ OrganizationDto org1 = dbTester.organizations().insert(newOrganizationDto());
+ OrganizationDto org2 = dbTester.organizations().insert(newOrganizationDto());
+
+ addProjectPermission(org1, USER, user1, project1);
+ addProjectPermission(org1, USER, user2, project1);
+ addProjectPermission(org2, USER, user1, project2);
+ addProjectPermission(org1, ISSUE_ADMIN, user2, project1);
+ addProjectPermission(org2, ISSUE_ADMIN, user2, project2);
// logins are ordered by user name: user2 ("Marie") then user1 ("Marius")
PermissionQuery query = PermissionQuery.builder().setComponentUuid(project1.uuid()).withAtLeastOnePermission().build();
- List<String> logins = underTest.selectLogins(dbSession, query);
- assertThat(logins).containsExactly(user2.getLogin(), user1.getLogin());
+ assertThat(underTest.selectUserIds(dbSession, org1.getUuid(), query)).containsExactly(user2.getId(), user1.getId());
+ assertThat(underTest.selectUserIds(dbSession, "otherOrg", query)).isEmpty();
// on a project without permissions
query = PermissionQuery.builder().setComponentUuid("missing").withAtLeastOnePermission().build();
- assertThat(underTest.selectLogins(dbSession, query)).isEmpty();
+ assertThat(underTest.selectUserIds(dbSession, org1.getUuid(), query)).isEmpty();
+
+ // search all users whose name matches "mar", whatever the permissions
+ query = PermissionQuery.builder().setSearchQuery("mar").build();
+ assertThat(underTest.selectUserIds(dbSession, org1.getUuid(), query)).containsExactly(user2.getId(), user1.getId());
+
+ // search all users whose name matches "mariu", whatever the permissions
+ query = PermissionQuery.builder().setSearchQuery("mariu").build();
+ assertThat(underTest.selectUserIds(dbSession, org1.getUuid(), query)).containsExactly(user1.getId());
+
+ // search all users whose name matches "mariu", whatever the permissions
+ query = PermissionQuery.builder().setSearchQuery("mariu").setComponentUuid(project1.uuid()).build();
+ assertThat(underTest.selectUserIds(dbSession, org1.getUuid(), query)).containsExactly(user1.getId());
+
+ // search all users whose name matches "mariu", whatever the organization
+ query = PermissionQuery.builder().setSearchQuery("mariu").build();
+ assertThat(underTest.selectUserIds(dbSession, "missingOrg", query)).containsExactly(user1.getId());
}
@Test
}
private void expectPermissions(PermissionQuery query, @Nullable Collection<String> logins, UserPermissionDto... expected) {
+ expectPermissions(dbTester.getDefaultOrganization(), query, logins, expected);
+ }
+
+ private void expectPermissions(OrganizationDto org, PermissionQuery query, @Nullable Collection<String> logins, UserPermissionDto... expected) {
// test method "select()"
- List<ExtendedUserPermissionDto> permissions = underTest.select(dbSession, query, logins);
+ List<UserPermissionDto> permissions = underTest.select(dbSession, org.getUuid(), query, logins);
assertThat(permissions).hasSize(expected.length);
for (int i = 0; i < expected.length; i++) {
- ExtendedUserPermissionDto got = permissions.get(i);
+ UserPermissionDto got = permissions.get(i);
UserPermissionDto expect = expected[i];
assertThat(got.getUserId()).isEqualTo(expect.getUserId());
assertThat(got.getPermission()).isEqualTo(expect.getPermission());
assertThat(got.getComponentId()).isEqualTo(expect.getComponentId());
- assertThat(got.getUserLogin()).isNotNull();
- if (got.getComponentId() != null) {
- assertThat(got.getComponentUuid()).isNotNull();
- }
}
if (logins == null) {
// test method "countUsers()", which does not make sense if users are filtered
long distinctUsers = Arrays.stream(expected).mapToLong(p -> p.getUserId()).distinct().count();
- assertThat((long) underTest.countUsers(dbSession, query)).isEqualTo(distinctUsers);
+ assertThat((long) underTest.countUsers(dbSession, org.getUuid(), query)).isEqualTo(distinctUsers);
}
}
assertThat(isRoot)
.as("Root flag of user '%s' is '%s'", userDto.getLogin(), root)
.isEqualTo(isRoot instanceof Long ? toLong(root) : root);
-// assertThat(row.get("updatedAt"))
-// .as("UpdatedAt of user '%s' has changed since insertion", userDto.getLogin())
-// .isNotEqualTo(userDto.getUpdatedAt());
+ assertThat(row.get("updatedAt"))
+ .as("UpdatedAt of user '%s' has changed since insertion", userDto.getLogin())
+ .isNotEqualTo(userDto.getUpdatedAt());
}
private static Long toLong(boolean root) {