You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UpdateVisibilityActionTest.java 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2018 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.project.ws;
  21. import java.util.Arrays;
  22. import java.util.Random;
  23. import java.util.Set;
  24. import java.util.stream.IntStream;
  25. import java.util.stream.Stream;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.junit.rules.ExpectedException;
  29. import org.sonar.api.resources.Qualifiers;
  30. import org.sonar.api.resources.ResourceTypes;
  31. import org.sonar.api.server.ws.WebService;
  32. import org.sonar.api.utils.System2;
  33. import org.sonar.api.web.UserRole;
  34. import org.sonar.core.util.stream.MoreCollectors;
  35. import org.sonar.db.DbClient;
  36. import org.sonar.db.DbSession;
  37. import org.sonar.db.DbTester;
  38. import org.sonar.db.ce.CeQueueDto;
  39. import org.sonar.db.component.BranchDto;
  40. import org.sonar.db.component.ComponentDto;
  41. import org.sonar.db.component.ComponentTesting;
  42. import org.sonar.db.component.ResourceTypesRule;
  43. import org.sonar.db.organization.OrganizationDto;
  44. import org.sonar.db.permission.GroupPermissionDto;
  45. import org.sonar.db.permission.OrganizationPermission;
  46. import org.sonar.db.permission.UserPermissionDto;
  47. import org.sonar.db.user.GroupDto;
  48. import org.sonar.db.user.UserDto;
  49. import org.sonar.server.component.TestComponentFinder;
  50. import org.sonar.server.es.EsTester;
  51. import org.sonar.server.es.ProjectIndexer;
  52. import org.sonar.server.es.TestProjectIndexers;
  53. import org.sonar.server.exceptions.BadRequestException;
  54. import org.sonar.server.exceptions.ForbiddenException;
  55. import org.sonar.server.exceptions.NotFoundException;
  56. import org.sonar.server.exceptions.UnauthorizedException;
  57. import org.sonar.server.organization.BillingValidations;
  58. import org.sonar.server.organization.BillingValidationsProxy;
  59. import org.sonar.server.organization.TestDefaultOrganizationProvider;
  60. import org.sonar.server.permission.PermissionService;
  61. import org.sonar.server.permission.PermissionServiceImpl;
  62. import org.sonar.server.permission.index.FooIndexDefinition;
  63. import org.sonar.server.tester.UserSessionRule;
  64. import org.sonar.server.ws.TestRequest;
  65. import org.sonar.server.ws.WsActionTester;
  66. import static java.lang.String.format;
  67. import static java.util.Arrays.stream;
  68. import static org.assertj.core.api.Assertions.assertThat;
  69. import static org.assertj.core.api.Assertions.fail;
  70. import static org.mockito.ArgumentMatchers.any;
  71. import static org.mockito.ArgumentMatchers.eq;
  72. import static org.mockito.Mockito.doThrow;
  73. import static org.mockito.Mockito.mock;
  74. import static org.sonar.db.component.ComponentTesting.newProjectCopy;
  75. import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
  76. public class UpdateVisibilityActionTest {
  77. private static final String PARAM_VISIBILITY = "visibility";
  78. private static final String PARAM_PROJECT = "project";
  79. private static final String PUBLIC = "public";
  80. private static final String PRIVATE = "private";
  81. private static final Set<String> ORGANIZATION_PERMISSIONS_NAME_SET = stream(OrganizationPermission.values()).map(OrganizationPermission::getKey)
  82. .collect(MoreCollectors.toSet(OrganizationPermission.values().length));
  83. @Rule
  84. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  85. @Rule
  86. public EsTester es = EsTester.createCustom(new FooIndexDefinition());
  87. @Rule
  88. public UserSessionRule userSessionRule = UserSessionRule.standalone().logIn();
  89. @Rule
  90. public ExpectedException expectedException = ExpectedException.none();
  91. private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
  92. private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
  93. private final Set<String> PROJECT_PERMISSIONS_BUT_USER_AND_CODEVIEWER = permissionService.getAllProjectPermissions().stream()
  94. .filter(perm -> !perm.equals(UserRole.USER) && !perm.equals(UserRole.CODEVIEWER))
  95. .collect(MoreCollectors.toSet(permissionService.getAllProjectPermissions().size() - 2));
  96. private DbClient dbClient = dbTester.getDbClient();
  97. private DbSession dbSession = dbTester.getSession();
  98. private TestProjectIndexers projectIndexers = new TestProjectIndexers();
  99. private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class);
  100. private ProjectsWsSupport wsSupport = new ProjectsWsSupport(dbClient, TestDefaultOrganizationProvider.from(dbTester), billingValidations);
  101. private UpdateVisibilityAction underTest = new UpdateVisibilityAction(dbClient, TestComponentFinder.from(dbTester), userSessionRule, projectIndexers, wsSupport);
  102. private WsActionTester ws = new WsActionTester(underTest);
  103. private final Random random = new Random();
  104. private final String randomVisibility = random.nextBoolean() ? PUBLIC : PRIVATE;
  105. private final TestRequest request = ws.newRequest();
  106. @Test
  107. public void definition() {
  108. WebService.Action definition = ws.getDef();
  109. assertThat(definition.key()).isEqualTo("update_visibility");
  110. assertThat(definition.isPost()).isTrue();
  111. assertThat(definition.since()).isEqualTo("6.4");
  112. assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "visibility");
  113. }
  114. @Test
  115. public void execute_fails_if_user_is_not_logged_in() {
  116. userSessionRule.anonymous();
  117. expectedException.expect(UnauthorizedException.class);
  118. expectedException.expectMessage("Authentication is required");
  119. request.execute();
  120. }
  121. @Test
  122. public void execute_fails_with_IAE_when_project_parameter_is_not_provided() {
  123. expectedException.expect(IllegalArgumentException.class);
  124. expectedException.expectMessage("The 'project' parameter is missing");
  125. request.execute();
  126. }
  127. @Test
  128. public void execute_fails_with_IAE_when_project_parameter_is_not_empty() {
  129. expectedException.expect(IllegalArgumentException.class);
  130. expectedException.expectMessage("The 'project' parameter is missing");
  131. request.execute();
  132. }
  133. @Test
  134. public void execute_fails_with_IAE_when_parameter_visibility_is_not_provided() {
  135. request.setParam(PARAM_PROJECT, "foo");
  136. expectedException.expect(IllegalArgumentException.class);
  137. expectedException.expectMessage("The 'visibility' parameter is missing");
  138. request.execute();
  139. }
  140. @Test
  141. public void execute_fails_with_IAE_when_parameter_visibility_is_empty() {
  142. request.setParam(PARAM_PROJECT, "foo")
  143. .setParam(PARAM_VISIBILITY, "");
  144. expectedException.expect(IllegalArgumentException.class);
  145. expectedException.expectMessage("Value of parameter '" + PARAM_VISIBILITY + "' () must be one of: [private, public]");
  146. request.execute();
  147. }
  148. @Test
  149. public void execute_fails_with_IAE_when_value_of_parameter_visibility_is_not_lowercase() {
  150. request.setParam(PARAM_PROJECT, "foo");
  151. Stream.of("PUBLIC", "pUBliC", "PRIVATE", "PrIVAtE")
  152. .forEach(visibility -> {
  153. try {
  154. request.setParam(PARAM_VISIBILITY, visibility).execute();
  155. fail("An exception should have been raised");
  156. } catch (IllegalArgumentException e) {
  157. assertThat(e.getMessage()).isEqualTo(format("Value of parameter '%s' (%s) must be one of: [private, public]", PARAM_VISIBILITY, visibility));
  158. }
  159. });
  160. }
  161. @Test
  162. public void execute_fails_with_NotFoundException_when_specified_component_does_not_exist() {
  163. request.setParam(PARAM_PROJECT, "foo")
  164. .setParam(PARAM_VISIBILITY, randomVisibility);
  165. expectedException.expect(NotFoundException.class);
  166. expectedException.expectMessage("Component key 'foo' not found");
  167. request.execute();
  168. }
  169. @Test
  170. public void execute_fails_with_BadRequestException_if_specified_component_is_neither_a_project_a_portfolio_nor_an_application() {
  171. OrganizationDto organization = dbTester.organizations().insert();
  172. ComponentDto project = randomPublicOrPrivateProject();
  173. ComponentDto module = ComponentTesting.newModuleDto(project);
  174. ComponentDto dir = ComponentTesting.newDirectory(project, "path");
  175. ComponentDto file = ComponentTesting.newFileDto(project);
  176. dbTester.components().insertComponents(module, dir, file);
  177. ComponentDto application = dbTester.components().insertApplication(organization);
  178. ComponentDto portfolio = dbTester.components().insertView(organization);
  179. ComponentDto subView = ComponentTesting.newSubView(portfolio);
  180. ComponentDto projectCopy = newProjectCopy("foo", project, subView);
  181. dbTester.components().insertComponents(subView, projectCopy);
  182. userSessionRule.addProjectPermission(UserRole.ADMIN, project, portfolio, application);
  183. Stream.of(project, portfolio, application).forEach(c -> request
  184. .setParam(PARAM_PROJECT, c.getDbKey())
  185. .setParam(PARAM_VISIBILITY, randomVisibility)
  186. .execute());
  187. Stream.of(module, dir, file, subView, projectCopy)
  188. .forEach(nonRootComponent -> {
  189. request.setParam(PARAM_PROJECT, nonRootComponent.getDbKey())
  190. .setParam(PARAM_VISIBILITY, randomVisibility);
  191. try {
  192. request.execute();
  193. fail("a BadRequestException should have been raised");
  194. } catch (BadRequestException e) {
  195. assertThat(e.getMessage()).isEqualTo("Component must be a project, a portfolio or an application");
  196. }
  197. });
  198. }
  199. @Test
  200. public void execute_throws_ForbiddenException_if_user_has_no_permission_on_specified_component() {
  201. OrganizationDto organization = dbTester.organizations().insert();
  202. ComponentDto project = dbTester.components().insertPrivateProject(organization);
  203. request.setParam(PARAM_PROJECT, project.getDbKey())
  204. .setParam(PARAM_VISIBILITY, randomVisibility);
  205. expectInsufficientPrivilegeException();
  206. request.execute();
  207. }
  208. @Test
  209. public void execute_throws_ForbiddenException_if_user_has_all_permissions_but_ADMIN_on_specified_component() {
  210. OrganizationDto organization = dbTester.organizations().insert();
  211. ComponentDto project = dbTester.components().insertPublicProject(organization);
  212. request.setParam(PARAM_PROJECT, project.getDbKey())
  213. .setParam(PARAM_VISIBILITY, randomVisibility);
  214. userSessionRule.addProjectPermission(UserRole.ISSUE_ADMIN, project);
  215. Arrays.stream(OrganizationPermission.values())
  216. .forEach(perm -> userSessionRule.addPermission(perm, organization));
  217. request.setParam(PARAM_PROJECT, project.getDbKey())
  218. .setParam(PARAM_VISIBILITY, randomVisibility);
  219. expectInsufficientPrivilegeException();
  220. request.execute();
  221. }
  222. @Test
  223. public void execute_throws_BadRequestException_if_specified_component_has_pending_tasks() {
  224. ComponentDto project = randomPublicOrPrivateProject();
  225. IntStream.range(0, 1 + Math.abs(random.nextInt(5)))
  226. .forEach(i -> insertPendingTask(project));
  227. request.setParam(PARAM_PROJECT, project.getDbKey())
  228. .setParam(PARAM_VISIBILITY, randomVisibility);
  229. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  230. expectedException.expect(BadRequestException.class);
  231. expectedException.expectMessage("Component visibility can't be changed as long as it has background task(s) pending or in progress");
  232. request.execute();
  233. }
  234. @Test
  235. public void execute_throws_BadRequestException_if_main_component_of_specified_component_has_in_progress_tasks() {
  236. ComponentDto project = randomPublicOrPrivateProject();
  237. IntStream.range(0, 1 + Math.abs(random.nextInt(5)))
  238. .forEach(i -> insertInProgressTask(project));
  239. request.setParam(PARAM_PROJECT, project.getDbKey())
  240. .setParam(PARAM_VISIBILITY, randomVisibility);
  241. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  242. expectedException.expect(BadRequestException.class);
  243. expectedException.expectMessage("Component visibility can't be changed as long as it has background task(s) pending or in progress");
  244. request.execute();
  245. }
  246. @Test
  247. public void execute_throws_ISE_when_project_organization_uuid_does_not_match_existing_organization() {
  248. // Organization is not persisted
  249. OrganizationDto organization = newOrganizationDto();
  250. ComponentDto project = dbTester.components().insertPublicProject(organization);
  251. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  252. expectedException.expect(IllegalStateException.class);
  253. expectedException.expectMessage(format("Could not find organization with uuid '%s' of project '%s'", organization.getUuid(), project.getDbKey()));
  254. request.setParam(PARAM_PROJECT, project.getDbKey())
  255. .setParam(PARAM_VISIBILITY, PRIVATE)
  256. .execute();
  257. }
  258. @Test
  259. public void execute_changes_private_flag_of_specified_project_and_all_children_to_specified_new_visibility() {
  260. ComponentDto project = randomPublicOrPrivateProject();
  261. boolean initiallyPrivate = project.isPrivate();
  262. BranchDto branchDto = ComponentTesting.newBranchDto(project);
  263. dbClient.branchDao().insert(dbSession, branchDto);
  264. ComponentDto branch = ComponentTesting.newProjectBranch(project, branchDto);
  265. ComponentDto module = ComponentTesting.newModuleDto(project);
  266. ComponentDto dir = ComponentTesting.newDirectory(project, "path");
  267. ComponentDto file = ComponentTesting.newFileDto(project);
  268. dbTester.components().insertComponents(branch, module, dir, file);
  269. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  270. request.setParam(PARAM_PROJECT, project.getDbKey())
  271. .setParam(PARAM_VISIBILITY, initiallyPrivate ? PUBLIC : PRIVATE)
  272. .execute();
  273. assertThat(isPrivateInDb(project)).isEqualTo(!initiallyPrivate);
  274. assertThat(isPrivateInDb(branch)).isEqualTo(!initiallyPrivate);
  275. assertThat(isPrivateInDb(module)).isEqualTo(!initiallyPrivate);
  276. assertThat(isPrivateInDb(dir)).isEqualTo(!initiallyPrivate);
  277. assertThat(isPrivateInDb(file)).isEqualTo(!initiallyPrivate);
  278. }
  279. @Test
  280. public void execute_has_no_effect_if_specified_project_already_has_specified_visibility() {
  281. ComponentDto project = randomPublicOrPrivateProject();
  282. boolean initiallyPrivate = project.isPrivate();
  283. BranchDto branchDto = ComponentTesting.newBranchDto(project);
  284. dbClient.branchDao().insert(dbSession, branchDto);
  285. ComponentDto branch = ComponentTesting.newProjectBranch(project, branchDto)
  286. .setPrivate(initiallyPrivate);
  287. ComponentDto module = ComponentTesting.newModuleDto(project)
  288. .setPrivate(initiallyPrivate);
  289. ComponentDto dir = ComponentTesting.newDirectory(project, "path")
  290. // child is inconsistent with root (should not occur) and won't be fixed
  291. .setPrivate(!initiallyPrivate);
  292. ComponentDto file = ComponentTesting.newFileDto(project)
  293. .setPrivate(initiallyPrivate);
  294. dbTester.components().insertComponents(branch, module, dir, file);
  295. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  296. request.setParam(PARAM_PROJECT, project.getDbKey())
  297. .setParam(PARAM_VISIBILITY, initiallyPrivate ? PRIVATE : PUBLIC)
  298. .execute();
  299. assertThat(isPrivateInDb(project)).isEqualTo(initiallyPrivate);
  300. assertThat(isPrivateInDb(branch)).isEqualTo(initiallyPrivate);
  301. assertThat(isPrivateInDb(module)).isEqualTo(initiallyPrivate);
  302. assertThat(isPrivateInDb(dir)).isEqualTo(!initiallyPrivate);
  303. assertThat(isPrivateInDb(file)).isEqualTo(initiallyPrivate);
  304. }
  305. @Test
  306. public void execute_deletes_all_permissions_to_Anyone_on_specified_project_when_new_visibility_is_private() {
  307. OrganizationDto organization = dbTester.organizations().insert();
  308. ComponentDto project = dbTester.components().insertPublicProject(organization);
  309. UserDto user = dbTester.users().insertUser();
  310. GroupDto group = dbTester.users().insertGroup(organization);
  311. unsafeGiveAllPermissionsToRootComponent(project, user, group, organization);
  312. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  313. request.setParam(PARAM_PROJECT, project.getDbKey())
  314. .setParam(PARAM_VISIBILITY, PRIVATE)
  315. .execute();
  316. verifyHasAllPermissionsButProjectPermissionsToGroupAnyOne(project, user, group);
  317. }
  318. @Test
  319. public void execute_does_not_delete_all_permissions_to_AnyOne_on_specified_project_if_already_private() {
  320. OrganizationDto organization = dbTester.organizations().insert();
  321. ComponentDto project = dbTester.components().insertPrivateProject(organization);
  322. UserDto user = dbTester.users().insertUser();
  323. GroupDto group = dbTester.users().insertGroup(organization);
  324. unsafeGiveAllPermissionsToRootComponent(project, user, group, organization);
  325. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  326. request.setParam(PARAM_PROJECT, project.getDbKey())
  327. .setParam(PARAM_VISIBILITY, PRIVATE)
  328. .execute();
  329. verifyStillHasAllPermissions(project, user, group);
  330. }
  331. @Test
  332. public void execute_deletes_all_permissions_USER_and_BROWSE_of_specified_project_when_new_visibility_is_public() {
  333. OrganizationDto organization = dbTester.organizations().insert();
  334. ComponentDto project = dbTester.components().insertPrivateProject(organization);
  335. UserDto user = dbTester.users().insertUser();
  336. GroupDto group = dbTester.users().insertGroup(organization);
  337. unsafeGiveAllPermissionsToRootComponent(project, user, group, organization);
  338. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  339. request.setParam(PARAM_PROJECT, project.getDbKey())
  340. .setParam(PARAM_VISIBILITY, PUBLIC)
  341. .execute();
  342. verifyHasAllPermissionsButProjectPermissionsUserAndBrowse(project, user, group);
  343. }
  344. @Test
  345. public void execute_does_not_delete_permissions_USER_and_BROWSE_of_specified_project_when_new_component_is_already_public() {
  346. OrganizationDto organization = dbTester.organizations().insert();
  347. ComponentDto project = dbTester.components().insertPublicProject(organization);
  348. UserDto user = dbTester.users().insertUser();
  349. GroupDto group = dbTester.users().insertGroup(organization);
  350. unsafeGiveAllPermissionsToRootComponent(project, user, group, organization);
  351. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  352. request.setParam(PARAM_PROJECT, project.getDbKey())
  353. .setParam(PARAM_VISIBILITY, PUBLIC)
  354. .execute();
  355. verifyStillHasAllPermissions(project, user, group);
  356. }
  357. @Test
  358. public void execute_updates_permission_of_specified_project_in_indexes_when_changing_visibility() {
  359. ComponentDto project = randomPublicOrPrivateProject();
  360. boolean initiallyPrivate = project.isPrivate();
  361. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  362. request.setParam(PARAM_PROJECT, project.getDbKey())
  363. .setParam(PARAM_VISIBILITY, initiallyPrivate ? PUBLIC : PRIVATE)
  364. .execute();
  365. assertThat(projectIndexers.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.PERMISSION_CHANGE)).isTrue();
  366. }
  367. @Test
  368. public void execute_does_not_update_permission_of_specified_project_in_indexes_if_already_has_specified_visibility() {
  369. ComponentDto project = randomPublicOrPrivateProject();
  370. boolean initiallyPrivate = project.isPrivate();
  371. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  372. request.setParam(PARAM_PROJECT, project.getDbKey())
  373. .setParam(PARAM_VISIBILITY, initiallyPrivate ? PRIVATE : PUBLIC)
  374. .execute();
  375. assertThat(projectIndexers.hasBeenCalled(project.uuid())).isFalse();
  376. }
  377. @Test
  378. public void execute_grants_USER_and_CODEVIEWER_permissions_to_any_user_with_at_least_one_permission_when_making_project_private() {
  379. OrganizationDto organization = dbTester.organizations().insert();
  380. ComponentDto project = dbTester.components().insertPublicProject(organization);
  381. UserDto user1 = dbTester.users().insertUser();
  382. UserDto user2 = dbTester.users().insertUser();
  383. UserDto user3 = dbTester.users().insertUser();
  384. dbTester.users().insertProjectPermissionOnUser(user1, "p1", project);
  385. dbTester.users().insertProjectPermissionOnUser(user1, "p2", project);
  386. dbTester.users().insertProjectPermissionOnUser(user2, "p2", project);
  387. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  388. request.setParam(PARAM_PROJECT, project.getDbKey())
  389. .setParam(PARAM_VISIBILITY, PRIVATE)
  390. .execute();
  391. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user1.getId(), project.getId()))
  392. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, "p1", "p2");
  393. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user2.getId(), project.getId()))
  394. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, "p2");
  395. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user3.getId(), project.getId()))
  396. .isEmpty();
  397. }
  398. @Test
  399. public void execute_grants_USER_and_CODEVIEWER_permissions_to_any_group_with_at_least_one_permission_when_making_project_private() {
  400. OrganizationDto organization = dbTester.organizations().insert();
  401. ComponentDto project = dbTester.components().insertPublicProject(organization);
  402. GroupDto group1 = dbTester.users().insertGroup(organization);
  403. GroupDto group2 = dbTester.users().insertGroup(organization);
  404. GroupDto group3 = dbTester.users().insertGroup(organization);
  405. dbTester.users().insertProjectPermissionOnGroup(group1, "p1", project);
  406. dbTester.users().insertProjectPermissionOnGroup(group1, "p2", project);
  407. dbTester.users().insertProjectPermissionOnGroup(group2, "p2", project);
  408. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  409. request.setParam(PARAM_PROJECT, project.getDbKey())
  410. .setParam(PARAM_VISIBILITY, PRIVATE)
  411. .execute();
  412. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group1.getId(), project.getId()))
  413. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, "p1", "p2");
  414. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group2.getId(), project.getId()))
  415. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, "p2");
  416. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group3.getId(), project.getId()))
  417. .isEmpty();
  418. }
  419. @Test
  420. public void update_a_portfolio_to_private() {
  421. OrganizationDto organization = dbTester.organizations().insert();
  422. ComponentDto portfolio = dbTester.components().insertPublicPortfolio(organization);
  423. GroupDto group = dbTester.users().insertGroup(organization);
  424. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, portfolio);
  425. UserDto user = dbTester.users().insertUser();
  426. dbTester.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, portfolio);
  427. userSessionRule.addProjectPermission(UserRole.ADMIN, portfolio);
  428. request.setParam(PARAM_PROJECT, portfolio.getDbKey())
  429. .setParam(PARAM_VISIBILITY, PRIVATE)
  430. .execute();
  431. assertThat(dbClient.componentDao().selectByUuid(dbSession, portfolio.uuid()).get().isPrivate()).isTrue();
  432. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group.getId(), portfolio.getId()))
  433. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN);
  434. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), portfolio.getId()))
  435. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN);
  436. }
  437. @Test
  438. public void update_a_portfolio_to_public() {
  439. OrganizationDto organization = dbTester.organizations().insert();
  440. ComponentDto portfolio = dbTester.components().insertPrivatePortfolio(organization);
  441. userSessionRule.addProjectPermission(UserRole.ADMIN, portfolio);
  442. GroupDto group = dbTester.users().insertGroup(organization);
  443. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, portfolio);
  444. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.USER, portfolio);
  445. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.CODEVIEWER, portfolio);
  446. UserDto user = dbTester.users().insertUser();
  447. dbTester.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, portfolio);
  448. dbTester.users().insertProjectPermissionOnUser(user, UserRole.USER, portfolio);
  449. dbTester.users().insertProjectPermissionOnUser(user, UserRole.CODEVIEWER, portfolio);
  450. request.setParam(PARAM_PROJECT, portfolio.getDbKey())
  451. .setParam(PARAM_VISIBILITY, PUBLIC)
  452. .execute();
  453. assertThat(dbClient.componentDao().selectByUuid(dbSession, portfolio.uuid()).get().isPrivate()).isFalse();
  454. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group.getId(), portfolio.getId()))
  455. .containsOnly(UserRole.ISSUE_ADMIN);
  456. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), portfolio.getId()))
  457. .containsOnly(UserRole.ADMIN);
  458. }
  459. @Test
  460. public void update_an_application_to_private() {
  461. OrganizationDto organization = dbTester.organizations().insert();
  462. ComponentDto application = dbTester.components().insertPublicApplication(organization);
  463. GroupDto group = dbTester.users().insertGroup(organization);
  464. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, application);
  465. UserDto user = dbTester.users().insertUser();
  466. dbTester.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, application);
  467. userSessionRule.addProjectPermission(UserRole.ADMIN, application);
  468. request.setParam(PARAM_PROJECT, application.getDbKey())
  469. .setParam(PARAM_VISIBILITY, PRIVATE)
  470. .execute();
  471. assertThat(dbClient.componentDao().selectByUuid(dbSession, application.uuid()).get().isPrivate()).isTrue();
  472. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group.getId(), application.getId()))
  473. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN);
  474. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), application.getId()))
  475. .containsOnly(UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN);
  476. }
  477. @Test
  478. public void update_an_application_to_public() {
  479. OrganizationDto organization = dbTester.organizations().insert();
  480. ComponentDto portfolio = dbTester.components().insertPrivateApplication(organization);
  481. userSessionRule.addProjectPermission(UserRole.ADMIN, portfolio);
  482. GroupDto group = dbTester.users().insertGroup(organization);
  483. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.ISSUE_ADMIN, portfolio);
  484. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.USER, portfolio);
  485. dbTester.users().insertProjectPermissionOnGroup(group, UserRole.CODEVIEWER, portfolio);
  486. UserDto user = dbTester.users().insertUser();
  487. dbTester.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, portfolio);
  488. dbTester.users().insertProjectPermissionOnUser(user, UserRole.USER, portfolio);
  489. dbTester.users().insertProjectPermissionOnUser(user, UserRole.CODEVIEWER, portfolio);
  490. request.setParam(PARAM_PROJECT, portfolio.getDbKey())
  491. .setParam(PARAM_VISIBILITY, PUBLIC)
  492. .execute();
  493. assertThat(dbClient.componentDao().selectByUuid(dbSession, portfolio.uuid()).get().isPrivate()).isFalse();
  494. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, organization.getUuid(), group.getId(), portfolio.getId()))
  495. .containsOnly(UserRole.ISSUE_ADMIN);
  496. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), portfolio.getId()))
  497. .containsOnly(UserRole.ADMIN);
  498. }
  499. @Test
  500. public void fail_to_update_visibility_to_private_when_organization_is_not_allowed_to_use_private_projects() {
  501. OrganizationDto organization = dbTester.organizations().insert();
  502. ComponentDto project = dbTester.components().insertPublicProject(organization);
  503. dbTester.organizations().setNewProjectPrivate(organization, true);
  504. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  505. doThrow(new BillingValidations.BillingValidationsException("This organization cannot use project private")).when(billingValidations)
  506. .checkCanUpdateProjectVisibility(any(BillingValidations.Organization.class), eq(true));
  507. expectedException.expect(IllegalArgumentException.class);
  508. expectedException.expectMessage("This organization cannot use project private");
  509. request.setParam(PARAM_PROJECT, project.getDbKey())
  510. .setParam(PARAM_VISIBILITY, PRIVATE)
  511. .execute();
  512. }
  513. @Test
  514. public void does_not_fail_to_update_visibility_to_public_when_organization_is_not_allowed_to_use_private_projects() {
  515. OrganizationDto organization = dbTester.organizations().insert();
  516. ComponentDto project = dbTester.components().insertPublicProject(organization);
  517. dbTester.organizations().setNewProjectPrivate(organization, true);
  518. userSessionRule.addProjectPermission(UserRole.ADMIN, project);
  519. doThrow(new BillingValidations.BillingValidationsException("This organization cannot use project private")).when(billingValidations)
  520. .checkCanUpdateProjectVisibility(any(BillingValidations.Organization.class), eq(true));
  521. request.setParam(PARAM_PROJECT, project.getDbKey())
  522. .setParam(PARAM_VISIBILITY, PUBLIC)
  523. .execute();
  524. }
  525. @Test
  526. public void fail_when_using_branch_db_key() throws Exception {
  527. ComponentDto project = dbTester.components().insertMainBranch();
  528. userSessionRule.logIn().addProjectPermission(UserRole.USER, project);
  529. ComponentDto branch = dbTester.components().insertProjectBranch(project);
  530. expectedException.expect(NotFoundException.class);
  531. expectedException.expectMessage(String.format("Component key '%s' not found", branch.getDbKey()));
  532. request.setParam(PARAM_PROJECT, branch.getDbKey())
  533. .setParam(PARAM_VISIBILITY, PUBLIC)
  534. .execute();
  535. }
  536. private void unsafeGiveAllPermissionsToRootComponent(ComponentDto component, UserDto user, GroupDto group, OrganizationDto organization) {
  537. Arrays.stream(OrganizationPermission.values())
  538. .forEach(organizationPermission -> {
  539. dbTester.users().insertPermissionOnAnyone(organization, organizationPermission);
  540. dbTester.users().insertPermissionOnGroup(group, organizationPermission);
  541. dbTester.users().insertPermissionOnUser(organization, user, organizationPermission);
  542. });
  543. permissionService.getAllProjectPermissions()
  544. .forEach(permission -> {
  545. unsafeInsertProjectPermissionOnAnyone(component, permission);
  546. unsafeInsertProjectPermissionOnGroup(component, group, permission);
  547. unsafeInsertProjectPermissionOnUser(component, user, permission);
  548. });
  549. }
  550. private void unsafeInsertProjectPermissionOnAnyone(ComponentDto component, String permission) {
  551. GroupPermissionDto dto = new GroupPermissionDto()
  552. .setOrganizationUuid(component.getOrganizationUuid())
  553. .setGroupId(null)
  554. .setRole(permission)
  555. .setResourceId(component.getId());
  556. dbTester.getDbClient().groupPermissionDao().insert(dbTester.getSession(), dto);
  557. dbTester.commit();
  558. }
  559. private void unsafeInsertProjectPermissionOnGroup(ComponentDto component, GroupDto group, String permission) {
  560. GroupPermissionDto dto = new GroupPermissionDto()
  561. .setOrganizationUuid(group.getOrganizationUuid())
  562. .setGroupId(group.getId())
  563. .setRole(permission)
  564. .setResourceId(component.getId());
  565. dbTester.getDbClient().groupPermissionDao().insert(dbTester.getSession(), dto);
  566. dbTester.commit();
  567. }
  568. private void unsafeInsertProjectPermissionOnUser(ComponentDto component, UserDto user, String permission) {
  569. UserPermissionDto dto = new UserPermissionDto(component.getOrganizationUuid(), permission, user.getId(), component.getId());
  570. dbTester.getDbClient().userPermissionDao().insert(dbTester.getSession(), dto);
  571. dbTester.commit();
  572. }
  573. private void verifyHasAllPermissionsButProjectPermissionsToGroupAnyOne(ComponentDto component, UserDto user, GroupDto group) {
  574. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null))
  575. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  576. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId()))
  577. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  578. assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), component.getOrganizationUuid()))
  579. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  580. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null, component.getId()))
  581. .isEmpty();
  582. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId(), component.getId()))
  583. .containsAll(permissionService.getAllProjectPermissions());
  584. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), component.getId()))
  585. .containsAll(permissionService.getAllProjectPermissions());
  586. }
  587. private void verifyHasAllPermissionsButProjectPermissionsUserAndBrowse(ComponentDto component, UserDto user, GroupDto group) {
  588. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null))
  589. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  590. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId()))
  591. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  592. assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), component.getOrganizationUuid()))
  593. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  594. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null, component.getId()))
  595. .doesNotContain(UserRole.USER)
  596. .doesNotContain(UserRole.CODEVIEWER)
  597. .containsAll(PROJECT_PERMISSIONS_BUT_USER_AND_CODEVIEWER);
  598. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId(), component.getId()))
  599. .doesNotContain(UserRole.USER)
  600. .doesNotContain(UserRole.CODEVIEWER)
  601. .containsAll(PROJECT_PERMISSIONS_BUT_USER_AND_CODEVIEWER);
  602. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), component.getId()))
  603. .doesNotContain(UserRole.USER)
  604. .doesNotContain(UserRole.CODEVIEWER)
  605. .containsAll(PROJECT_PERMISSIONS_BUT_USER_AND_CODEVIEWER);
  606. }
  607. private void verifyStillHasAllPermissions(ComponentDto component, UserDto user, GroupDto group) {
  608. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null))
  609. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  610. assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId()))
  611. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  612. assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), component.getOrganizationUuid()))
  613. .containsAll(ORGANIZATION_PERMISSIONS_NAME_SET);
  614. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), null, component.getId()))
  615. .containsAll(permissionService.getAllProjectPermissions());
  616. assertThat(dbClient.groupPermissionDao().selectProjectPermissionsOfGroup(dbSession, component.getOrganizationUuid(), group.getId(), component.getId()))
  617. .containsAll(permissionService.getAllProjectPermissions());
  618. assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), component.getId()))
  619. .containsAll(permissionService.getAllProjectPermissions());
  620. }
  621. private void insertPendingTask(ComponentDto project) {
  622. insertCeQueueDto(project, CeQueueDto.Status.PENDING);
  623. }
  624. private void insertInProgressTask(ComponentDto project) {
  625. insertCeQueueDto(project, CeQueueDto.Status.IN_PROGRESS);
  626. }
  627. private int counter = 0;
  628. private void insertCeQueueDto(ComponentDto project, CeQueueDto.Status status) {
  629. dbClient.ceQueueDao().insert(dbTester.getSession(), new CeQueueDto()
  630. .setUuid("pending" + counter++)
  631. .setComponent(project)
  632. .setTaskType("foo")
  633. .setStatus(status));
  634. dbTester.commit();
  635. }
  636. private void expectInsufficientPrivilegeException() {
  637. expectedException.expect(ForbiddenException.class);
  638. expectedException.expectMessage("Insufficient privileges");
  639. }
  640. private boolean isPrivateInDb(ComponentDto project) {
  641. return dbClient.componentDao().selectByUuid(dbTester.getSession(), project.uuid()).get().isPrivate();
  642. }
  643. private ComponentDto randomPublicOrPrivateProject() {
  644. OrganizationDto organization = dbTester.organizations().insert();
  645. return random.nextBoolean() ? dbTester.components().insertPublicProject(organization) : dbTester.components().insertPrivateProject(organization);
  646. }
  647. }