3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.permission.ws;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.sonar.api.resources.Qualifiers;
25 import org.sonar.api.resources.ResourceTypes;
26 import org.sonar.api.web.UserRole;
27 import org.sonar.db.component.ComponentDto;
28 import org.sonar.db.component.ResourceTypesRule;
29 import org.sonar.db.user.UserDto;
30 import org.sonar.server.exceptions.BadRequestException;
31 import org.sonar.server.exceptions.ForbiddenException;
32 import org.sonar.server.exceptions.NotFoundException;
33 import org.sonar.server.exceptions.ServerException;
34 import org.sonar.server.permission.PermissionService;
35 import org.sonar.server.permission.PermissionServiceImpl;
36 import org.sonar.server.ws.TestRequest;
38 import static java.lang.String.format;
39 import static org.assertj.core.api.Assertions.assertThat;
40 import static org.assertj.core.api.Assertions.assertThatThrownBy;
41 import static org.sonar.api.web.UserRole.ADMIN;
42 import static org.sonar.api.web.UserRole.CODEVIEWER;
43 import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
44 import static org.sonar.api.web.UserRole.USER;
45 import static org.sonar.core.permission.GlobalPermissions.PROVISIONING;
46 import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
47 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
48 import static org.sonar.db.component.ComponentTesting.newDirectory;
49 import static org.sonar.db.component.ComponentTesting.newFileDto;
50 import static org.sonar.db.component.ComponentTesting.newModuleDto;
51 import static org.sonar.db.component.ComponentTesting.newSubPortfolio;
52 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
53 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES;
54 import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
55 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
56 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
57 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
58 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;
60 public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction> {
62 private static final String A_PROJECT_UUID = "project-uuid";
63 private static final String A_PROJECT_KEY = "project-key";
64 private static final String A_LOGIN = "ray.bradbury";
67 private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
68 private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
69 private WsParameters wsParameters = new WsParameters(permissionService);
73 user = db.users().insertUser(A_LOGIN);
77 protected RemoveUserAction buildWsAction() {
78 return new RemoveUserAction(db.getDbClient(), userSession, newPermissionUpdater(), newPermissionWsSupport(), wsParameters, permissionService);
82 public void remove_permission_from_user() {
83 db.users().insertPermissionOnUser(user, PROVISION_PROJECTS);
84 db.users().insertPermissionOnUser(user, ADMINISTER_QUALITY_GATES);
88 .setParam(PARAM_USER_LOGIN, user.getLogin())
89 .setParam(PARAM_PERMISSION, QUALITY_GATE_ADMIN)
92 assertThat(db.users().selectPermissionsOfUser(user)).containsOnly(PROVISION_PROJECTS);
96 public void admin_can_not_remove_his_global_admin_right() {
97 db.users().insertPermissionOnUser(user, ADMINISTER);
99 UserDto admin = db.users().insertUser(userSession.getLogin());
100 db.users().insertPermissionOnUser(admin, ADMINISTER);
102 TestRequest request = newRequest()
103 .setParam(PARAM_USER_LOGIN, userSession.getLogin())
104 .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
106 assertThatThrownBy(() -> request.execute())
107 .isInstanceOf(BadRequestException.class)
108 .hasMessage("As an admin, you can't remove your own admin right");
112 public void project_admin_can_not_remove_his_project_admin_right() {
114 UserDto admin = db.users().insertUser(userSession.getLogin());
115 ComponentDto project = db.components().insertPrivateProject();
116 db.users().insertProjectPermissionOnUser(admin, ADMINISTER.getKey(), project);
118 TestRequest request = newRequest()
119 .setParam(PARAM_USER_LOGIN, userSession.getLogin())
120 .setParam(PARAM_PROJECT_ID, project.uuid())
121 .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
123 assertThatThrownBy(() -> request.execute())
124 .isInstanceOf(BadRequestException.class)
125 .hasMessage("As an admin, you can't remove your own admin right");
129 public void fail_to_remove_admin_permission_if_last_admin() {
130 db.users().insertPermissionOnUser(user, ADMINISTER);
133 assertThatThrownBy(() -> {
135 .setParam(PARAM_USER_LOGIN, user.getLogin())
136 .setParam(PARAM_PERMISSION, ADMIN)
139 .isInstanceOf(BadRequestException.class)
140 .hasMessage("Last user with permission 'admin'. Permission cannot be removed.");
144 public void remove_permission_from_project() {
145 ComponentDto project = db.components().insertPrivateProject();
146 db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
147 db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
151 .setParam(PARAM_USER_LOGIN, user.getLogin())
152 .setParam(PARAM_PROJECT_ID, project.uuid())
153 .setParam(PARAM_PERMISSION, CODEVIEWER)
156 assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(ISSUE_ADMIN);
160 public void remove_with_project_key() {
161 ComponentDto project = db.components().insertPrivateProject();
162 db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
163 db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
167 .setParam(PARAM_USER_LOGIN, user.getLogin())
168 .setParam(PARAM_PROJECT_KEY, project.getDbKey())
169 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
172 assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
176 public void remove_with_view_uuid() {
177 ComponentDto view = db.components().insertPrivatePortfolio();
178 db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, view);
179 db.users().insertProjectPermissionOnUser(user, ADMIN, view);
183 .setParam(PARAM_USER_LOGIN, user.getLogin())
184 .setParam(PARAM_PROJECT_KEY, view.getDbKey())
185 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
188 assertThat(db.users().selectProjectPermissionsOfUser(user, view)).containsOnly(ADMIN);
192 public void fail_when_project_does_not_exist() {
195 assertThatThrownBy(() -> {
197 .setParam(PARAM_USER_LOGIN, user.getLogin())
198 .setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
199 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
202 .isInstanceOf(NotFoundException.class);
206 public void fail_when_project_permission_without_permission() {
209 assertThatThrownBy(() -> {
211 .setParam(PARAM_USER_LOGIN, user.getLogin())
212 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
215 .isInstanceOf(BadRequestException.class);
219 public void fail_when_component_is_a_module() {
220 ComponentDto project = db.components().insertPrivateProject();
221 ComponentDto module = db.components().insertComponent(newModuleDto(project));
223 failIfComponentIsNotAProjectOrView(module);
227 public void fail_when_component_is_a_directory() {
228 ComponentDto project = db.components().insertPrivateProject();
229 ComponentDto file = db.components().insertComponent(newDirectory(project, "A/B"));
231 failIfComponentIsNotAProjectOrView(file);
235 public void fail_when_component_is_a_file() {
236 ComponentDto project = db.components().insertPrivateProject();
237 ComponentDto file = db.components().insertComponent(newFileDto(project, null, "file-uuid"));
239 failIfComponentIsNotAProjectOrView(file);
243 public void fail_when_component_is_a_subview() {
244 ComponentDto portfolio = db.components().insertPrivatePortfolio();
245 ComponentDto file = db.components().insertComponent(newSubPortfolio(portfolio));
247 failIfComponentIsNotAProjectOrView(file);
250 private void failIfComponentIsNotAProjectOrView(ComponentDto file) {
253 assertThatThrownBy(() -> {
255 .setParam(PARAM_USER_LOGIN, user.getLogin())
256 .setParam(PARAM_PROJECT_ID, file.uuid())
257 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
260 .isInstanceOf(BadRequestException.class)
261 .hasMessage("Component '" + file.getDbKey() + "' (id: " + file.uuid() + ") must be a project or a view.");
265 public void fail_when_get_request() {
268 assertThatThrownBy(() -> {
271 .setParam(PARAM_USER_LOGIN, "george.orwell")
272 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
275 .isInstanceOf(ServerException.class);
279 public void fail_when_user_login_is_missing() {
282 assertThatThrownBy(() -> {
284 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
287 .isInstanceOf(IllegalArgumentException.class);
291 public void fail_when_permission_is_missing() {
294 assertThatThrownBy(() -> {
296 .setParam(PARAM_USER_LOGIN, user.getLogin())
299 .isInstanceOf(IllegalArgumentException.class);
303 public void fail_when_project_uuid_and_project_key_are_provided() {
304 ComponentDto project = db.components().insertPrivateProject();
307 assertThatThrownBy(() -> {
309 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
310 .setParam(PARAM_USER_LOGIN, user.getLogin())
311 .setParam(PARAM_PROJECT_ID, project.uuid())
312 .setParam(PARAM_PROJECT_KEY, project.getDbKey())
315 .isInstanceOf(BadRequestException.class)
316 .hasMessage("Project id or project key can be provided, not both.");
320 public void removing_global_permission_fails_if_not_system_administrator() {
323 assertThatThrownBy(() -> {
325 .setParam(PARAM_USER_LOGIN, user.getLogin())
326 .setParam(PARAM_PERMISSION, PROVISIONING)
329 .isInstanceOf(ForbiddenException.class);
333 public void removing_project_permission_fails_if_not_administrator_of_project() {
334 ComponentDto project = db.components().insertPrivateProject();
337 assertThatThrownBy(() -> {
339 .setParam(PARAM_USER_LOGIN, user.getLogin())
340 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
341 .setParam(PARAM_PROJECT_KEY, project.getDbKey())
344 .isInstanceOf(ForbiddenException.class);
348 * User is project administrator but not system administrator
351 public void removing_project_permission_is_allowed_to_project_administrators() {
352 ComponentDto project = db.components().insertPrivateProject();
353 db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
354 db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
355 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
358 .setParam(PARAM_USER_LOGIN, user.getLogin())
359 .setParam(PARAM_PROJECT_ID, project.uuid())
360 .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
363 assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
367 public void fail_when_removing_USER_permission_on_a_public_project() {
368 ComponentDto project = db.components().insertPublicProject();
369 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
371 assertThatThrownBy(() -> {
373 .setParam(PARAM_USER_LOGIN, user.getLogin())
374 .setParam(PARAM_PROJECT_ID, project.uuid())
375 .setParam(PARAM_PERMISSION, USER)
378 .isInstanceOf(BadRequestException.class)
379 .hasMessage("Permission user can't be removed from a public component");
384 public void fail_when_removing_CODEVIEWER_permission_on_a_public_project() {
385 ComponentDto project = db.components().insertPublicProject();
386 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
388 assertThatThrownBy(() -> {
390 .setParam(PARAM_USER_LOGIN, user.getLogin())
391 .setParam(PARAM_PROJECT_ID, project.uuid())
392 .setParam(PARAM_PERMISSION, CODEVIEWER)
395 .isInstanceOf(BadRequestException.class)
396 .hasMessage("Permission codeviewer can't be removed from a public component");
400 public void fail_when_using_branch_db_key() {
401 ComponentDto project = db.components().insertPublicProject();
402 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
403 ComponentDto branch = db.components().insertProjectBranch(project);
405 assertThatThrownBy(() -> {
407 .setParam(PARAM_PROJECT_KEY, branch.getDbKey())
408 .setParam(PARAM_USER_LOGIN, user.getLogin())
409 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
412 .isInstanceOf(NotFoundException.class)
413 .hasMessage(format("Project key '%s' not found", branch.getDbKey()));
417 public void fail_when_using_branch_uuid() {
418 ComponentDto project = db.components().insertPublicProject();
419 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
420 ComponentDto branch = db.components().insertProjectBranch(project);
422 assertThatThrownBy(() -> {
424 .setParam(PARAM_PROJECT_ID, branch.uuid())
425 .setParam(PARAM_USER_LOGIN, user.getLogin())
426 .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
429 .isInstanceOf(NotFoundException.class)
430 .hasMessage(format("Project id '%s' not found", branch.uuid()));