This is an automated email from the ASF dual-hosted git repository. machristie pushed a commit to branch custos-integration in repository https://gitbox.apache.org/repos/asf/airavata-data-catalog.git
commit 032c659769b4e78d199ee67a03e2dc402fa8cb89 Author: Marcus Christie <[email protected]> AuthorDate: Tue Apr 25 15:41:21 2023 -0400 Simple implementation of hierarchical sharing of data products --- .../server/src/main/resources/schema.sql | 31 +++++-- .../api/sharing/SimpleSharingManagerImplTest.java | 103 +++++++++++++++++++++ 2 files changed, 128 insertions(+), 6 deletions(-) diff --git a/data-catalog-api/server/src/main/resources/schema.sql b/data-catalog-api/server/src/main/resources/schema.sql index faad468..162f1af 100644 --- a/data-catalog-api/server/src/main/resources/schema.sql +++ b/data-catalog-api/server/src/main/resources/schema.sql @@ -1,8 +1,26 @@ -- TODO: move this to Liquibase or some other schema migration management tool CREATE -OR REPLACE VIEW simple_data_product_sharing_view AS +OR REPLACE VIEW simple_data_product_sharing_view AS -- +WITH recursive data_product_hierarchy(data_product_id, root) AS ( + SELECT + -- include self with the root + dp.data_product_id, + dp.data_product_id AS root + FROM + data_product dp + UNION + ALL + SELECT + dp.data_product_id, + h.root + FROM + data_product_hierarchy h, + data_product dp + WHERE + dp.parent_data_product_id = h.data_product_id +) SELECT - s.data_product_id AS data_product_id, + dph.data_product_id AS data_product_id, su.user_id AS user_id, CASE WHEN s.permission_id = 'OWNER' THEN 0 @@ -15,10 +33,11 @@ SELECT END AS permission_id FROM simple_user_sharing s - INNER JOIN simple_user su ON su.simple_user_id = s.simple_user_id -- INNER JOIN user_table u ON u.user_id = su.user_id + INNER JOIN simple_user su ON su.simple_user_id = s.simple_user_id + INNER JOIN data_product_hierarchy dph ON dph.root = s.data_product_id UNION SELECT - s.data_product_id AS data_product_id, + dph.data_product_id AS data_product_id, su.user_id AS user_id, CASE WHEN s.permission_id = 'OWNER' THEN 0 @@ -32,5 +51,5 @@ SELECT FROM simple_group_sharing s INNER JOIN simple_group_membership gm ON gm.simple_group_id = s.simple_group_id - INNER JOIN simple_user su ON su.simple_user_id = gm.simple_user_id -- INNER JOIN user_table u ON u.user_id = su.user_id -; + INNER JOIN simple_user su ON su.simple_user_id = gm.simple_user_id + INNER JOIN data_product_hierarchy dph ON dph.root = s.data_product_id; diff --git a/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java b/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java index 6fe117f..74df1c4 100644 --- a/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java +++ b/data-catalog-api/server/src/test/java/org/apache/airavata/datacatalog/api/sharing/SimpleSharingManagerImplTest.java @@ -320,4 +320,107 @@ public class SimpleSharingManagerImplTest { assertFalse(simpleSharingManagerImpl.hasPublicAccess(dataProduct, Permission.READ)); } + + @Test + public void testUserHasAccessViaCascade() throws SharingException { + + UserInfo userA = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userA").build(); + UserEntity testUserA = simpleSharingManagerImpl.resolveUser(userA); + UserInfo userB = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userB").build(); + + DataProductEntity dp1 = new DataProductEntity(); + dp1.setExternalId(UUID.randomUUID().toString()); + dp1.setOwner(testUserA); + dp1.setName("test data product 1"); + dataProductRepository.save(dp1); + + DataProductEntity dp2 = new DataProductEntity(); + dp2.setExternalId(UUID.randomUUID().toString()); + dp2.setOwner(testUserA); + dp2.setName("test data product 2"); + dp2.setParentDataProductEntity(dp1); + dataProductRepository.save(dp2); + + DataProductEntity dp3 = new DataProductEntity(); + dp3.setExternalId(UUID.randomUUID().toString()); + dp3.setOwner(testUserA); + dp3.setName("test data product 3"); + dp3.setParentDataProductEntity(dp2); + dataProductRepository.save(dp3); + + // Check that userB doesn't have READ access to the data products 1, 2 or 3 + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dp1.getExternalId()) // only need the data product id + .build(); + assertFalse(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + + // Grant READ access to userB for the data product + simpleSharingManagerImpl.grantPermissionToUser(userB, dataProduct, Permission.READ, userA); + + // Check that userB does now have READ access to the data product 1, 2 and 3 + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, + DataProduct.newBuilder().setDataProductId(dp2.getExternalId()).build(), Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, + DataProduct.newBuilder().setDataProductId(dp3.getExternalId()).build(), Permission.READ)); + } + + @Test + public void testUserHasAccessViaGroupMembershipAndCascade() throws SharingException { + + UserInfo userA = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userA").build(); + UserEntity testUserA = simpleSharingManagerImpl.resolveUser(userA); + UserInfo userB = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userB").build(); + + GroupInfo testGroup = GroupInfo.newBuilder().setGroupId("groupId").setTenantId("tenantId").build(); + + // Create data products + DataProductEntity dp1 = new DataProductEntity(); + dp1.setExternalId(UUID.randomUUID().toString()); + dp1.setOwner(testUserA); + dp1.setName("test data product 1"); + dataProductRepository.save(dp1); + + DataProductEntity dp2 = new DataProductEntity(); + dp2.setExternalId(UUID.randomUUID().toString()); + dp2.setOwner(testUserA); + dp2.setName("test data product 2"); + dp2.setParentDataProductEntity(dp1); + dataProductRepository.save(dp2); + + DataProductEntity dp3 = new DataProductEntity(); + dp3.setExternalId(UUID.randomUUID().toString()); + dp3.setOwner(testUserA); + dp3.setName("test data product 3"); + dp3.setParentDataProductEntity(dp2); + dataProductRepository.save(dp3); + + // Add user B to the testGroup + simpleSharingManagerImpl.resolveUser(userB); + Optional<SimpleUserEntity> userBEntity = simpleUserRepository + .findByExternalIdAndSimpleTenant_ExternalId(userB.getUserId(), userB.getTenantId()); + assertTrue(userBEntity.isPresent()); + SimpleGroupEntity testGroupEntity = new SimpleGroupEntity(); + testGroupEntity.setName(testGroup.getGroupId()); + testGroupEntity.setExternalId(testGroup.getGroupId()); + testGroupEntity.getMemberUsers().addAll(Arrays.asList(userBEntity.get())); + testGroupEntity.setSimpleTenant(userBEntity.get().getSimpleTenant()); + simpleGroupRepository.save(testGroupEntity); + + // Check that user B doesn't have READ access to the data product + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dp1.getExternalId()) // only need the data product id + .build(); + assertFalse(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + + // Grant READ access to testGroup for the data product + simpleSharingManagerImpl.grantPermissionToGroup(testGroup, dataProduct, Permission.READ, userA); + + // Check that users B now has READ access to the data products 1, 2, and 3 + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, + DataProduct.newBuilder().setDataProductId(dp2.getExternalId()).build(), Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, + DataProduct.newBuilder().setDataProductId(dp3.getExternalId()).build(), Permission.READ)); + } }
