]> source.dussan.org Git - sonarqube.git/blob
3b808431776aa96cd907bb393e64106fc4f42dff
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.permission.ws;
21
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;
37
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;
59
60 public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction> {
61
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";
65
66   private UserDto user;
67   private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
68   private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
69   private WsParameters wsParameters = new WsParameters(permissionService);
70
71   @Before
72   public void setUp() {
73     user = db.users().insertUser(A_LOGIN);
74   }
75
76   @Override
77   protected RemoveUserAction buildWsAction() {
78     return new RemoveUserAction(db.getDbClient(), userSession, newPermissionUpdater(), newPermissionWsSupport(), wsParameters, permissionService);
79   }
80
81   @Test
82   public void remove_permission_from_user() {
83     db.users().insertPermissionOnUser(user, PROVISION_PROJECTS);
84     db.users().insertPermissionOnUser(user, ADMINISTER_QUALITY_GATES);
85     loginAsAdmin();
86
87     newRequest()
88       .setParam(PARAM_USER_LOGIN, user.getLogin())
89       .setParam(PARAM_PERMISSION, QUALITY_GATE_ADMIN)
90       .execute();
91
92     assertThat(db.users().selectPermissionsOfUser(user)).containsOnly(PROVISION_PROJECTS);
93   }
94
95   @Test
96   public void admin_can_not_remove_his_global_admin_right() {
97     db.users().insertPermissionOnUser(user, ADMINISTER);
98     loginAsAdmin();
99     UserDto admin = db.users().insertUser(userSession.getLogin());
100     db.users().insertPermissionOnUser(admin, ADMINISTER);
101
102     TestRequest request = newRequest()
103       .setParam(PARAM_USER_LOGIN, userSession.getLogin())
104       .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
105
106     assertThatThrownBy(() -> request.execute())
107       .isInstanceOf(BadRequestException.class)
108       .hasMessage("As an admin, you can't remove your own admin right");
109   }
110
111   @Test
112   public void project_admin_can_not_remove_his_project_admin_right() {
113     loginAsAdmin();
114     UserDto admin = db.users().insertUser(userSession.getLogin());
115     ComponentDto project = db.components().insertPrivateProject();
116     db.users().insertProjectPermissionOnUser(admin, ADMINISTER.getKey(), project);
117
118     TestRequest request = newRequest()
119       .setParam(PARAM_USER_LOGIN, userSession.getLogin())
120       .setParam(PARAM_PROJECT_ID, project.uuid())
121       .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
122
123     assertThatThrownBy(() -> request.execute())
124       .isInstanceOf(BadRequestException.class)
125       .hasMessage("As an admin, you can't remove your own admin right");
126   }
127
128   @Test
129   public void fail_to_remove_admin_permission_if_last_admin() {
130     db.users().insertPermissionOnUser(user, ADMINISTER);
131     loginAsAdmin();
132
133     assertThatThrownBy(() -> {
134       newRequest()
135         .setParam(PARAM_USER_LOGIN, user.getLogin())
136         .setParam(PARAM_PERMISSION, ADMIN)
137         .execute();
138     })
139       .isInstanceOf(BadRequestException.class)
140       .hasMessage("Last user with permission 'admin'. Permission cannot be removed.");
141   }
142
143   @Test
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);
148     loginAsAdmin();
149
150     newRequest()
151       .setParam(PARAM_USER_LOGIN, user.getLogin())
152       .setParam(PARAM_PROJECT_ID, project.uuid())
153       .setParam(PARAM_PERMISSION, CODEVIEWER)
154       .execute();
155
156     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(ISSUE_ADMIN);
157   }
158
159   @Test
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);
164     loginAsAdmin();
165
166     newRequest()
167       .setParam(PARAM_USER_LOGIN, user.getLogin())
168       .setParam(PARAM_PROJECT_KEY, project.getDbKey())
169       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
170       .execute();
171
172     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
173   }
174
175   @Test
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);
180     loginAsAdmin();
181
182     newRequest()
183       .setParam(PARAM_USER_LOGIN, user.getLogin())
184       .setParam(PARAM_PROJECT_KEY, view.getDbKey())
185       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
186       .execute();
187
188     assertThat(db.users().selectProjectPermissionsOfUser(user, view)).containsOnly(ADMIN);
189   }
190
191   @Test
192   public void fail_when_project_does_not_exist() {
193     loginAsAdmin();
194
195     assertThatThrownBy(() -> {
196       newRequest()
197         .setParam(PARAM_USER_LOGIN, user.getLogin())
198         .setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
199         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
200         .execute();
201     })
202       .isInstanceOf(NotFoundException.class);
203   }
204
205   @Test
206   public void fail_when_project_permission_without_permission() {
207     loginAsAdmin();
208
209     assertThatThrownBy(() -> {
210       newRequest()
211         .setParam(PARAM_USER_LOGIN, user.getLogin())
212         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
213         .execute();
214     })
215       .isInstanceOf(BadRequestException.class);
216   }
217
218   @Test
219   public void fail_when_component_is_a_module() {
220     ComponentDto project = db.components().insertPrivateProject();
221     ComponentDto module = db.components().insertComponent(newModuleDto(project));
222
223     failIfComponentIsNotAProjectOrView(module);
224   }
225
226   @Test
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"));
230
231     failIfComponentIsNotAProjectOrView(file);
232   }
233
234   @Test
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"));
238
239     failIfComponentIsNotAProjectOrView(file);
240   }
241
242   @Test
243   public void fail_when_component_is_a_subview() {
244     ComponentDto portfolio = db.components().insertPrivatePortfolio();
245     ComponentDto file = db.components().insertComponent(newSubPortfolio(portfolio));
246
247     failIfComponentIsNotAProjectOrView(file);
248   }
249
250   private void failIfComponentIsNotAProjectOrView(ComponentDto file) {
251     loginAsAdmin();
252
253     assertThatThrownBy(() -> {
254       newRequest()
255         .setParam(PARAM_USER_LOGIN, user.getLogin())
256         .setParam(PARAM_PROJECT_ID, file.uuid())
257         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
258         .execute();
259     })
260       .isInstanceOf(BadRequestException.class)
261       .hasMessage("Component '" + file.getDbKey() + "' (id: " + file.uuid() + ") must be a project or a view.");
262   }
263
264   @Test
265   public void fail_when_get_request() {
266     loginAsAdmin();
267
268     assertThatThrownBy(() -> {
269       newRequest()
270         .setMethod("GET")
271         .setParam(PARAM_USER_LOGIN, "george.orwell")
272         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
273         .execute();
274     })
275       .isInstanceOf(ServerException.class);
276   }
277
278   @Test
279   public void fail_when_user_login_is_missing() {
280     loginAsAdmin();
281
282     assertThatThrownBy(() -> {
283       newRequest()
284         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
285         .execute();
286     })
287       .isInstanceOf(IllegalArgumentException.class);
288   }
289
290   @Test
291   public void fail_when_permission_is_missing() {
292     loginAsAdmin();
293
294     assertThatThrownBy(() -> {
295       newRequest()
296         .setParam(PARAM_USER_LOGIN, user.getLogin())
297         .execute();
298     })
299       .isInstanceOf(IllegalArgumentException.class);
300   }
301
302   @Test
303   public void fail_when_project_uuid_and_project_key_are_provided() {
304     ComponentDto project = db.components().insertPrivateProject();
305     loginAsAdmin();
306
307     assertThatThrownBy(() -> {
308       newRequest()
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())
313         .execute();
314     })
315       .isInstanceOf(BadRequestException.class)
316       .hasMessage("Project id or project key can be provided, not both.");
317   }
318
319   @Test
320   public void removing_global_permission_fails_if_not_system_administrator() {
321     userSession.logIn();
322
323     assertThatThrownBy(() -> {
324       newRequest()
325         .setParam(PARAM_USER_LOGIN, user.getLogin())
326         .setParam(PARAM_PERMISSION, PROVISIONING)
327         .execute();
328     })
329       .isInstanceOf(ForbiddenException.class);
330   }
331
332   @Test
333   public void removing_project_permission_fails_if_not_administrator_of_project() {
334     ComponentDto project = db.components().insertPrivateProject();
335     userSession.logIn();
336
337     assertThatThrownBy(() -> {
338       newRequest()
339         .setParam(PARAM_USER_LOGIN, user.getLogin())
340         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
341         .setParam(PARAM_PROJECT_KEY, project.getDbKey())
342         .execute();
343     })
344       .isInstanceOf(ForbiddenException.class);
345   }
346
347   /**
348    * User is project administrator but not system administrator
349    */
350   @Test
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);
356
357     newRequest()
358       .setParam(PARAM_USER_LOGIN, user.getLogin())
359       .setParam(PARAM_PROJECT_ID, project.uuid())
360       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
361       .execute();
362
363     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
364   }
365
366   @Test
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);
370
371     assertThatThrownBy(() -> {
372       newRequest()
373         .setParam(PARAM_USER_LOGIN, user.getLogin())
374         .setParam(PARAM_PROJECT_ID, project.uuid())
375         .setParam(PARAM_PERMISSION, USER)
376         .execute();
377     })
378       .isInstanceOf(BadRequestException.class)
379       .hasMessage("Permission user can't be removed from a public component");
380
381   }
382
383   @Test
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);
387
388     assertThatThrownBy(() -> {
389       newRequest()
390         .setParam(PARAM_USER_LOGIN, user.getLogin())
391         .setParam(PARAM_PROJECT_ID, project.uuid())
392         .setParam(PARAM_PERMISSION, CODEVIEWER)
393         .execute();
394     })
395       .isInstanceOf(BadRequestException.class)
396       .hasMessage("Permission codeviewer can't be removed from a public component");
397   }
398
399   @Test
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);
404
405     assertThatThrownBy(() -> {
406       newRequest()
407         .setParam(PARAM_PROJECT_KEY, branch.getDbKey())
408         .setParam(PARAM_USER_LOGIN, user.getLogin())
409         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
410         .execute();
411     })
412       .isInstanceOf(NotFoundException.class)
413       .hasMessage(format("Project key '%s' not found", branch.getDbKey()));
414   }
415
416   @Test
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);
421
422     assertThatThrownBy(() -> {
423       newRequest()
424         .setParam(PARAM_PROJECT_ID, branch.uuid())
425         .setParam(PARAM_USER_LOGIN, user.getLogin())
426         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
427         .execute();
428     })
429       .isInstanceOf(NotFoundException.class)
430       .hasMessage(format("Project id '%s' not found", branch.uuid()));
431   }
432
433 }