]> source.dussan.org Git - sonarqube.git/blob
a4e70827191636dc77604b0514eb8e7c6a45da06
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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.newSubPortfolio;
51 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
52 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES;
53 import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
54 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
55 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
56 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
57 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_USER_LOGIN;
58
59 public class RemoveUserActionTest extends BasePermissionWsTest<RemoveUserAction> {
60
61   private static final String A_PROJECT_UUID = "project-uuid";
62   private static final String A_PROJECT_KEY = "project-key";
63   private static final String A_LOGIN = "ray.bradbury";
64
65   private UserDto user;
66   private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
67   private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
68   private WsParameters wsParameters = new WsParameters(permissionService);
69
70   @Before
71   public void setUp() {
72     user = db.users().insertUser(A_LOGIN);
73   }
74
75   @Override
76   protected RemoveUserAction buildWsAction() {
77     return new RemoveUserAction(db.getDbClient(), userSession, newPermissionUpdater(), newPermissionWsSupport(), wsParameters, permissionService);
78   }
79
80   @Test
81   public void remove_permission_from_user() {
82     db.users().insertPermissionOnUser(user, PROVISION_PROJECTS);
83     db.users().insertPermissionOnUser(user, ADMINISTER_QUALITY_GATES);
84     loginAsAdmin();
85
86     newRequest()
87       .setParam(PARAM_USER_LOGIN, user.getLogin())
88       .setParam(PARAM_PERMISSION, QUALITY_GATE_ADMIN)
89       .execute();
90
91     assertThat(db.users().selectPermissionsOfUser(user)).containsOnly(PROVISION_PROJECTS);
92   }
93
94   @Test
95   public void admin_can_not_remove_his_global_admin_right() {
96     db.users().insertPermissionOnUser(user, ADMINISTER);
97     loginAsAdmin();
98     UserDto admin = db.users().insertUser(userSession.getLogin());
99     db.users().insertPermissionOnUser(admin, ADMINISTER);
100
101     TestRequest request = newRequest()
102       .setParam(PARAM_USER_LOGIN, userSession.getLogin())
103       .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
104
105     assertThatThrownBy(() -> request.execute())
106       .isInstanceOf(BadRequestException.class)
107       .hasMessage("As an admin, you can't remove your own admin right");
108   }
109
110   @Test
111   public void project_admin_can_not_remove_his_project_admin_right() {
112     loginAsAdmin();
113     UserDto admin = db.users().insertUser(userSession.getLogin());
114     ComponentDto project = db.components().insertPrivateProject();
115     db.users().insertProjectPermissionOnUser(admin, ADMINISTER.getKey(), project);
116
117     TestRequest request = newRequest()
118       .setParam(PARAM_USER_LOGIN, userSession.getLogin())
119       .setParam(PARAM_PROJECT_ID, project.uuid())
120       .setParam(PARAM_PERMISSION, ADMINISTER.getKey());
121
122     assertThatThrownBy(() -> request.execute())
123       .isInstanceOf(BadRequestException.class)
124       .hasMessage("As an admin, you can't remove your own admin right");
125   }
126
127   @Test
128   public void fail_to_remove_admin_permission_if_last_admin() {
129     db.users().insertPermissionOnUser(user, ADMINISTER);
130     loginAsAdmin();
131
132     assertThatThrownBy(() -> {
133       newRequest()
134         .setParam(PARAM_USER_LOGIN, user.getLogin())
135         .setParam(PARAM_PERMISSION, ADMIN)
136         .execute();
137     })
138       .isInstanceOf(BadRequestException.class)
139       .hasMessage("Last user with permission 'admin'. Permission cannot be removed.");
140   }
141
142   @Test
143   public void remove_permission_from_project() {
144     ComponentDto project = db.components().insertPrivateProject();
145     db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
146     db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
147     loginAsAdmin();
148
149     newRequest()
150       .setParam(PARAM_USER_LOGIN, user.getLogin())
151       .setParam(PARAM_PROJECT_ID, project.uuid())
152       .setParam(PARAM_PERMISSION, CODEVIEWER)
153       .execute();
154
155     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(ISSUE_ADMIN);
156   }
157
158   @Test
159   public void remove_with_project_key() {
160     ComponentDto project = db.components().insertPrivateProject();
161     db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
162     db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
163     loginAsAdmin();
164
165     newRequest()
166       .setParam(PARAM_USER_LOGIN, user.getLogin())
167       .setParam(PARAM_PROJECT_KEY, project.getKey())
168       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
169       .execute();
170
171     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
172   }
173
174   @Test
175   public void remove_with_view_uuid() {
176     ComponentDto view = db.components().insertPrivatePortfolio();
177     db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, view);
178     db.users().insertProjectPermissionOnUser(user, ADMIN, view);
179     loginAsAdmin();
180
181     newRequest()
182       .setParam(PARAM_USER_LOGIN, user.getLogin())
183       .setParam(PARAM_PROJECT_KEY, view.getKey())
184       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
185       .execute();
186
187     assertThat(db.users().selectProjectPermissionsOfUser(user, view)).containsOnly(ADMIN);
188   }
189
190   @Test
191   public void fail_when_project_does_not_exist() {
192     loginAsAdmin();
193
194     assertThatThrownBy(() -> {
195       newRequest()
196         .setParam(PARAM_USER_LOGIN, user.getLogin())
197         .setParam(PARAM_PROJECT_ID, "unknown-project-uuid")
198         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
199         .execute();
200     })
201       .isInstanceOf(NotFoundException.class);
202   }
203
204   @Test
205   public void fail_when_project_permission_without_permission() {
206     loginAsAdmin();
207
208     assertThatThrownBy(() -> {
209       newRequest()
210         .setParam(PARAM_USER_LOGIN, user.getLogin())
211         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
212         .execute();
213     })
214       .isInstanceOf(BadRequestException.class);
215   }
216
217   @Test
218   public void fail_when_component_is_a_directory() {
219     ComponentDto project = db.components().insertPrivateProject();
220     ComponentDto file = db.components().insertComponent(newDirectory(project, "A/B"));
221
222     failIfComponentIsNotAProjectOrView(file);
223   }
224
225   @Test
226   public void fail_when_component_is_a_file() {
227     ComponentDto project = db.components().insertPrivateProject();
228     ComponentDto file = db.components().insertComponent(newFileDto(project, null, "file-uuid"));
229
230     failIfComponentIsNotAProjectOrView(file);
231   }
232
233   @Test
234   public void fail_when_component_is_a_subview() {
235     ComponentDto portfolio = db.components().insertPrivatePortfolio();
236     ComponentDto file = db.components().insertComponent(newSubPortfolio(portfolio));
237
238     failIfComponentIsNotAProjectOrView(file);
239   }
240
241   private void failIfComponentIsNotAProjectOrView(ComponentDto file) {
242     loginAsAdmin();
243
244     assertThatThrownBy(() -> {
245       newRequest()
246         .setParam(PARAM_USER_LOGIN, user.getLogin())
247         .setParam(PARAM_PROJECT_ID, file.uuid())
248         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
249         .execute();
250     })
251       .isInstanceOf(BadRequestException.class)
252       .hasMessage("Component '" + file.getKey() + "' (id: " + file.uuid() + ") must be a project or a view.");
253   }
254
255   @Test
256   public void fail_when_get_request() {
257     loginAsAdmin();
258
259     assertThatThrownBy(() -> {
260       newRequest()
261         .setMethod("GET")
262         .setParam(PARAM_USER_LOGIN, "george.orwell")
263         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
264         .execute();
265     })
266       .isInstanceOf(ServerException.class);
267   }
268
269   @Test
270   public void fail_when_user_login_is_missing() {
271     loginAsAdmin();
272
273     assertThatThrownBy(() -> {
274       newRequest()
275         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
276         .execute();
277     })
278       .isInstanceOf(IllegalArgumentException.class);
279   }
280
281   @Test
282   public void fail_when_permission_is_missing() {
283     loginAsAdmin();
284
285     assertThatThrownBy(() -> {
286       newRequest()
287         .setParam(PARAM_USER_LOGIN, user.getLogin())
288         .execute();
289     })
290       .isInstanceOf(IllegalArgumentException.class);
291   }
292
293   @Test
294   public void fail_when_project_uuid_and_project_key_are_provided() {
295     ComponentDto project = db.components().insertPrivateProject();
296     loginAsAdmin();
297
298     assertThatThrownBy(() -> {
299       newRequest()
300         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
301         .setParam(PARAM_USER_LOGIN, user.getLogin())
302         .setParam(PARAM_PROJECT_ID, project.uuid())
303         .setParam(PARAM_PROJECT_KEY, project.getKey())
304         .execute();
305     })
306       .isInstanceOf(BadRequestException.class)
307       .hasMessage("Project id or project key can be provided, not both.");
308   }
309
310   @Test
311   public void removing_global_permission_fails_if_not_system_administrator() {
312     userSession.logIn();
313
314     assertThatThrownBy(() -> {
315       newRequest()
316         .setParam(PARAM_USER_LOGIN, user.getLogin())
317         .setParam(PARAM_PERMISSION, PROVISIONING)
318         .execute();
319     })
320       .isInstanceOf(ForbiddenException.class);
321   }
322
323   @Test
324   public void removing_project_permission_fails_if_not_administrator_of_project() {
325     ComponentDto project = db.components().insertPrivateProject();
326     userSession.logIn();
327
328     assertThatThrownBy(() -> {
329       newRequest()
330         .setParam(PARAM_USER_LOGIN, user.getLogin())
331         .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
332         .setParam(PARAM_PROJECT_KEY, project.getKey())
333         .execute();
334     })
335       .isInstanceOf(ForbiddenException.class);
336   }
337
338   /**
339    * User is project administrator but not system administrator
340    */
341   @Test
342   public void removing_project_permission_is_allowed_to_project_administrators() {
343     ComponentDto project = db.components().insertPrivateProject();
344     db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
345     db.users().insertProjectPermissionOnUser(user, ISSUE_ADMIN, project);
346     userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
347
348     newRequest()
349       .setParam(PARAM_USER_LOGIN, user.getLogin())
350       .setParam(PARAM_PROJECT_ID, project.uuid())
351       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
352       .execute();
353
354     assertThat(db.users().selectProjectPermissionsOfUser(user, project)).containsOnly(CODEVIEWER);
355   }
356
357   @Test
358   public void fail_when_removing_USER_permission_on_a_public_project() {
359     ComponentDto project = db.components().insertPublicProject();
360     userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
361
362     assertThatThrownBy(() -> {
363       newRequest()
364         .setParam(PARAM_USER_LOGIN, user.getLogin())
365         .setParam(PARAM_PROJECT_ID, project.uuid())
366         .setParam(PARAM_PERMISSION, USER)
367         .execute();
368     })
369       .isInstanceOf(BadRequestException.class)
370       .hasMessage("Permission user can't be removed from a public component");
371
372   }
373
374   @Test
375   public void fail_when_removing_CODEVIEWER_permission_on_a_public_project() {
376     ComponentDto project = db.components().insertPublicProject();
377     userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
378
379     assertThatThrownBy(() -> {
380       newRequest()
381         .setParam(PARAM_USER_LOGIN, user.getLogin())
382         .setParam(PARAM_PROJECT_ID, project.uuid())
383         .setParam(PARAM_PERMISSION, CODEVIEWER)
384         .execute();
385     })
386       .isInstanceOf(BadRequestException.class)
387       .hasMessage("Permission codeviewer can't be removed from a public component");
388   }
389
390   @Test
391   public void fail_when_using_branch_uuid() {
392     ComponentDto project = db.components().insertPublicProject();
393     userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
394     ComponentDto branch = db.components().insertProjectBranch(project);
395
396     assertThatThrownBy(() -> {
397       newRequest()
398         .setParam(PARAM_PROJECT_ID, branch.uuid())
399         .setParam(PARAM_USER_LOGIN, user.getLogin())
400         .setParam(PARAM_PERMISSION, SYSTEM_ADMIN)
401         .execute();
402     })
403       .isInstanceOf(NotFoundException.class)
404       .hasMessage(format("Project id '%s' not found", branch.uuid()));
405   }
406
407 }