]> source.dussan.org Git - sonarqube.git/blob
03435d3c93b468b040da446a0063479d2b83fd69
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 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;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.junit.rules.ExpectedException;
27 import org.sonar.api.resources.Qualifiers;
28 import org.sonar.api.resources.ResourceTypes;
29 import org.sonar.api.utils.System2;
30 import org.sonar.api.web.UserRole;
31 import org.sonar.core.permission.GlobalPermissions;
32 import org.sonar.core.util.SequenceUuidFactory;
33 import org.sonar.core.util.Uuids;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.component.ResourceTypesRule;
37 import org.sonar.db.permission.GlobalPermission;
38 import org.sonar.db.permission.GroupPermissionDto;
39 import org.sonar.db.user.GroupDto;
40 import org.sonar.db.user.UserDto;
41 import org.sonar.server.exceptions.BadRequestException;
42
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.fail;
45 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
46 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES;
47 import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
48
49 public class GroupPermissionChangerTest {
50
51   @Rule
52   public DbTester db = DbTester.create(System2.INSTANCE);
53   @Rule
54   public ExpectedException expectedException = ExpectedException.none();
55
56   private final ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
57   private final PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
58   private final GroupPermissionChanger underTest = new GroupPermissionChanger(db.getDbClient(), new SequenceUuidFactory());
59   private GroupDto group;
60   private ComponentDto privateProject;
61   private ComponentDto publicProject;
62
63   @Before
64   public void setUp() {
65     group = db.users().insertGroup("a-group");
66     privateProject = db.components().insertPrivateProject();
67     publicProject = db.components().insertPublicProject();
68   }
69
70   @Test
71   public void apply_adds_global_permission_to_group() {
72     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
73
74     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupUuid, permissionService));
75
76     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
77   }
78
79   @Test
80   public void apply_adds_global_permission_to_group_AnyOne() {
81     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
82
83     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupUuid, permissionService));
84
85     assertThat(db.users().selectAnyonePermissions(null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
86   }
87
88   @Test
89   public void apply_fails_with_BadRequestException_when_adding_any_permission_to_group_AnyOne_on_private_project() {
90     GroupUuidOrAnyone anyOneGroup = GroupUuidOrAnyone.forAnyone();
91     permissionService.getAllProjectPermissions()
92       .forEach(perm -> {
93         GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, anyOneGroup, permissionService);
94         try {
95           apply(change);
96           fail("a BadRequestException should have been thrown");
97         } catch (BadRequestException e) {
98           assertThat(e).hasMessage("No permission can be granted to Anyone on a private component");
99         }
100       });
101   }
102
103   @Test
104   public void apply_has_no_effect_when_removing_any_permission_to_group_AnyOne_on_private_project() {
105     permissionService.getAllProjectPermissions()
106       .forEach(this::unsafeInsertProjectPermissionOnAnyone);
107
108     GroupUuidOrAnyone anyOneGroup = GroupUuidOrAnyone.forAnyone();
109     permissionService.getAllProjectPermissions()
110       .forEach(perm -> {
111         apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, perm, privateProject, anyOneGroup, permissionService));
112
113         assertThat(db.users().selectAnyonePermissions(privateProject)).contains(perm);
114       });
115   }
116
117   @Test
118   public void apply_adds_permission_USER_to_group_on_private_project() {
119     applyAddsPermissionToGroupOnPrivateProject(UserRole.USER);
120   }
121
122   @Test
123   public void apply_adds_permission_CODEVIEWER_to_group_on_private_project() {
124     applyAddsPermissionToGroupOnPrivateProject(UserRole.CODEVIEWER);
125   }
126
127   @Test
128   public void apply_adds_permission_ADMIN_to_group_on_private_project() {
129     applyAddsPermissionToGroupOnPrivateProject(UserRole.ADMIN);
130   }
131
132   @Test
133   public void apply_adds_permission_ISSUE_ADMIN_to_group_on_private_project() {
134     applyAddsPermissionToGroupOnPrivateProject(UserRole.ISSUE_ADMIN);
135   }
136
137   @Test
138   public void apply_adds_permission_SCAN_EXECUTION_to_group_on_private_project() {
139     applyAddsPermissionToGroupOnPrivateProject(GlobalPermissions.SCAN_EXECUTION);
140   }
141
142   private void applyAddsPermissionToGroupOnPrivateProject(String permission) {
143     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
144
145     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, groupUuid, permissionService));
146
147     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
148     assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
149   }
150
151   @Test
152   public void apply_removes_permission_USER_from_group_on_private_project() {
153     applyRemovesPermissionFromGroupOnPrivateProject(UserRole.USER);
154   }
155
156   @Test
157   public void apply_removes_permission_CODEVIEWER_from_group_on_private_project() {
158     applyRemovesPermissionFromGroupOnPrivateProject(UserRole.CODEVIEWER);
159   }
160
161   @Test
162   public void apply_removes_permission_ADMIN_from_on_private_project() {
163     applyRemovesPermissionFromGroupOnPrivateProject(UserRole.ADMIN);
164   }
165
166   @Test
167   public void apply_removes_permission_ISSUE_ADMIN_from_on_private_project() {
168     applyRemovesPermissionFromGroupOnPrivateProject(UserRole.ISSUE_ADMIN);
169   }
170
171   @Test
172   public void apply_removes_permission_SCAN_EXECUTION_from_on_private_project() {
173     applyRemovesPermissionFromGroupOnPrivateProject(GlobalPermissions.SCAN_EXECUTION);
174   }
175
176   private void applyRemovesPermissionFromGroupOnPrivateProject(String permission) {
177     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
178     db.users().insertProjectPermissionOnGroup(group, permission, privateProject);
179
180     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, groupUuid, permissionService));
181
182     assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
183   }
184
185   @Test
186   public void apply_has_no_effect_when_adding_USER_permission_to_group_AnyOne_on_a_public_project() {
187     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
188
189     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.USER, publicProject, groupUuid, permissionService));
190
191     assertThat(db.users().selectAnyonePermissions(publicProject)).isEmpty();
192   }
193
194   @Test
195   public void apply_has_no_effect_when_adding_CODEVIEWER_permission_to_group_AnyOne_on_a_public_project() {
196     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
197
198     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService));
199
200     assertThat(db.users().selectAnyonePermissions(publicProject)).isEmpty();
201   }
202
203   @Test
204   public void apply_fails_with_BadRequestException_when_adding_permission_ADMIN_to_group_AnyOne_on_a_public_project() {
205     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
206
207     expectedException.expect(BadRequestException.class);
208     expectedException.expectMessage("It is not possible to add the 'admin' permission to group 'Anyone'");
209
210     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ADMIN, publicProject, groupUuid, permissionService));
211   }
212
213   @Test
214   public void apply_adds_permission_ISSUE_ADMIN_to_group_AnyOne_on_a_public_project() {
215     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
216
217     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, publicProject, groupUuid, permissionService));
218
219     assertThat(db.users().selectAnyonePermissions(publicProject)).containsOnly(UserRole.ISSUE_ADMIN);
220   }
221
222   @Test
223   public void apply_adds_permission_SCAN_EXECUTION_to_group_AnyOne_on_a_public_project() {
224     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
225
226     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.SCAN_EXECUTION, publicProject, groupUuid, permissionService));
227
228     assertThat(db.users().selectAnyonePermissions(publicProject)).containsOnly(GlobalPermissions.SCAN_EXECUTION);
229   }
230
231   @Test
232   public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_group_AnyOne_on_a_public_project() {
233     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
234
235     expectedException.expect(BadRequestException.class);
236     expectedException.expectMessage("Permission user can't be removed from a public component");
237
238     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, groupUuid, permissionService));
239   }
240
241   @Test
242   public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_group_AnyOne_on_a_public_project() {
243     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
244
245     expectedException.expect(BadRequestException.class);
246     expectedException.expectMessage("Permission codeviewer can't be removed from a public component");
247
248     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService));
249   }
250
251   @Test
252   public void apply_removes_ADMIN_permission_from_group_AnyOne_on_a_public_project() {
253     applyRemovesPermissionFromGroupAnyOneOnAPublicProject(UserRole.ADMIN);
254   }
255
256   @Test
257   public void apply_removes_ISSUE_ADMIN_permission_from_group_AnyOne_on_a_public_project() {
258     applyRemovesPermissionFromGroupAnyOneOnAPublicProject(UserRole.ISSUE_ADMIN);
259   }
260
261   @Test
262   public void apply_removes_SCAN_EXECUTION_permission_from_group_AnyOne_on_a_public_project() {
263     applyRemovesPermissionFromGroupAnyOneOnAPublicProject(GlobalPermissions.SCAN_EXECUTION);
264   }
265
266   private void applyRemovesPermissionFromGroupAnyOneOnAPublicProject(String permission) {
267     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
268     db.users().insertProjectPermissionOnAnyone(permission, publicProject);
269
270     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, permission, publicProject, groupUuid, permissionService));
271
272     assertThat(db.users().selectAnyonePermissions(publicProject)).isEmpty();
273   }
274
275   @Test
276   public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_a_group_on_a_public_project() {
277     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
278
279     expectedException.expect(BadRequestException.class);
280     expectedException.expectMessage("Permission user can't be removed from a public component");
281
282     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, groupUuid, permissionService));
283   }
284
285   @Test
286   public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_a_group_on_a_public_project() {
287     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
288
289     expectedException.expect(BadRequestException.class);
290     expectedException.expectMessage("Permission codeviewer can't be removed from a public component");
291
292     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, groupUuid, permissionService));
293   }
294
295   @Test
296   public void add_permission_to_anyone() {
297     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.forAnyone();
298
299     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermissions.QUALITY_GATE_ADMIN, null, groupUuid, permissionService));
300
301     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
302     assertThat(db.users().selectAnyonePermissions(null)).containsOnly(GlobalPermissions.QUALITY_GATE_ADMIN);
303   }
304
305   @Test
306   public void do_nothing_when_adding_permission_that_already_exists() {
307     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
308     db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
309
310     apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, groupUuid, permissionService));
311
312     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
313   }
314
315   @Test
316   public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_private_project() {
317     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
318
319     permissionService.getGlobalPermissions().stream()
320       .map(GlobalPermission::getKey)
321       .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermissions.SCAN_EXECUTION.equals(perm))
322       .forEach(perm -> {
323         try {
324           new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, groupUuid, permissionService);
325           fail("a BadRequestException should have been thrown for permission " + perm);
326         } catch (BadRequestException e) {
327           assertThat(e).hasMessage("Invalid project permission '" + perm +
328             "'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
329         }
330       });
331   }
332
333   @Test
334   public void fail_to_add_global_permission_but_SCAN_and_ADMIN_on_public_project() {
335     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
336
337     permissionService.getGlobalPermissions().stream()
338       .map(GlobalPermission::getKey)
339       .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermissions.SCAN_EXECUTION.equals(perm))
340       .forEach(perm -> {
341         try {
342           new GroupPermissionChange(PermissionChange.Operation.ADD, perm, publicProject, groupUuid, permissionService);
343           fail("a BadRequestException should have been thrown for permission " + perm);
344         } catch (BadRequestException e) {
345           assertThat(e).hasMessage("Invalid project permission '" + perm +
346             "'. Valid values are [" + StringUtils.join(permissionService.getAllProjectPermissions(), ", ") + "]");
347         }
348       });
349   }
350
351   @Test
352   public void fail_to_add_project_permission_but_SCAN_and_ADMIN_on_global_group() {
353     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
354
355     permissionService.getAllProjectPermissions()
356       .stream()
357       .filter(perm -> !GlobalPermissions.SCAN_EXECUTION.equals(perm) && !GlobalPermission.ADMINISTER.getKey().equals(perm))
358       .forEach(permission -> {
359         try {
360           new GroupPermissionChange(PermissionChange.Operation.ADD, permission, null, groupUuid, permissionService);
361           fail("a BadRequestException should have been thrown for permission " + permission);
362         } catch (BadRequestException e) {
363           assertThat(e).hasMessage("Invalid global permission '" + permission + "'. Valid values are [admin, gateadmin, profileadmin, provisioning, scan]");
364         }
365       });
366   }
367
368   @Test
369   public void remove_permission_from_group() {
370     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
371     db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
372     db.users().insertPermissionOnGroup(group, PROVISION_PROJECTS);
373
374     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, groupUuid, permissionService));
375
376     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(PROVISION_PROJECTS.getKey());
377   }
378
379   @Test
380   public void remove_project_permission_from_group() {
381     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
382     db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
383     db.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, privateProject);
384     db.users().insertProjectPermissionOnGroup(group, UserRole.CODEVIEWER, privateProject);
385
386     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, groupUuid, permissionService));
387
388     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
389     assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(UserRole.CODEVIEWER);
390   }
391
392   @Test
393   public void do_not_fail_if_removing_a_permission_that_does_not_exist() {
394     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
395
396     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, groupUuid, permissionService));
397
398     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
399     assertThat(db.users().selectGroupPermissions(group, privateProject)).isEmpty();
400   }
401
402   @Test
403   public void fail_to_remove_admin_permission_if_no_more_admins() {
404     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
405     db.users().insertPermissionOnGroup(group, ADMINISTER);
406
407     expectedException.expect(BadRequestException.class);
408     expectedException.expectMessage("Last group with permission 'admin'. Permission cannot be removed.");
409
410     underTest.apply(db.getSession(), new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupUuid, permissionService));
411   }
412
413   @Test
414   public void remove_admin_group_if_still_other_admins() {
415     GroupUuidOrAnyone groupUuid = GroupUuidOrAnyone.from(group);
416     db.users().insertPermissionOnGroup(group, ADMINISTER);
417     UserDto admin = db.users().insertUser();
418     db.users().insertPermissionOnUser(admin, ADMINISTER);
419
420     apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, groupUuid, permissionService));
421
422     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
423   }
424
425   private void apply(GroupPermissionChange change) {
426     underTest.apply(db.getSession(), change);
427     db.commit();
428   }
429
430   private void unsafeInsertProjectPermissionOnAnyone(String perm) {
431     GroupPermissionDto dto = new GroupPermissionDto()
432       .setUuid(Uuids.createFast())
433       .setGroupUuid(null)
434       .setRole(perm)
435       .setComponentUuid(privateProject.uuid())
436       .setComponentName(privateProject.name());
437     db.getDbClient().groupPermissionDao().insert(db.getSession(), dto, privateProject);
438     db.commit();
439   }
440 }