]> source.dussan.org Git - sonarqube.git/blob
6c8d3189fa9d8260636dc4de8a73b25ee2ddd8cf
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 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.platform.db.migration.version.v64;
21
22 import java.sql.SQLException;
23 import java.util.Map;
24 import java.util.Random;
25 import java.util.Set;
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;
32
33 import static java.lang.String.valueOf;
34 import static org.assertj.core.api.Assertions.assertThat;
35
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";
41
42   @Rule
43   public CoreDbTester db = CoreDbTester.createForSchema(MakeComponentsPrivateBasedOnPermissionsTest.class, "projects_and_group_roles_and_user_roles.sql");
44
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());
52
53   @Test
54   public void execute_does_nothing_on_empty_tables() throws SQLException {
55     underTest.execute();
56   }
57
58   @Test
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);
63
64     underTest.execute();
65
66     assertThat(isPrivate("p1")).isTrue();
67   }
68
69   @Test
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);
74
75     underTest.execute();
76
77     assertThat(isPrivate("p1")).isTrue();
78   }
79
80   @Test
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));
84
85     underTest.execute();
86
87     assertThat(isPrivate("p1")).isTrue();
88   }
89
90   @Test
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));
94
95     underTest.execute();
96
97     assertThat(isPrivate("p1")).isTrue();
98   }
99
100   @Test
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);
104
105     underTest.execute();
106
107     assertThat(isPrivate("p1")).isFalse();
108   }
109
110   @Test
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);
114
115     underTest.execute();
116
117     assertThat(isPrivate("p1")).isFalse();
118   }
119
120   @Test
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);
124
125     underTest.execute();
126
127     assertThat(isPrivate("p1")).isFalse();
128   }
129
130   @Test
131   public void execute_keeps_project_public_if_project_has_no_permission() throws SQLException {
132     insertRootComponent("p1", false);
133
134     underTest.execute();
135
136     assertThat(isPrivate("p1")).isFalse();
137   }
138
139   @Test
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);
148
149     underTest.execute();
150
151     assertThat(isPrivate("p1")).isTrue();
152     assertThat(isPrivate("p2")).isTrue();
153     assertThat(isPrivate("p3")).isTrue();
154   }
155
156   @Test
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);
168
169     underTest.execute();
170
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();
176   }
177
178   @Test
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);
190
191     underTest.execute();
192
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();
199   }
200
201   @Test
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);
207
208     underTest.execute();
209
210     assertThat(isPrivate("u1")).isFalse();
211     assertThat(isPrivate("u2")).isTrue();
212   }
213
214   @Test
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);
222
223     underTest.execute();
224
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);
229   }
230
231   @Test
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);
238
239     underTest.execute();
240
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();
245   }
246
247   @Test
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);
254
255     underTest.execute();
256
257     assertThat(isPrivate("root1")).isTrue();
258     assertThat(permissionsOfGroup(idRoot, group1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
259     assertThat(permissionsOfGroup(idRoot, group2)).isEmpty();
260   }
261
262   @Test
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);
273
274     underTest.execute();
275
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);
280   }
281
282   @Test
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);
289
290     underTest.execute();
291
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();
296   }
297
298   @Test
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);
305
306     underTest.execute();
307
308     assertThat(isPrivate("root1")).isTrue();
309     assertThat(permissionsOfGroup(idRoot, group1)).containsOnly(someRole, ROLE_USER, ROLE_CODEVIEWER);
310     assertThat(permissionsOfGroup(idRoot, group2)).isEmpty();
311   }
312
313   @Test
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)
320       .forEach(role -> {
321         insertGroupPermission(role, idRoot, null);
322         insertGroupPermission(role, idRoot, someGroupId);
323         insertUserPermission(role, idRoot, someUserId);
324       });
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);
329
330     underTest.execute();
331
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);
336   }
337
338   private long insertRootComponent(String uuid, boolean isPrivate) {
339     db.executeInsert(
340       "PROJECTS",
341       "ORGANIZATION_UUID", "org_" + uuid,
342       "SCOPE", "PRJ",
343       "QUALIFIER", randomQualifier,
344       "UUID", uuid,
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");
350   }
351
352   private long insertComponent(String uuid, String projectUuid, boolean isPrivate) {
353     db.executeInsert(
354       "PROJECTS",
355       "ORGANIZATION_UUID", "org_" + uuid,
356       "UUID", 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");
362   }
363
364   private void insertGroupPermission(String role, @Nullable Long resourceId, @Nullable Integer groupId) {
365     db.executeInsert(
366       "GROUP_ROLES",
367       "ORGANIZATION_UUID", "org" + random.nextInt(50),
368       "GROUP_ID", groupId == null ? null : valueOf(groupId),
369       "RESOURCE_ID", resourceId == null ? null : valueOf(resourceId),
370       "ROLE", role);
371   }
372
373   private int groupCount = Math.abs(random.nextInt(22));
374
375   private int insertGroup() {
376     String name = "group" + groupCount++;
377     db.executeInsert(
378       "GROUPS",
379       "ORGANIZATION_UUID", "org" + random.nextInt(12),
380       "NAME", name);
381     return ((Long) db.selectFirst("select id as \"ID\" from groups where name='" + name + "'").get("ID")).intValue();
382   }
383
384   private void insertUserPermission(String role, @Nullable Long resourceId, int userId) {
385     db.executeInsert(
386       "USER_ROLES",
387       "ORGANIZATION_UUID", "org_" + random.nextInt(66),
388       "USER_ID", valueOf(userId),
389       "RESOURCE_ID", resourceId == null ? null : valueOf(resourceId),
390       "ROLE", role);
391   }
392
393   private int userCount = Math.abs(random.nextInt(22));
394
395   private int insertUser() {
396     String login = "user" + userCount++;
397     db.executeInsert(
398       "USERS",
399       "LOGIN", login,
400       "IS_ROOT", String.valueOf(false));
401     return ((Long) db.selectFirst("select id as \"ID\" from users where login='" + login + "'").get("ID")).intValue();
402   }
403
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");
407   }
408
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)
411       .stream()
412       .flatMap(map -> map.entrySet().stream())
413       .map(entry -> (String) entry.getValue())
414       .collect(MoreCollectors.toSet());
415   }
416
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)
419       .stream()
420       .flatMap(map -> map.entrySet().stream())
421       .map(entry -> (String) entry.getValue())
422       .collect(MoreCollectors.toSet());
423   }
424
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)
427       .stream()
428       .flatMap(map -> map.entrySet().stream())
429       .map(entry -> (String) entry.getValue())
430       .collect(MoreCollectors.toSet());
431   }
432 }