3 * Copyright (C) 2009-2017 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.platform.db.migration.version.v64;
22 import java.sql.SQLException;
24 import java.util.Random;
26 import java.util.stream.Stream;
27 import javax.annotation.Nullable;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.sonar.core.util.stream.MoreCollectors;
31 import org.sonar.db.CoreDbTester;
33 import static java.lang.String.valueOf;
34 import static org.assertj.core.api.Assertions.assertThat;
36 public class MakeComponentsPrivateBasedOnPermissionsTest {
37 private static final String ROLE_USER = "user";
38 private static final String ROLE_CODEVIEWER = "codeviewer";
39 private static final String PROJECT_QUALIFIER = "TRK";
40 private static final String VIEW_QUALIFIER = "VW";
43 public CoreDbTester db = CoreDbTester.createForSchema(MakeComponentsPrivateBasedOnPermissionsTest.class, "projects_and_group_roles_and_user_roles.sql");
45 private final Random random = new Random();
46 private final String randomPublicConditionRole = random.nextBoolean() ? ROLE_CODEVIEWER : ROLE_USER;
47 private final String randomQualifier = random.nextBoolean() ? PROJECT_QUALIFIER : VIEW_QUALIFIER;
48 private final String randomRole = "role_" + random.nextInt(12);
49 private final int randomUserId = random.nextInt(500);
50 private final int randomGroupId = random.nextInt(500);
51 private MakeComponentsPrivateBasedOnPermissions underTest = new MakeComponentsPrivateBasedOnPermissions(db.database());
54 public void execute_does_nothing_on_empty_tables() throws SQLException {
59 public void execute_makes_project_private_if_group_AnyOne_has_global_permission_USER() throws SQLException {
60 long pId = insertRootComponent("p1", false);
61 insertGroupPermission(ROLE_USER, null, null);
62 insertGroupPermission(randomRole, pId, randomGroupId);
66 assertThat(isPrivate("p1")).isTrue();
70 public void execute_makes_project_private_if_group_AnyOne_has_global_permission_BROWSE() throws SQLException {
71 long pId = insertRootComponent("p1", false);
72 insertGroupPermission(ROLE_CODEVIEWER, null, null);
73 insertUserPermission(randomRole, pId, randomUserId);
77 assertThat(isPrivate("p1")).isTrue();
81 public void execute_makes_project_private_if_group_other_than_AnyOne_has_permission_BROWSE_on_other_project() throws SQLException {
82 long pId1 = insertRootComponent("p1", false);
83 insertGroupPermission(ROLE_CODEVIEWER, pId1, random.nextInt(30));
87 assertThat(isPrivate("p1")).isTrue();
91 public void execute_makes_project_private_if_group_other_than_AnyOne_has_permission_USER_on_other_project() throws SQLException {
92 long pId1 = insertRootComponent("p1", false);
93 insertGroupPermission(ROLE_USER, pId1, random.nextInt(30));
97 assertThat(isPrivate("p1")).isTrue();
101 public void execute_keeps_project_public_if_group_AnyOne_has_permission_USER_on_it() throws SQLException {
102 long pId1 = insertRootComponent("p1", false);
103 insertGroupPermission(ROLE_USER, pId1, null);
107 assertThat(isPrivate("p1")).isFalse();
111 public void execute_keeps_project_public_if_group_AnyOne_has_permission_BROWSE_on_it() throws SQLException {
112 long pId1 = insertRootComponent("p1", false);
113 insertGroupPermission(ROLE_CODEVIEWER, pId1, null);
117 assertThat(isPrivate("p1")).isFalse();
121 public void execute_keeps_project_public_if_only_group_AnyOne_has_permission_on_it() throws SQLException {
122 long pId1 = insertRootComponent("p1", false);
123 insertGroupPermission(randomRole, pId1, null);
127 assertThat(isPrivate("p1")).isFalse();
131 public void execute_keeps_project_public_if_project_has_no_permission() throws SQLException {
132 insertRootComponent("p1", false);
136 assertThat(isPrivate("p1")).isFalse();
140 public void execute_does_not_change_private_projects_to_public_when_they_actually_should_be_because_they_have_USER_or_BROWSE_on_group_Anyone() throws SQLException {
141 long p1Id = insertRootComponent("p1", true);
142 long p2Id = insertRootComponent("p2", true);
143 long p3Id = insertRootComponent("p3", true);
144 insertGroupPermission(ROLE_CODEVIEWER, p1Id, null);
145 insertGroupPermission(ROLE_USER, p1Id, null);
146 insertGroupPermission(ROLE_CODEVIEWER, p2Id, null);
147 insertGroupPermission(ROLE_USER, p3Id, null);
151 assertThat(isPrivate("p1")).isTrue();
152 assertThat(isPrivate("p2")).isTrue();
153 assertThat(isPrivate("p3")).isTrue();
157 public void execute_changes_non_root_rows_to_private_based_on_permissions_of_their_root_row() throws SQLException {
158 // root stays public, children are unchanged
159 long pId1 = insertRootComponent("root1", false);
160 insertGroupPermission(randomPublicConditionRole, pId1, null);
161 insertComponent("u1", "root1", false);
162 // root becomes privates, children are changed accordingly
163 long pId2 = insertRootComponent("root2", false);
164 int someUserId = random.nextInt(50);
165 insertGroupPermission(randomRole, pId2, someUserId);
166 insertComponent("u2", "root2", false);
167 insertComponent("u3", "root2", true);
171 assertThat(isPrivate("root1")).isFalse();
172 assertThat(isPrivate("u1")).isFalse();
173 assertThat(isPrivate("root2")).isTrue();
174 assertThat(isPrivate("u2")).isTrue();
175 assertThat(isPrivate("u3")).isTrue();
179 public void execute_does_not_fix_inconsistencies_of_non_root_rows_if_root_stays_public_or_is_already_private() throws SQLException {
180 // root stays public, children are unchanged
181 long pId1 = insertRootComponent("root1", false);
182 insertGroupPermission(randomPublicConditionRole, pId1, null);
183 insertComponent("u1", "root1", false);
184 insertComponent("u2", "root1", true); // inconsistent information is not fixed
185 // root is already private but children are inconsistent => not fixed
186 insertRootComponent("root2", true);
187 insertGroupPermission(randomPublicConditionRole, pId1, null);
188 insertComponent("u3", "root2", false);
189 insertComponent("u4", "root2", true);
193 assertThat(isPrivate("root1")).isFalse();
194 assertThat(isPrivate("u1")).isFalse();
195 assertThat(isPrivate("u2")).isTrue();
196 assertThat(isPrivate("root2")).isTrue();
197 assertThat(isPrivate("u3")).isFalse();
198 assertThat(isPrivate("u4")).isTrue();
202 public void execute_does_change_non_root_rows_which_root_does_not_exist() throws SQLException {
203 // non existent root, won't be changed
204 long pId1 = insertComponent("u1", "non existent root", false);
205 insertGroupPermission(randomPublicConditionRole, pId1, null);
206 insertComponent("u2", "non existent root", true);
210 assertThat(isPrivate("u1")).isFalse();
211 assertThat(isPrivate("u2")).isTrue();
215 public void execute_deletes_any_permission_to_group_Anyone_for_root_components_which_are_made_private() throws SQLException {
216 long idRoot1 = insertRootComponent("root1", false);
217 int someGroupId = random.nextInt(50);
218 int someUserId = random.nextInt(50);
219 insertGroupPermission(randomRole, idRoot1, null);
220 insertGroupPermission(randomRole, idRoot1, someGroupId);
221 insertUserPermission(randomRole, idRoot1, someUserId);
225 assertThat(isPrivate("root1")).isTrue();
226 assertThat(permissionsOfGroupAnyone(idRoot1)).isEmpty();
227 assertThat(permissionsOfGroup(idRoot1, someGroupId)).containsOnly(randomRole, ROLE_USER, ROLE_CODEVIEWER);
228 assertThat(permissionsOfUser(idRoot1, someUserId)).containsOnly(randomRole, ROLE_USER, ROLE_CODEVIEWER);
232 public void execute_ensures_any_user_of_with_at_least_one_permission_on_root_component_which_is_made_private_also_has_permissions_USER_and_CODEVIEWER() throws SQLException {
233 long idRoot = insertRootComponent("root1", false);
234 String someRole = "role_" + random.nextInt(12);
235 int user1 = insertUser();
236 int user2 = insertUser();
237 insertUserPermission(someRole, idRoot, user1);
241 assertThat(isPrivate("root1")).isTrue();
242 assertThat(permissionsOfGroupAnyone(idRoot)).isEmpty();
243 assertThat(permissionsOfUser(idRoot, user1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
244 assertThat(permissionsOfUser(idRoot, user2)).isEmpty();
248 public void execute_ensures_any_group_of_with_at_least_one_permission_on_root_component_which_is_made_private_also_has_permissions_USER_and_CODEVIEWER() throws SQLException {
249 long idRoot = insertRootComponent("root1", false);
250 String someRole = "role_" + random.nextInt(12);
251 int group1 = insertGroup();
252 int group2 = insertGroup();
253 insertGroupPermission(someRole, idRoot, group1);
257 assertThat(isPrivate("root1")).isTrue();
258 assertThat(permissionsOfGroup(idRoot, group1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
259 assertThat(permissionsOfGroup(idRoot, group2)).isEmpty();
263 public void execute_does_not_delete_permissions_to_group_Anyone_for_root_components_which_are_already_private() throws SQLException {
264 long idRoot = insertRootComponent("root1", true);
265 String someRole = "role_" + random.nextInt(12);
266 int someGroupId = random.nextInt(50);
267 int someUserId = random.nextInt(50);
268 insertGroupPermission(someRole, idRoot, null);
269 insertGroupPermission(someRole, idRoot, someGroupId);
270 insertGroupPermission(randomPublicConditionRole, idRoot, someGroupId);
271 insertUserPermission(someRole, idRoot, someUserId);
272 insertUserPermission(randomPublicConditionRole, idRoot, someUserId);
276 assertThat(isPrivate("root1")).isTrue();
277 assertThat(permissionsOfGroupAnyone(idRoot)).containsOnly(someRole);
278 assertThat(permissionsOfGroup(idRoot, someGroupId)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
279 assertThat(permissionsOfUser(idRoot, someUserId)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
283 public void execute_ensures_any_user_of_with_at_least_one_permission_on_root_component_which_is_already_private_also_has_permissions_USER_and_CODEVIEWER() throws SQLException {
284 long idRoot = insertRootComponent("root1", true);
285 String someRole = "role_" + random.nextInt(12);
286 int user1 = insertUser();
287 int user2 = insertUser();
288 insertUserPermission(someRole, idRoot, user1);
292 assertThat(isPrivate("root1")).isTrue();
293 assertThat(permissionsOfGroupAnyone(idRoot)).isEmpty();
294 assertThat(permissionsOfUser(idRoot, user1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
295 assertThat(permissionsOfUser(idRoot, user2)).isEmpty();
299 public void execute_ensures_any_group_of_with_at_least_one_permission_on_root_component_which_is_already_private_also_has_permissions_USER_and_CODEVIEWER() throws SQLException {
300 long idRoot = insertRootComponent("root1", true);
301 String someRole = "role_" + random.nextInt(12);
302 int group1 = insertGroup();
303 int group2 = insertGroup();
304 insertGroupPermission(someRole, idRoot, group1);
308 assertThat(isPrivate("root1")).isTrue();
309 assertThat(permissionsOfGroup(idRoot, group1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
310 assertThat(permissionsOfGroup(idRoot, group2)).isEmpty();
314 public void execute_deletes_any_USER_or_BROWSE_permission_of_public_project() throws SQLException {
315 long idRoot = insertRootComponent("root1", false);
316 int someGroupId = random.nextInt(55);
317 int someUserId = random.nextInt(55);
318 String someRole = "role_" + random.nextInt(12);
319 Stream.of(ROLE_USER, ROLE_CODEVIEWER, someRole)
321 insertGroupPermission(role, idRoot, null);
322 insertGroupPermission(role, idRoot, someGroupId);
323 insertUserPermission(role, idRoot, someUserId);
325 assertThat(isPrivate("root1")).isFalse();
326 assertThat(permissionsOfGroupAnyone(idRoot)).containsOnly(ROLE_USER, ROLE_CODEVIEWER, someRole);
327 assertThat(permissionsOfGroup(idRoot, someGroupId)).containsOnly(ROLE_USER, ROLE_CODEVIEWER, someRole);
328 assertThat(permissionsOfUser(idRoot, someUserId)).containsOnly(ROLE_USER, ROLE_CODEVIEWER, someRole);
332 assertThat(isPrivate("root1")).isFalse();
333 assertThat(permissionsOfGroupAnyone(idRoot)).containsOnly(someRole);
334 assertThat(permissionsOfGroup(idRoot, someGroupId)).containsOnly(someRole);
335 assertThat(permissionsOfUser(idRoot, someUserId)).containsOnly(someRole);
338 private long insertRootComponent(String uuid, boolean isPrivate) {
341 "ORGANIZATION_UUID", "org_" + uuid,
343 "QUALIFIER", randomQualifier,
345 "UUID_PATH", "path_" + uuid,
346 "ROOT_UUID", "root_" + uuid,
347 "PROJECT_UUID", uuid,
348 "PRIVATE", valueOf(isPrivate));
349 return (long) db.selectFirst("select id as \"ID\" from projects where uuid='" + uuid + "'").get("ID");
352 private long insertComponent(String uuid, String projectUuid, boolean isPrivate) {
355 "ORGANIZATION_UUID", "org_" + uuid,
357 "UUID_PATH", "path_" + uuid,
358 "ROOT_UUID", "root_" + uuid,
359 "PROJECT_UUID", projectUuid,
360 "PRIVATE", valueOf(isPrivate));
361 return (long) db.selectFirst("select id as \"ID\" from projects where uuid='" + uuid + "'").get("ID");
364 private void insertGroupPermission(String role, @Nullable Long resourceId, @Nullable Integer groupId) {
367 "ORGANIZATION_UUID", "org" + random.nextInt(50),
368 "GROUP_ID", groupId == null ? null : valueOf(groupId),
369 "RESOURCE_ID", resourceId == null ? null : valueOf(resourceId),
373 private int groupCount = Math.abs(random.nextInt(22));
375 private int insertGroup() {
376 String name = "group" + groupCount++;
379 "ORGANIZATION_UUID", "org" + random.nextInt(12),
381 return ((Long) db.selectFirst("select id as \"ID\" from groups where name='" + name + "'").get("ID")).intValue();
384 private void insertUserPermission(String role, @Nullable Long resourceId, int userId) {
387 "ORGANIZATION_UUID", "org_" + random.nextInt(66),
388 "USER_ID", valueOf(userId),
389 "RESOURCE_ID", resourceId == null ? null : valueOf(resourceId),
393 private int userCount = Math.abs(random.nextInt(22));
395 private int insertUser() {
396 String login = "user" + userCount++;
400 "IS_ROOT", String.valueOf(false));
401 return ((Long) db.selectFirst("select id as \"ID\" from users where login='" + login + "'").get("ID")).intValue();
404 private boolean isPrivate(String uuid) {
405 Map<String, Object> row = db.selectFirst("select private as \"PRIVATE\" from projects where uuid = '" + uuid + "'");
406 return (boolean) row.get("PRIVATE");
409 private Set<String> permissionsOfGroupAnyone(long resourceId) {
410 return db.select("select role from group_roles where group_id is null and resource_id = " + resourceId)
412 .flatMap(map -> map.entrySet().stream())
413 .map(entry -> (String) entry.getValue())
414 .collect(MoreCollectors.toSet());
417 private Set<String> permissionsOfGroup(long resourceId, int groupId) {
418 return db.select("select role from group_roles where group_id = " + groupId + " and resource_id = " + resourceId)
420 .flatMap(map -> map.entrySet().stream())
421 .map(entry -> (String) entry.getValue())
422 .collect(MoreCollectors.toSet());
425 private Set<String> permissionsOfUser(long resourceId, int userId) {
426 return db.select("select role from user_roles where resource_id = " + resourceId + " and user_id = " + userId)
428 .flatMap(map -> map.entrySet().stream())
429 .map(entry -> (String) entry.getValue())
430 .collect(MoreCollectors.toSet());