]> source.dussan.org Git - sonarqube.git/blob
ca9e451a47e4008e3d11f65e01242188b0c6a958
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 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.template;
21
22 import java.util.Collections;
23 import java.util.List;
24 import org.apache.commons.lang.StringUtils;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.sonar.api.resources.Qualifiers;
28 import org.sonar.api.server.ws.WebService.Param;
29 import org.sonar.api.web.UserRole;
30 import org.sonar.db.component.ComponentDto;
31 import org.sonar.db.component.ComponentTesting;
32 import org.sonar.db.organization.OrganizationDto;
33 import org.sonar.db.permission.PermissionQuery;
34 import org.sonar.db.permission.template.PermissionTemplateDto;
35 import org.sonar.db.user.GroupDto;
36 import org.sonar.db.user.UserDto;
37 import org.sonar.server.es.ProjectIndexers;
38 import org.sonar.server.es.TestProjectIndexers;
39 import org.sonar.server.exceptions.BadRequestException;
40 import org.sonar.server.exceptions.NotFoundException;
41 import org.sonar.server.l18n.I18nRule;
42 import org.sonar.server.permission.PermissionTemplateService;
43 import org.sonar.server.permission.ws.BasePermissionWsTest;
44
45 import static org.assertj.core.api.Assertions.assertThat;
46 import static org.sonar.api.utils.DateUtils.parseDate;
47 import static org.sonar.db.component.ComponentTesting.newApplication;
48 import static org.sonar.db.component.ComponentTesting.newView;
49 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
50 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
51 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
52 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
53 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
54 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
55 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
56 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
57 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
58
59 public class BulkApplyTemplateActionTest extends BasePermissionWsTest<BulkApplyTemplateAction> {
60
61   @org.junit.Rule
62   public DefaultTemplatesResolverRule defaultTemplatesResolver = DefaultTemplatesResolverRule.withoutGovernance();
63
64   private UserDto user1;
65   private UserDto user2;
66   private GroupDto group1;
67   private GroupDto group2;
68   private OrganizationDto organization;
69   private PermissionTemplateDto template1;
70   private PermissionTemplateDto template2;
71   private ProjectIndexers projectIndexers = new TestProjectIndexers();
72
73   @Override
74   protected BulkApplyTemplateAction buildWsAction() {
75     PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
76       projectIndexers, userSession, defaultTemplatesResolver);
77     return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
78   }
79
80   @Before
81   public void setUp() {
82     organization = db.organizations().insert();
83
84     user1 = db.users().insertUser();
85     user2 = db.users().insertUser();
86     group1 = db.users().insertGroup(organization);
87     group2 = db.users().insertGroup(organization);
88
89     db.organizations().addMember(organization, user1);
90     db.organizations().addMember(organization, user2);
91
92     // template 1 for org 1
93     template1 = db.permissionTemplates().insertTemplate(organization);
94     addUserToTemplate(user1, template1, UserRole.CODEVIEWER);
95     addUserToTemplate(user2, template1, UserRole.ISSUE_ADMIN);
96     addGroupToTemplate(group1, template1, UserRole.ADMIN);
97     addGroupToTemplate(group2, template1, UserRole.USER);
98     // template 2
99     template2 = db.permissionTemplates().insertTemplate(organization);
100     addUserToTemplate(user1, template2, UserRole.USER);
101     addUserToTemplate(user2, template2, UserRole.USER);
102     addGroupToTemplate(group1, template2, UserRole.USER);
103     addGroupToTemplate(group2, template2, UserRole.USER);
104   }
105
106   @Test
107   public void bulk_apply_template_by_template_uuid() {
108     // this project should not be applied the template
109     OrganizationDto otherOrganization = db.organizations().insert();
110     db.components().insertPrivateProject(otherOrganization);
111
112     ComponentDto privateProject = db.components().insertPrivateProject(organization);
113     ComponentDto publicProject = db.components().insertPublicProject(organization);
114     loginAsAdmin(organization);
115
116     newRequest()
117       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
118       .execute();
119
120     assertTemplate1AppliedToPrivateProject(privateProject);
121     assertTemplate1AppliedToPublicProject(publicProject);
122   }
123
124   @Test
125   public void request_throws_NotFoundException_if_template_with_specified_name_does_not_exist_in_specified_organization() {
126     OrganizationDto otherOrganization = db.organizations().insert();
127     loginAsAdmin(otherOrganization);
128
129     expectedException.expect(NotFoundException.class);
130     expectedException.expectMessage("Permission template with name '" + template1.getName()
131       + "' is not found (case insensitive) in organization with key '" + otherOrganization.getKey() + "'");
132
133     newRequest()
134       .setParam(PARAM_ORGANIZATION, otherOrganization.getKey())
135       .setParam(PARAM_TEMPLATE_NAME, template1.getName())
136       .execute();
137   }
138
139   @Test
140   public void request_throws_IAE_if_more_than_1000_projects() {
141     expectedException.expect(IllegalArgumentException.class);
142     expectedException.expectMessage("'projects' can contains only 1000 values, got 1001");
143
144     newRequest()
145       .setParam(PARAM_ORGANIZATION, organization.getKey())
146       .setParam(PARAM_TEMPLATE_NAME, template1.getName())
147       .setParam(PARAM_PROJECTS, StringUtils.join(Collections.nCopies(1_001, "foo"), ","))
148       .execute();
149   }
150
151   @Test
152   public void bulk_apply_template_by_template_name() {
153     ComponentDto privateProject = db.components().insertPrivateProject(organization);
154     ComponentDto publicProject = db.components().insertPublicProject(organization);
155     loginAsAdmin(organization);
156
157     newRequest()
158       .setParam(PARAM_ORGANIZATION, organization.getKey())
159       .setParam(PARAM_TEMPLATE_NAME, template1.getName())
160       .execute();
161
162     assertTemplate1AppliedToPrivateProject(privateProject);
163     assertTemplate1AppliedToPublicProject(publicProject);
164   }
165
166   @Test
167   public void apply_template_by_qualifiers() {
168     ComponentDto publicProject = db.components().insertPublicProject(organization);
169     ComponentDto privateProject = db.components().insertPrivateProject(organization);
170     ComponentDto view = db.components().insertComponent(newView(organization));
171     ComponentDto application = db.components().insertComponent(newApplication(organization));
172     loginAsAdmin(organization);
173
174     newRequest()
175       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
176       .setParam(PARAM_QUALIFIERS, String.join(",", Qualifiers.PROJECT, Qualifiers.APP))
177       .execute();
178
179     assertTemplate1AppliedToPrivateProject(privateProject);
180     assertTemplate1AppliedToPublicProject(publicProject);
181     assertTemplate1AppliedToPublicProject(application);
182     assertNoPermissionOnProject(view);
183   }
184
185   @Test
186   public void apply_template_by_query_on_name_and_key_public_project() {
187     ComponentDto publicProjectFoundByKey = ComponentTesting.newPublicProjectDto(organization).setDbKey("sonar");
188     db.components().insertProjectAndSnapshot(publicProjectFoundByKey);
189     ComponentDto publicProjectFoundByName = ComponentTesting.newPublicProjectDto(organization).setName("name-sonar-name");
190     db.components().insertProjectAndSnapshot(publicProjectFoundByName);
191     ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
192     db.components().insertProjectAndSnapshot(projectUntouched);
193     loginAsAdmin(organization);
194
195     newRequest()
196       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
197       .setParam(Param.TEXT_QUERY, "SONAR")
198       .execute();
199
200     assertTemplate1AppliedToPublicProject(publicProjectFoundByKey);
201     assertTemplate1AppliedToPublicProject(publicProjectFoundByName);
202     assertNoPermissionOnProject(projectUntouched);
203   }
204
205   @Test
206   public void apply_template_by_query_on_name_and_key() {
207     // partial match on key
208     ComponentDto privateProjectFoundByKey = ComponentTesting.newPrivateProjectDto(organization).setDbKey("sonarqube");
209     db.components().insertProjectAndSnapshot(privateProjectFoundByKey);
210     ComponentDto privateProjectFoundByName = ComponentTesting.newPrivateProjectDto(organization).setName("name-sonar-name");
211     db.components().insertProjectAndSnapshot(privateProjectFoundByName);
212     ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
213     db.components().insertProjectAndSnapshot(projectUntouched);
214     loginAsAdmin(organization);
215
216     newRequest()
217       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
218       .setParam(Param.TEXT_QUERY, "SONAR")
219       .execute();
220
221     assertTemplate1AppliedToPrivateProject(privateProjectFoundByKey);
222     assertTemplate1AppliedToPrivateProject(privateProjectFoundByName);
223     assertNoPermissionOnProject(projectUntouched);
224   }
225
226   @Test
227   public void apply_template_by_project_keys() {
228     ComponentDto project1 = db.components().insertPrivateProject(organization);
229     ComponentDto project2 = db.components().insertPrivateProject(organization);
230     ComponentDto untouchedProject = db.components().insertPrivateProject(organization);
231     loginAsAdmin(organization);
232
233     newRequest()
234       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
235       .setParam(PARAM_PROJECTS, String.join(",", project1.getKey(), project2.getKey()))
236       .execute();
237
238     assertTemplate1AppliedToPrivateProject(project1);
239     assertTemplate1AppliedToPrivateProject(project2);
240     assertNoPermissionOnProject(untouchedProject);
241   }
242
243   @Test
244   public void apply_template_by_provisioned_only() {
245     ComponentDto provisionedProject1 = db.components().insertPrivateProject(organization);
246     ComponentDto provisionedProject2 = db.components().insertPrivateProject(organization);
247     ComponentDto analyzedProject = db.components().insertPrivateProject(organization);
248     db.components().insertSnapshot(newAnalysis(analyzedProject));
249     loginAsAdmin(organization);
250
251     newRequest()
252       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
253       .setParam(PARAM_ON_PROVISIONED_ONLY, "true")
254       .execute();
255
256     assertTemplate1AppliedToPrivateProject(provisionedProject1);
257     assertTemplate1AppliedToPrivateProject(provisionedProject2);
258     assertNoPermissionOnProject(analyzedProject);
259   }
260
261   @Test
262   public void apply_template_by_analyzed_before() {
263     ComponentDto oldProject1 = db.components().insertPrivateProject(organization);
264     ComponentDto oldProject2 = db.components().insertPrivateProject(organization);
265     ComponentDto recentProject = db.components().insertPrivateProject(organization);
266     db.components().insertSnapshot(oldProject1, a -> a.setCreatedAt(parseDate("2015-02-03").getTime()));
267     db.components().insertSnapshot(oldProject2, a -> a.setCreatedAt(parseDate("2016-12-11").getTime()));
268     db.components().insertSnapshot(recentProject, a -> a.setCreatedAt(System.currentTimeMillis()));
269     loginAsAdmin(organization);
270
271     newRequest()
272       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
273       .setParam(PARAM_ANALYZED_BEFORE, "2017-09-07")
274       .execute();
275
276     assertTemplate1AppliedToPrivateProject(oldProject1);
277     assertTemplate1AppliedToPrivateProject(oldProject2);
278     assertNoPermissionOnProject(recentProject);
279   }
280
281   @Test
282   public void apply_template_by_visibility() {
283     ComponentDto privateProject1 = db.components().insertPrivateProject(organization);
284     ComponentDto privateProject2 = db.components().insertPrivateProject(organization);
285     ComponentDto publicProject = db.components().insertPublicProject(organization);
286     loginAsAdmin(organization);
287
288     newRequest()
289       .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
290       .setParam(PARAM_VISIBILITY, "private")
291       .execute();
292
293     assertTemplate1AppliedToPrivateProject(privateProject1);
294     assertTemplate1AppliedToPrivateProject(privateProject2);
295     assertNoPermissionOnProject(publicProject);
296   }
297
298   @Test
299   public void fail_if_no_template_parameter() {
300     loginAsAdmin(db.getDefaultOrganization());
301
302     expectedException.expect(BadRequestException.class);
303     expectedException.expectMessage("Template name or template id must be provided, not both.");
304
305     newRequest().execute();
306   }
307
308   @Test
309   public void fail_if_template_name_is_incorrect() {
310     loginAsAdmin(db.getDefaultOrganization());
311
312     expectedException.expect(NotFoundException.class);
313     expectedException.expectMessage("Permission template with id 'unknown-template-uuid' is not found");
314
315     newRequest().setParam(PARAM_TEMPLATE_ID, "unknown-template-uuid").execute();
316   }
317
318   private void assertTemplate1AppliedToPublicProject(ComponentDto project) {
319     assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
320     assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
321     assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
322     assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
323     assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
324   }
325
326   private void assertTemplate1AppliedToPrivateProject(ComponentDto project) {
327     assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
328     assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
329     assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
330     assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
331     assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
332   }
333
334   private void assertNoPermissionOnProject(ComponentDto project) {
335     assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).isEmpty();
336     assertThat(selectProjectPermissionGroups(project, UserRole.CODEVIEWER)).isEmpty();
337     assertThat(selectProjectPermissionGroups(project, UserRole.ISSUE_ADMIN)).isEmpty();
338     assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
339     assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
340     assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
341     assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).isEmpty();
342     assertThat(selectProjectPermissionUsers(project, UserRole.USER)).isEmpty();
343   }
344
345   private void addUserToTemplate(UserDto user, PermissionTemplateDto permissionTemplate, String permission) {
346     db.getDbClient().permissionTemplateDao().insertUserPermission(db.getSession(), permissionTemplate.getId(), user.getId(), permission);
347     db.commit();
348   }
349
350   private void addGroupToTemplate(GroupDto group, PermissionTemplateDto permissionTemplate, String permission) {
351     db.getDbClient().permissionTemplateDao().insertGroupPermission(db.getSession(), permissionTemplate.getId(), group.getId(), permission);
352     db.commit();
353   }
354
355   private List<String> selectProjectPermissionGroups(ComponentDto project, String permission) {
356     PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
357     return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), query);
358   }
359
360   private List<Integer> selectProjectPermissionUsers(ComponentDto project, String permission) {
361     PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
362     return db.getDbClient().userPermissionDao().selectUserIdsByQuery(db.getSession(), query);
363   }
364 }