3 * Copyright (C) 2009-2019 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.template;
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.DefaultTemplatesResolverRule;
43 import org.sonar.server.permission.PermissionTemplateService;
44 import org.sonar.server.permission.ws.BasePermissionWsTest;
46 import static org.assertj.core.api.Assertions.assertThat;
47 import static org.sonar.api.utils.DateUtils.parseDate;
48 import static org.sonar.db.component.ComponentTesting.newApplication;
49 import static org.sonar.db.component.ComponentTesting.newView;
50 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
51 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
52 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
53 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
54 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
55 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
56 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
57 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
58 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
60 public class BulkApplyTemplateActionTest extends BasePermissionWsTest<BulkApplyTemplateAction> {
63 public DefaultTemplatesResolverRule defaultTemplatesResolver = DefaultTemplatesResolverRule.withoutGovernance();
65 private UserDto user1;
66 private UserDto user2;
67 private GroupDto group1;
68 private GroupDto group2;
69 private OrganizationDto organization;
70 private PermissionTemplateDto template1;
71 private PermissionTemplateDto template2;
72 private ProjectIndexers projectIndexers = new TestProjectIndexers();
75 protected BulkApplyTemplateAction buildWsAction() {
76 PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
77 projectIndexers, userSession, defaultTemplatesResolver);
78 return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
83 organization = db.organizations().insert();
85 user1 = db.users().insertUser();
86 user2 = db.users().insertUser();
87 group1 = db.users().insertGroup(organization);
88 group2 = db.users().insertGroup(organization);
90 db.organizations().addMember(organization, user1);
91 db.organizations().addMember(organization, user2);
93 // template 1 for org 1
94 template1 = db.permissionTemplates().insertTemplate(organization);
95 addUserToTemplate(user1, template1, UserRole.CODEVIEWER);
96 addUserToTemplate(user2, template1, UserRole.ISSUE_ADMIN);
97 addGroupToTemplate(group1, template1, UserRole.ADMIN);
98 addGroupToTemplate(group2, template1, UserRole.USER);
100 template2 = db.permissionTemplates().insertTemplate(organization);
101 addUserToTemplate(user1, template2, UserRole.USER);
102 addUserToTemplate(user2, template2, UserRole.USER);
103 addGroupToTemplate(group1, template2, UserRole.USER);
104 addGroupToTemplate(group2, template2, UserRole.USER);
108 public void bulk_apply_template_by_template_uuid() {
109 // this project should not be applied the template
110 OrganizationDto otherOrganization = db.organizations().insert();
111 db.components().insertPrivateProject(otherOrganization);
113 ComponentDto privateProject = db.components().insertPrivateProject(organization);
114 ComponentDto publicProject = db.components().insertPublicProject(organization);
115 loginAsAdmin(organization);
118 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
121 assertTemplate1AppliedToPrivateProject(privateProject);
122 assertTemplate1AppliedToPublicProject(publicProject);
126 public void request_throws_NotFoundException_if_template_with_specified_name_does_not_exist_in_specified_organization() {
127 OrganizationDto otherOrganization = db.organizations().insert();
128 loginAsAdmin(otherOrganization);
130 expectedException.expect(NotFoundException.class);
131 expectedException.expectMessage("Permission template with name '" + template1.getName()
132 + "' is not found (case insensitive) in organization with key '" + otherOrganization.getKey() + "'");
135 .setParam(PARAM_ORGANIZATION, otherOrganization.getKey())
136 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
141 public void request_throws_IAE_if_more_than_1000_projects() {
142 expectedException.expect(IllegalArgumentException.class);
143 expectedException.expectMessage("'projects' can contains only 1000 values, got 1001");
146 .setParam(PARAM_ORGANIZATION, organization.getKey())
147 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
148 .setParam(PARAM_PROJECTS, StringUtils.join(Collections.nCopies(1_001, "foo"), ","))
153 public void bulk_apply_template_by_template_name() {
154 ComponentDto privateProject = db.components().insertPrivateProject(organization);
155 ComponentDto publicProject = db.components().insertPublicProject(organization);
156 loginAsAdmin(organization);
159 .setParam(PARAM_ORGANIZATION, organization.getKey())
160 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
163 assertTemplate1AppliedToPrivateProject(privateProject);
164 assertTemplate1AppliedToPublicProject(publicProject);
168 public void apply_template_by_qualifiers() {
169 ComponentDto publicProject = db.components().insertPublicProject(organization);
170 ComponentDto privateProject = db.components().insertPrivateProject(organization);
171 ComponentDto view = db.components().insertComponent(newView(organization));
172 ComponentDto application = db.components().insertComponent(newApplication(organization));
173 loginAsAdmin(organization);
176 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
177 .setParam(PARAM_QUALIFIERS, String.join(",", Qualifiers.PROJECT, Qualifiers.APP))
180 assertTemplate1AppliedToPrivateProject(privateProject);
181 assertTemplate1AppliedToPublicProject(publicProject);
182 assertTemplate1AppliedToPublicProject(application);
183 assertNoPermissionOnProject(view);
187 public void apply_template_by_query_on_name_and_key_public_project() {
188 ComponentDto publicProjectFoundByKey = ComponentTesting.newPublicProjectDto(organization).setDbKey("sonar");
189 db.components().insertProjectAndSnapshot(publicProjectFoundByKey);
190 ComponentDto publicProjectFoundByName = ComponentTesting.newPublicProjectDto(organization).setName("name-sonar-name");
191 db.components().insertProjectAndSnapshot(publicProjectFoundByName);
192 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
193 db.components().insertProjectAndSnapshot(projectUntouched);
194 loginAsAdmin(organization);
197 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
198 .setParam(Param.TEXT_QUERY, "SONAR")
201 assertTemplate1AppliedToPublicProject(publicProjectFoundByKey);
202 assertTemplate1AppliedToPublicProject(publicProjectFoundByName);
203 assertNoPermissionOnProject(projectUntouched);
207 public void apply_template_by_query_on_name_and_key() {
208 // partial match on key
209 ComponentDto privateProjectFoundByKey = ComponentTesting.newPrivateProjectDto(organization).setDbKey("sonarqube");
210 db.components().insertProjectAndSnapshot(privateProjectFoundByKey);
211 ComponentDto privateProjectFoundByName = ComponentTesting.newPrivateProjectDto(organization).setName("name-sonar-name");
212 db.components().insertProjectAndSnapshot(privateProjectFoundByName);
213 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
214 db.components().insertProjectAndSnapshot(projectUntouched);
215 loginAsAdmin(organization);
218 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
219 .setParam(Param.TEXT_QUERY, "SONAR")
222 assertTemplate1AppliedToPrivateProject(privateProjectFoundByKey);
223 assertTemplate1AppliedToPrivateProject(privateProjectFoundByName);
224 assertNoPermissionOnProject(projectUntouched);
228 public void apply_template_by_project_keys() {
229 ComponentDto project1 = db.components().insertPrivateProject(organization);
230 ComponentDto project2 = db.components().insertPrivateProject(organization);
231 ComponentDto untouchedProject = db.components().insertPrivateProject(organization);
232 loginAsAdmin(organization);
235 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
236 .setParam(PARAM_PROJECTS, String.join(",", project1.getKey(), project2.getKey()))
239 assertTemplate1AppliedToPrivateProject(project1);
240 assertTemplate1AppliedToPrivateProject(project2);
241 assertNoPermissionOnProject(untouchedProject);
245 public void apply_template_by_provisioned_only() {
246 ComponentDto provisionedProject1 = db.components().insertPrivateProject(organization);
247 ComponentDto provisionedProject2 = db.components().insertPrivateProject(organization);
248 ComponentDto analyzedProject = db.components().insertPrivateProject(organization);
249 db.components().insertSnapshot(newAnalysis(analyzedProject));
250 loginAsAdmin(organization);
253 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
254 .setParam(PARAM_ON_PROVISIONED_ONLY, "true")
257 assertTemplate1AppliedToPrivateProject(provisionedProject1);
258 assertTemplate1AppliedToPrivateProject(provisionedProject2);
259 assertNoPermissionOnProject(analyzedProject);
263 public void apply_template_by_analyzed_before() {
264 ComponentDto oldProject1 = db.components().insertPrivateProject(organization);
265 ComponentDto oldProject2 = db.components().insertPrivateProject(organization);
266 ComponentDto recentProject = db.components().insertPrivateProject(organization);
267 db.components().insertSnapshot(oldProject1, a -> a.setCreatedAt(parseDate("2015-02-03").getTime()));
268 db.components().insertSnapshot(oldProject2, a -> a.setCreatedAt(parseDate("2016-12-11").getTime()));
269 db.components().insertSnapshot(recentProject, a -> a.setCreatedAt(System.currentTimeMillis()));
270 loginAsAdmin(organization);
273 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
274 .setParam(PARAM_ANALYZED_BEFORE, "2017-09-07")
277 assertTemplate1AppliedToPrivateProject(oldProject1);
278 assertTemplate1AppliedToPrivateProject(oldProject2);
279 assertNoPermissionOnProject(recentProject);
283 public void apply_template_by_visibility() {
284 ComponentDto privateProject1 = db.components().insertPrivateProject(organization);
285 ComponentDto privateProject2 = db.components().insertPrivateProject(organization);
286 ComponentDto publicProject = db.components().insertPublicProject(organization);
287 loginAsAdmin(organization);
290 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
291 .setParam(PARAM_VISIBILITY, "private")
294 assertTemplate1AppliedToPrivateProject(privateProject1);
295 assertTemplate1AppliedToPrivateProject(privateProject2);
296 assertNoPermissionOnProject(publicProject);
300 public void fail_if_no_template_parameter() {
301 loginAsAdmin(db.getDefaultOrganization());
303 expectedException.expect(BadRequestException.class);
304 expectedException.expectMessage("Template name or template id must be provided, not both.");
306 newRequest().execute();
310 public void fail_if_template_name_is_incorrect() {
311 loginAsAdmin(db.getDefaultOrganization());
313 expectedException.expect(NotFoundException.class);
314 expectedException.expectMessage("Permission template with id 'unknown-template-uuid' is not found");
316 newRequest().setParam(PARAM_TEMPLATE_ID, "unknown-template-uuid").execute();
319 private void assertTemplate1AppliedToPublicProject(ComponentDto project) {
320 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
321 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
322 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
323 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
324 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
327 private void assertTemplate1AppliedToPrivateProject(ComponentDto project) {
328 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
329 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
330 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
331 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
332 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
335 private void assertNoPermissionOnProject(ComponentDto project) {
336 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).isEmpty();
337 assertThat(selectProjectPermissionGroups(project, UserRole.CODEVIEWER)).isEmpty();
338 assertThat(selectProjectPermissionGroups(project, UserRole.ISSUE_ADMIN)).isEmpty();
339 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
340 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
341 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
342 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).isEmpty();
343 assertThat(selectProjectPermissionUsers(project, UserRole.USER)).isEmpty();
346 private void addUserToTemplate(UserDto user, PermissionTemplateDto permissionTemplate, String permission) {
347 db.getDbClient().permissionTemplateDao().insertUserPermission(db.getSession(), permissionTemplate.getId(), user.getId(), permission);
351 private void addGroupToTemplate(GroupDto group, PermissionTemplateDto permissionTemplate, String permission) {
352 db.getDbClient().permissionTemplateDao().insertGroupPermission(db.getSession(), permissionTemplate.getId(), group.getId(), permission);
356 private List<String> selectProjectPermissionGroups(ComponentDto project, String permission) {
357 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
358 return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), query);
361 private List<Integer> selectProjectPermissionUsers(ComponentDto project, String permission) {
362 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
363 return db.getDbClient().userPermissionDao().selectUserIdsByQuery(db.getSession(), query);