3 * Copyright (C) 2009-2018 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.resources.ResourceTypes;
29 import org.sonar.api.server.ws.WebService.Param;
30 import org.sonar.api.web.UserRole;
31 import org.sonar.db.component.ComponentDto;
32 import org.sonar.db.component.ComponentTesting;
33 import org.sonar.db.component.ResourceTypesRule;
34 import org.sonar.db.organization.OrganizationDto;
35 import org.sonar.db.permission.PermissionQuery;
36 import org.sonar.db.permission.template.PermissionTemplateDto;
37 import org.sonar.db.user.GroupDto;
38 import org.sonar.db.user.UserDto;
39 import org.sonar.server.es.ProjectIndexers;
40 import org.sonar.server.es.TestProjectIndexers;
41 import org.sonar.server.exceptions.BadRequestException;
42 import org.sonar.server.exceptions.NotFoundException;
43 import org.sonar.server.l18n.I18nRule;
44 import org.sonar.server.permission.PermissionService;
45 import org.sonar.server.permission.PermissionServiceImpl;
46 import org.sonar.server.permission.PermissionTemplateService;
47 import org.sonar.server.permission.ws.BasePermissionWsTest;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.sonar.api.utils.DateUtils.parseDate;
51 import static org.sonar.db.component.ComponentTesting.newApplication;
52 import static org.sonar.db.component.ComponentTesting.newView;
53 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
54 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_ORGANIZATION;
55 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
56 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
57 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
58 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
59 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
60 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
61 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
63 public class BulkApplyTemplateActionTest extends BasePermissionWsTest<BulkApplyTemplateAction> {
66 public DefaultTemplatesResolverRule defaultTemplatesResolver = DefaultTemplatesResolverRule.withoutGovernance();
68 private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
69 private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
71 private UserDto user1;
72 private UserDto user2;
73 private GroupDto group1;
74 private GroupDto group2;
75 private OrganizationDto organization;
76 private PermissionTemplateDto template1;
77 private PermissionTemplateDto template2;
78 private ProjectIndexers projectIndexers = new TestProjectIndexers();
81 protected BulkApplyTemplateAction buildWsAction() {
82 PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
83 projectIndexers, userSession, defaultTemplatesResolver, permissionService);
84 return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
89 organization = db.organizations().insert();
91 user1 = db.users().insertUser();
92 user2 = db.users().insertUser();
93 group1 = db.users().insertGroup(organization);
94 group2 = db.users().insertGroup(organization);
96 db.organizations().addMember(organization, user1);
97 db.organizations().addMember(organization, user2);
99 // template 1 for org 1
100 template1 = db.permissionTemplates().insertTemplate(organization);
101 addUserToTemplate(user1, template1, UserRole.CODEVIEWER);
102 addUserToTemplate(user2, template1, UserRole.ISSUE_ADMIN);
103 addGroupToTemplate(group1, template1, UserRole.ADMIN);
104 addGroupToTemplate(group2, template1, UserRole.USER);
106 template2 = db.permissionTemplates().insertTemplate(organization);
107 addUserToTemplate(user1, template2, UserRole.USER);
108 addUserToTemplate(user2, template2, UserRole.USER);
109 addGroupToTemplate(group1, template2, UserRole.USER);
110 addGroupToTemplate(group2, template2, UserRole.USER);
114 public void bulk_apply_template_by_template_uuid() {
115 // this project should not be applied the template
116 OrganizationDto otherOrganization = db.organizations().insert();
117 db.components().insertPrivateProject(otherOrganization);
119 ComponentDto privateProject = db.components().insertPrivateProject(organization);
120 ComponentDto publicProject = db.components().insertPublicProject(organization);
121 loginAsAdmin(organization);
124 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
127 assertTemplate1AppliedToPrivateProject(privateProject);
128 assertTemplate1AppliedToPublicProject(publicProject);
132 public void request_throws_NotFoundException_if_template_with_specified_name_does_not_exist_in_specified_organization() {
133 OrganizationDto otherOrganization = db.organizations().insert();
134 loginAsAdmin(otherOrganization);
136 expectedException.expect(NotFoundException.class);
137 expectedException.expectMessage("Permission template with name '" + template1.getName()
138 + "' is not found (case insensitive) in organization with key '" + otherOrganization.getKey() + "'");
141 .setParam(PARAM_ORGANIZATION, otherOrganization.getKey())
142 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
147 public void request_throws_IAE_if_more_than_1000_projects() {
148 expectedException.expect(IllegalArgumentException.class);
149 expectedException.expectMessage("'projects' can contains only 1000 values, got 1001");
152 .setParam(PARAM_ORGANIZATION, organization.getKey())
153 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
154 .setParam(PARAM_PROJECTS, StringUtils.join(Collections.nCopies(1_001, "foo"), ","))
159 public void bulk_apply_template_by_template_name() {
160 ComponentDto privateProject = db.components().insertPrivateProject(organization);
161 ComponentDto publicProject = db.components().insertPublicProject(organization);
162 loginAsAdmin(organization);
165 .setParam(PARAM_ORGANIZATION, organization.getKey())
166 .setParam(PARAM_TEMPLATE_NAME, template1.getName())
169 assertTemplate1AppliedToPrivateProject(privateProject);
170 assertTemplate1AppliedToPublicProject(publicProject);
174 public void apply_template_by_qualifiers() {
175 ComponentDto publicProject = db.components().insertPublicProject(organization);
176 ComponentDto privateProject = db.components().insertPrivateProject(organization);
177 ComponentDto view = db.components().insertComponent(newView(organization));
178 ComponentDto application = db.components().insertComponent(newApplication(organization));
179 loginAsAdmin(organization);
182 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
183 .setParam(PARAM_QUALIFIERS, String.join(",", Qualifiers.PROJECT, Qualifiers.APP))
186 assertTemplate1AppliedToPrivateProject(privateProject);
187 assertTemplate1AppliedToPublicProject(publicProject);
188 assertTemplate1AppliedToPublicProject(application);
189 assertNoPermissionOnProject(view);
193 public void apply_template_by_query_on_name_and_key_public_project() {
194 ComponentDto publicProjectFoundByKey = ComponentTesting.newPublicProjectDto(organization).setDbKey("sonar");
195 db.components().insertProjectAndSnapshot(publicProjectFoundByKey);
196 ComponentDto publicProjectFoundByName = ComponentTesting.newPublicProjectDto(organization).setName("name-sonar-name");
197 db.components().insertProjectAndSnapshot(publicProjectFoundByName);
198 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
199 db.components().insertProjectAndSnapshot(projectUntouched);
200 loginAsAdmin(organization);
203 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
204 .setParam(Param.TEXT_QUERY, "SONAR")
207 assertTemplate1AppliedToPublicProject(publicProjectFoundByKey);
208 assertTemplate1AppliedToPublicProject(publicProjectFoundByName);
209 assertNoPermissionOnProject(projectUntouched);
213 public void apply_template_by_query_on_name_and_key() {
214 // partial match on key
215 ComponentDto privateProjectFoundByKey = ComponentTesting.newPrivateProjectDto(organization).setDbKey("sonarqube");
216 db.components().insertProjectAndSnapshot(privateProjectFoundByKey);
217 ComponentDto privateProjectFoundByName = ComponentTesting.newPrivateProjectDto(organization).setName("name-sonar-name");
218 db.components().insertProjectAndSnapshot(privateProjectFoundByName);
219 ComponentDto projectUntouched = ComponentTesting.newPublicProjectDto(organization).setDbKey("new-sona").setName("project-name");
220 db.components().insertProjectAndSnapshot(projectUntouched);
221 loginAsAdmin(organization);
224 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
225 .setParam(Param.TEXT_QUERY, "SONAR")
228 assertTemplate1AppliedToPrivateProject(privateProjectFoundByKey);
229 assertTemplate1AppliedToPrivateProject(privateProjectFoundByName);
230 assertNoPermissionOnProject(projectUntouched);
234 public void apply_template_by_project_keys() {
235 ComponentDto project1 = db.components().insertPrivateProject(organization);
236 ComponentDto project2 = db.components().insertPrivateProject(organization);
237 ComponentDto untouchedProject = db.components().insertPrivateProject(organization);
238 loginAsAdmin(organization);
241 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
242 .setParam(PARAM_PROJECTS, String.join(",", project1.getKey(), project2.getKey()))
245 assertTemplate1AppliedToPrivateProject(project1);
246 assertTemplate1AppliedToPrivateProject(project2);
247 assertNoPermissionOnProject(untouchedProject);
251 public void apply_template_by_provisioned_only() {
252 ComponentDto provisionedProject1 = db.components().insertPrivateProject(organization);
253 ComponentDto provisionedProject2 = db.components().insertPrivateProject(organization);
254 ComponentDto analyzedProject = db.components().insertPrivateProject(organization);
255 db.components().insertSnapshot(newAnalysis(analyzedProject));
256 loginAsAdmin(organization);
259 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
260 .setParam(PARAM_ON_PROVISIONED_ONLY, "true")
263 assertTemplate1AppliedToPrivateProject(provisionedProject1);
264 assertTemplate1AppliedToPrivateProject(provisionedProject2);
265 assertNoPermissionOnProject(analyzedProject);
269 public void apply_template_by_analyzed_before() {
270 ComponentDto oldProject1 = db.components().insertPrivateProject(organization);
271 ComponentDto oldProject2 = db.components().insertPrivateProject(organization);
272 ComponentDto recentProject = db.components().insertPrivateProject(organization);
273 db.components().insertSnapshot(oldProject1, a -> a.setCreatedAt(parseDate("2015-02-03").getTime()));
274 db.components().insertSnapshot(oldProject2, a -> a.setCreatedAt(parseDate("2016-12-11").getTime()));
275 db.components().insertSnapshot(recentProject, a -> a.setCreatedAt(System.currentTimeMillis()));
276 loginAsAdmin(organization);
279 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
280 .setParam(PARAM_ANALYZED_BEFORE, "2017-09-07")
283 assertTemplate1AppliedToPrivateProject(oldProject1);
284 assertTemplate1AppliedToPrivateProject(oldProject2);
285 assertNoPermissionOnProject(recentProject);
289 public void apply_template_by_visibility() {
290 ComponentDto privateProject1 = db.components().insertPrivateProject(organization);
291 ComponentDto privateProject2 = db.components().insertPrivateProject(organization);
292 ComponentDto publicProject = db.components().insertPublicProject(organization);
293 loginAsAdmin(organization);
296 .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
297 .setParam(PARAM_VISIBILITY, "private")
300 assertTemplate1AppliedToPrivateProject(privateProject1);
301 assertTemplate1AppliedToPrivateProject(privateProject2);
302 assertNoPermissionOnProject(publicProject);
306 public void fail_if_no_template_parameter() {
307 loginAsAdmin(db.getDefaultOrganization());
309 expectedException.expect(BadRequestException.class);
310 expectedException.expectMessage("Template name or template id must be provided, not both.");
312 newRequest().execute();
316 public void fail_if_template_name_is_incorrect() {
317 loginAsAdmin(db.getDefaultOrganization());
319 expectedException.expect(NotFoundException.class);
320 expectedException.expectMessage("Permission template with id 'unknown-template-uuid' is not found");
322 newRequest().setParam(PARAM_TEMPLATE_ID, "unknown-template-uuid").execute();
325 private void assertTemplate1AppliedToPublicProject(ComponentDto project) {
326 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
327 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
328 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
329 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
330 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
333 private void assertTemplate1AppliedToPrivateProject(ComponentDto project) {
334 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).containsExactly(group1.getName());
335 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).containsExactly(group2.getName());
336 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
337 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).containsExactly(user1.getId());
338 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).containsExactly(user2.getId());
341 private void assertNoPermissionOnProject(ComponentDto project) {
342 assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).isEmpty();
343 assertThat(selectProjectPermissionGroups(project, UserRole.CODEVIEWER)).isEmpty();
344 assertThat(selectProjectPermissionGroups(project, UserRole.ISSUE_ADMIN)).isEmpty();
345 assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
346 assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
347 assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
348 assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).isEmpty();
349 assertThat(selectProjectPermissionUsers(project, UserRole.USER)).isEmpty();
352 private void addUserToTemplate(UserDto user, PermissionTemplateDto permissionTemplate, String permission) {
353 db.getDbClient().permissionTemplateDao().insertUserPermission(db.getSession(), permissionTemplate.getId(), user.getId(), permission);
357 private void addGroupToTemplate(GroupDto group, PermissionTemplateDto permissionTemplate, String permission) {
358 db.getDbClient().permissionTemplateDao().insertGroupPermission(db.getSession(), permissionTemplate.getId(), group.getId(), permission);
362 private List<String> selectProjectPermissionGroups(ComponentDto project, String permission) {
363 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
364 return db.getDbClient().groupPermissionDao().selectGroupNamesByQuery(db.getSession(), query);
367 private List<Integer> selectProjectPermissionUsers(ComponentDto project, String permission) {
368 PermissionQuery query = PermissionQuery.builder().setOrganizationUuid(project.getOrganizationUuid()).setPermission(permission).setComponentUuid(project.uuid()).build();
369 return db.getDbClient().userPermissionDao().selectUserIdsByQuery(db.getSession(), query);