From: Simon Brandhof Date: Fri, 14 Oct 2016 05:54:54 +0000 (+0200) Subject: SONAR-8134 add dao to verify authorizations X-Git-Tag: 6.2-RC1~423 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=bf7b10fc5ca07faa4666836c2c53fd40febc46bb;p=sonarqube.git SONAR-8134 add dao to verify authorizations --- diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index f46233de178..444c3ae5d9a 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -106,7 +106,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION + 24 // level 1 - + 52 // content of DaoModule + + 53 // content of DaoModule + 2 // content of EsSearchModule + 62 // content of CorePropertyDefinitions + 1 // content of CePropertyDefinitions diff --git a/sonar-db/src/main/java/org/sonar/db/DaoModule.java b/sonar-db/src/main/java/org/sonar/db/DaoModule.java index f607cd29d4d..35b3ec91854 100644 --- a/sonar-db/src/main/java/org/sonar/db/DaoModule.java +++ b/sonar-db/src/main/java/org/sonar/db/DaoModule.java @@ -50,6 +50,7 @@ import org.sonar.db.measure.custom.CustomMeasureDao; import org.sonar.db.metric.MetricDao; import org.sonar.db.notification.NotificationQueueDao; import org.sonar.db.organization.OrganizationDao; +import org.sonar.db.permission.AuthorizationDao; import org.sonar.db.permission.GroupPermissionDao; import org.sonar.db.permission.UserPermissionDao; import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao; @@ -79,6 +80,7 @@ public class DaoModule extends Module { private static final List> classes = ImmutableList.>builder().add( ActiveDashboardDao.class, AuthorDao.class, + AuthorizationDao.class, PermissionDao.class, CeActivityDao.class, CeQueueDao.class, diff --git a/sonar-db/src/main/java/org/sonar/db/DbClient.java b/sonar-db/src/main/java/org/sonar/db/DbClient.java index a86820b115d..ac37cfe50f8 100644 --- a/sonar-db/src/main/java/org/sonar/db/DbClient.java +++ b/sonar-db/src/main/java/org/sonar/db/DbClient.java @@ -50,6 +50,7 @@ import org.sonar.db.measure.custom.CustomMeasureDao; import org.sonar.db.metric.MetricDao; import org.sonar.db.notification.NotificationQueueDao; import org.sonar.db.organization.OrganizationDao; +import org.sonar.db.permission.AuthorizationDao; import org.sonar.db.permission.GroupPermissionDao; import org.sonar.db.permission.PermissionDao; import org.sonar.db.permission.UserPermissionDao; @@ -79,6 +80,7 @@ public class DbClient { private final Database database; private final MyBatis myBatis; + private final AuthorizationDao authorizationDao; private final OrganizationDao organizationDao; private final QualityProfileDao qualityProfileDao; private final LoadedTemplateDao loadedTemplateDao; @@ -140,6 +142,7 @@ public class DbClient { for (Dao dao : daos) { map.put(dao.getClass(), dao); } + authorizationDao = getDao(map, AuthorizationDao.class); organizationDao = getDao(map, OrganizationDao.class); qualityProfileDao = getDao(map, QualityProfileDao.class); loadedTemplateDao = getDao(map, LoadedTemplateDao.class); @@ -206,6 +209,10 @@ public class DbClient { return database; } + public AuthorizationDao authorizationDao() { + return authorizationDao; + } + public OrganizationDao organizationDao() { return organizationDao; } diff --git a/sonar-db/src/main/java/org/sonar/db/MyBatis.java b/sonar-db/src/main/java/org/sonar/db/MyBatis.java index 66ff9549f00..a7c75e9b5ca 100644 --- a/sonar-db/src/main/java/org/sonar/db/MyBatis.java +++ b/sonar-db/src/main/java/org/sonar/db/MyBatis.java @@ -84,6 +84,7 @@ import org.sonar.db.notification.NotificationQueueDto; import org.sonar.db.notification.NotificationQueueMapper; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.organization.OrganizationMapper; +import org.sonar.db.permission.AuthorizationMapper; import org.sonar.db.permission.GroupPermissionDto; import org.sonar.db.permission.GroupPermissionMapper; import org.sonar.db.permission.PermissionMapper; @@ -228,6 +229,7 @@ public class MyBatis { ActiveDashboardMapper.class, ActiveRuleMapper.class, AuthorMapper.class, + AuthorizationMapper.class, CeActivityMapper.class, CeQueueMapper.class, CeScannerContextMapper.class, diff --git a/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationDao.java b/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationDao.java new file mode 100644 index 00000000000..3f2f32da72e --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationDao.java @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.permission; + +import java.util.Set; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; + +/** + * The SQL requests used to verify authorization (the permissions + * granted to users) + * + * @see GroupPermissionDao for CRUD of table group_roles + * @see UserPermissionDao for CRUD of table user_roles + */ +public class AuthorizationDao implements Dao { + + /** + * Loads all the permissions granted to logged-in user for the specified organization + */ + public Set selectOrganizationPermissions(DbSession dbSession, String organizationUuid, long userId) { + return mapper(dbSession).selectOrganizationPermissions(organizationUuid, userId); + } + + /** + * Loads all the permissions granted to anonymous user for the specified organization + */ + public Set selectOrganizationPermissionsOfAnonymous(DbSession dbSession, String organizationUuid) { + return mapper(dbSession).selectOrganizationPermissionsOfAnonymous(organizationUuid); + } + + /** + * Loads all the permissions granted to logged-in user for the specified root component (project) + */ + public Set selectRootComponentPermissions(DbSession dbSession, long rootComponentId, long userId) { + return mapper(dbSession).selectRootComponentPermissions(rootComponentId, userId); + } + + /** + * Loads all the permissions granted to anonymous user for the specified root component (project) + */ + public Set selectRootComponentPermissionsOfAnonymous(DbSession dbSession, long rootComponentId) { + return mapper(dbSession).selectRootComponentPermissionsOfAnonymous(rootComponentId); + } + + private static AuthorizationMapper mapper(DbSession dbSession) { + return dbSession.getMapper(AuthorizationMapper.class); + } +} diff --git a/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationMapper.java b/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationMapper.java new file mode 100644 index 00000000000..fcf9d1274c7 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/permission/AuthorizationMapper.java @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.permission; + +import java.util.Set; +import org.apache.ibatis.annotations.Param; + +/** + * @see AuthorizationDao + */ +public interface AuthorizationMapper { + + Set selectOrganizationPermissions(@Param("organizationUuid") String organizationUuid, + @Param("userId") long userId); + + Set selectOrganizationPermissionsOfAnonymous(@Param("organizationUuid") String organizationUuid); + + Set selectRootComponentPermissions(@Param("rootComponentId") long rootComponentId, @Param("userId") long userId); + + Set selectRootComponentPermissionsOfAnonymous(@Param("rootComponentId") long rootComponentId); + +} diff --git a/sonar-db/src/main/java/org/sonar/db/permission/PermissionMapper.java b/sonar-db/src/main/java/org/sonar/db/permission/PermissionMapper.java index d8d1c029ef1..a24d3e6b2ac 100644 --- a/sonar-db/src/main/java/org/sonar/db/permission/PermissionMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/permission/PermissionMapper.java @@ -26,8 +26,8 @@ import org.apache.ibatis.annotations.Param; /** * Only the requests involving both user and group permissions. * - * @see GroupPermissionMapper - * @see UserPermissionMapper + * @see GroupPermissionMapper for CRUD of table group_roles + * @see UserPermissionMapper for CRUD of table user_roles */ public interface PermissionMapper { diff --git a/sonar-db/src/main/java/org/sonar/db/permission/PermissionRepository.java b/sonar-db/src/main/java/org/sonar/db/permission/PermissionRepository.java index d909d0ff0fe..f9f00b66b07 100644 --- a/sonar-db/src/main/java/org/sonar/db/permission/PermissionRepository.java +++ b/sonar-db/src/main/java/org/sonar/db/permission/PermissionRepository.java @@ -56,15 +56,6 @@ public class PermissionRepository { this.settings = settings; } - /** - * For each modification of permission on a project, update the authorization_updated_at to help ES reindex only relevant changes - */ - private void updateProjectAuthorizationDate(DbSession session, @Nullable Long projectId) { - if (projectId != null) { - dbClient.resourceDao().updateAuthorizationDate(projectId, session); - } - } - public void applyPermissionTemplate(DbSession session, String templateUuid, ComponentDto project) { applyPermissionTemplate(session, templateUuid, project, null); } @@ -109,6 +100,13 @@ public class PermissionRepository { } } + /** + * For each modification of permission on a project, update the authorization_updated_at to help ES reindex only relevant changes + */ + private void updateProjectAuthorizationDate(DbSession dbSession, long projectId) { + dbClient.resourceDao().updateAuthorizationDate(projectId, dbSession); + } + /** * Warning, this method is also used by the Developer Cockpit plugin */ @@ -127,6 +125,7 @@ public class PermissionRepository { * permission template for the resource qualifier. */ private String getApplicablePermissionTemplateKey(DbSession session, final String componentKey, String qualifier) { + // FIXME performance issue here, we should not load all templates List allPermissionTemplates = dbClient.permissionTemplateDao().selectAll(session); List matchingTemplates = new ArrayList<>(); for (PermissionTemplateDto permissionTemplateDto : allPermissionTemplates) { diff --git a/sonar-db/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml b/sonar-db/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml new file mode 100644 index 00000000000..6a05e22892d --- /dev/null +++ b/sonar-db/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + diff --git a/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java b/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java index a87ffc547e0..aa47872bb1c 100644 --- a/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java +++ b/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java @@ -29,6 +29,6 @@ public class DaoModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new DaoModule().configure(container); - assertThat(container.size()).isEqualTo(2 + 52); + assertThat(container.size()).isEqualTo(2 + 53); } } diff --git a/sonar-db/src/test/java/org/sonar/db/permission/AuthorizationDaoTest.java b/sonar-db/src/test/java/org/sonar/db/permission/AuthorizationDaoTest.java new file mode 100644 index 00000000000..7599aea951b --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/permission/AuthorizationDaoTest.java @@ -0,0 +1,146 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.permission; + +import java.util.Set; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.organization.OrganizationTesting; +import org.sonar.db.user.GroupDto; +import org.sonar.db.user.UserDto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; + +public class AuthorizationDaoTest { + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + private DbSession dbSession = db.getSession(); + private AuthorizationDao underTest = new AuthorizationDao(); + private OrganizationDto org; + private UserDto user; + private GroupDto group1; + private GroupDto group2; + + @Before + public void setUp() throws Exception { + org = OrganizationTesting.insert(db, newOrganizationDto()); + user = db.users().insertUser(); + group1 = db.users().insertGroup(org, "group1"); + group2 = db.users().insertGroup(org, "group2"); + } + + /** + * Union of the permissions granted to: + * - the user + * - the groups which user is member + * - anyone + */ + @Test + public void selectOrganizationPermissions_for_logged_in_user() { + db.users().insertMember(group1, user); + db.users().insertPermissionOnUser(org, user, "perm1"); + db.users().insertPermissionOnGroup(group1, "perm2"); + db.users().insertPermissionOnAnyone(org, "perm3"); + + // ignored permissions, user is not member of this group + db.users().insertPermissionOnGroup(group2, "ignored"); + + Set permissions = underTest.selectOrganizationPermissions(dbSession, org.getUuid(), user.getId()); + + assertThat(permissions).containsOnly("perm1", "perm2", "perm3"); + } + + /** + * Anonymous user only benefits from the permissions granted to + * "Anyone" + */ + @Test + public void selectOrganizationPermissions_for_anonymous_user() { + db.users().insertPermissionOnAnyone(org, "perm1"); + + // ignored permissions + db.users().insertPermissionOnUser(org, user, "ignored"); + db.users().insertPermissionOnGroup(group1, "ignored"); + + Set permissions = underTest.selectOrganizationPermissionsOfAnonymous(dbSession, org.getUuid()); + + assertThat(permissions).containsOnly("perm1"); + } + + /** + * Union of the permissions granted to: + * - the user + * - the groups which user is member + * - anyone + */ + @Test + public void selectRootComponentPermissions_for_logged_in_user() { + db.users().insertMember(group1, user); + ComponentDto project1 = db.components().insertProject(); + db.users().insertProjectPermissionOnAnyone("perm1", project1); + db.users().insertProjectPermissionOnGroup(group1, "perm2", project1); + db.users().insertProjectPermissionOnUser(user, "perm3", project1); + + // ignored permissions + db.users().insertPermissionOnAnyone(org, "ignored"); + db.users().insertPermissionOnGroup(group2, "ignored"); + ComponentDto project2 = db.components().insertProject(); + + Set permissions = underTest.selectRootComponentPermissions(dbSession, project1.getId(), user.getId()); + assertThat(permissions).containsOnly("perm1", "perm2", "perm3"); + + // non granted project + permissions = underTest.selectRootComponentPermissions(dbSession, project2.getId(), user.getId()); + assertThat(permissions).isEmpty(); + } + + /** + * Anonymous user only benefits from the permissions granted to + * "Anyone" + */ + @Test + public void selectRootComponentPermissions_for_anonymous_user() { + ComponentDto project1 = db.components().insertProject(); + db.users().insertProjectPermissionOnAnyone("perm1", project1); + + // ignored permissions + db.users().insertPermissionOnAnyone(org, "ignored"); + db.users().insertPermissionOnUser(org, user, "ignored"); + db.users().insertPermissionOnGroup(group1, "ignored"); + ComponentDto project2 = db.components().insertProject(); + db.users().insertProjectPermissionOnGroup(group1, "ignored", project2); + + Set permissions = underTest.selectRootComponentPermissionsOfAnonymous(dbSession, project1.getId()); + assertThat(permissions).containsOnly("perm1"); + + // non granted project + permissions = underTest.selectRootComponentPermissionsOfAnonymous(dbSession, project2.getId()); + assertThat(permissions).isEmpty(); + } + +}