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 a798dbb2df5b199bf38633f753d61ec9a2325367 Author: Marcus Christie <[email protected]> AuthorDate: Tue Apr 25 10:34:21 2023 -0400 simple group sharing implementation --- .../datacatalog/api/model/GroupEntity.java | 95 --------------- .../model/sharing/simple/SimpleGroupEntity.java | 8 ++ .../api/repository/GroupRepository.java | 13 -- .../sharing/simple/SimpleUserRepository.java | 3 + .../server/src/main/resources/schema.sql | 38 +++--- .../api/sharing/SimpleSharingManagerImplTest.java | 135 +++++++++++++++++++++ 6 files changed, 165 insertions(+), 127 deletions(-) diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java deleted file mode 100644 index 4c6caf7..0000000 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/GroupEntity.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.apache.airavata.datacatalog.api.model; - -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; - -// TODO: not needed? -// TODO: need a unique constraint on (tenant, externalId) -@Entity -@Table(name = "user_group") -public class GroupEntity { - - @Id - @SequenceGenerator(name = "user_group_group_id", sequenceName = "user_group_group_id", allocationSize = 1) - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_group_group_id") - @Column(name = "group_id") - private Long groupId; - - @Basic - @Column(name = "external_id", nullable = false) - private String externalId; - @Basic - - @Column(name = "name", nullable = false) - private String name; - - @ManyToOne(optional = false) - @JoinColumn(name = "tenant_id", referencedColumnName = "tenant_id", nullable = false, updatable = false) - private TenantEntity tenant; - - public Long getGroupId() { - return groupId; - } - - public void setGroupId(Long groupId) { - this.groupId = groupId; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public TenantEntity getTenant() { - return tenant; - } - - public void setTenant(TenantEntity tenant) { - this.tenant = tenant; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((groupId == null) ? 0 : groupId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - GroupEntity other = (GroupEntity) obj; - if (groupId == null) { - if (other.groupId != null) - return false; - } else if (!groupId.equals(other.groupId)) - return false; - return true; - } - -} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java index 26416a3..78d4268 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/model/sharing/simple/SimpleGroupEntity.java @@ -75,6 +75,14 @@ public class SimpleGroupEntity { this.simpleTenant = simpleTenant; } + public Set<SimpleUserEntity> getMemberUsers() { + return memberUsers; + } + + public void setMemberUsers(Set<SimpleUserEntity> memberUsers) { + this.memberUsers = memberUsers; + } + @Override public int hashCode() { final int prime = 31; diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java deleted file mode 100644 index f821fd9..0000000 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/GroupRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.apache.airavata.datacatalog.api.repository; - -import java.util.Optional; - -import org.apache.airavata.datacatalog.api.model.GroupEntity; -import org.apache.airavata.datacatalog.api.model.TenantEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -// TODO: not needed? -public interface GroupRepository extends JpaRepository<GroupEntity, Long> { - - Optional<GroupEntity> findByExternalIdAndTenant(String externalId, TenantEntity tenantEntity); -} diff --git a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java index 515da5a..cc26c73 100644 --- a/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java +++ b/data-catalog-api/server/src/main/java/org/apache/airavata/datacatalog/api/repository/sharing/simple/SimpleUserRepository.java @@ -9,4 +9,7 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface SimpleUserRepository extends JpaRepository<SimpleUserEntity, Long> { Optional<SimpleUserEntity> findByExternalIdAndSimpleTenant(String externalId, SimpleTenantEntity simpleTenant); + + Optional<SimpleUserEntity> findByExternalIdAndSimpleTenant_ExternalId(String externalId, + String tenantId); } diff --git a/data-catalog-api/server/src/main/resources/schema.sql b/data-catalog-api/server/src/main/resources/schema.sql index e890d2e..faad468 100644 --- a/data-catalog-api/server/src/main/resources/schema.sql +++ b/data-catalog-api/server/src/main/resources/schema.sql @@ -3,7 +3,7 @@ CREATE OR REPLACE VIEW simple_data_product_sharing_view AS SELECT s.data_product_id AS data_product_id, - u.user_id AS user_id, + su.user_id AS user_id, CASE WHEN s.permission_id = 'OWNER' THEN 0 WHEN s.permission_id = 'READ' THEN 1 @@ -15,22 +15,22 @@ 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 -- UNION - -- SELECT - -- dp.data_product_id AS data_product_id, - -- u.user_id AS user_id, - -- CASE - -- WHEN s.permission_id = 'OWNER' THEN 0 - -- WHEN s.permission_id = 'READ' THEN 1 - -- WHEN s.permission_id = 'READ_METADATA' THEN 2 - -- WHEN s.permission_id = 'WRITE' THEN 3 - -- WHEN s.permission_id = 'WRITE_METADATA' THEN 4 - -- WHEN s.permission_id = 'MANAGE_SHARING' THEN 5 - -- ELSE NULL - -- END AS permission_id - -- FROM - -- simple_group_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 user_table u ON u.user_id = su.user_id +UNION +SELECT + s.data_product_id AS data_product_id, + su.user_id AS user_id, + CASE + WHEN s.permission_id = 'OWNER' THEN 0 + WHEN s.permission_id = 'READ' THEN 1 + WHEN s.permission_id = 'READ_METADATA' THEN 2 + WHEN s.permission_id = 'WRITE' THEN 3 + WHEN s.permission_id = 'WRITE_METADATA' THEN 4 + WHEN s.permission_id = 'MANAGE_SHARING' THEN 5 + ELSE NULL + END AS permission_id +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 ; 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 91f485b..7d6d49f 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 @@ -4,21 +4,25 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.Optional; import java.util.UUID; import org.apache.airavata.datacatalog.api.DataProduct; +import org.apache.airavata.datacatalog.api.GroupInfo; import org.apache.airavata.datacatalog.api.Permission; import org.apache.airavata.datacatalog.api.UserInfo; import org.apache.airavata.datacatalog.api.exception.SharingException; import org.apache.airavata.datacatalog.api.model.DataProductEntity; import org.apache.airavata.datacatalog.api.model.TenantEntity; import org.apache.airavata.datacatalog.api.model.UserEntity; +import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleGroupEntity; import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleTenantEntity; import org.apache.airavata.datacatalog.api.model.sharing.simple.SimpleUserEntity; import org.apache.airavata.datacatalog.api.repository.DataProductRepository; import org.apache.airavata.datacatalog.api.repository.TenantRepository; import org.apache.airavata.datacatalog.api.repository.UserRepository; +import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleGroupRepository; import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleTenantRepository; import org.apache.airavata.datacatalog.api.repository.sharing.simple.SimpleUserRepository; import org.junit.jupiter.api.Test; @@ -40,6 +44,8 @@ public class SimpleSharingManagerImplTest { @Autowired SimpleUserRepository simpleUserRepository; @Autowired + SimpleGroupRepository simpleGroupRepository; + @Autowired SimpleTenantRepository simpleTenantRepository; @Autowired DataProductRepository dataProductRepository; @@ -135,4 +141,133 @@ public class SimpleSharingManagerImplTest { assertTrue(hasAccess); } + @Test + public void testRevokePermissionFromUser() 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 dataProductEntity = new DataProductEntity(); + dataProductEntity.setExternalId(UUID.randomUUID().toString()); + dataProductEntity.setOwner(testUserA); + dataProductEntity.setName("test data product"); + dataProductRepository.save(dataProductEntity); + + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dataProductEntity.getExternalId()) // only need the data product id + .build(); + + // Grant READ access to userB for the data product + simpleSharingManagerImpl.grantPermissionToUser(userB, dataProduct, Permission.READ, userA); + + // Check that userB does have READ access to the data product + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + + // Revoke READ access from userB + simpleSharingManagerImpl.revokePermissionFromUser(userB, dataProduct, Permission.READ); + + // Check that userB does not now have READ access + assertFalse(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + } + + @Test + public void testUserHasAccessViaGroupMembership() 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(); + UserInfo userC = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userC").build(); + + GroupInfo testGroup = GroupInfo.newBuilder().setGroupId("groupId").setTenantId("tenantId").build(); + + // Create a data product + DataProductEntity dataProductEntity = new DataProductEntity(); + dataProductEntity.setExternalId(UUID.randomUUID().toString()); + dataProductEntity.setOwner(testUserA); + dataProductEntity.setName("test data product"); + dataProductRepository.save(dataProductEntity); + + // Add users B and C to the testGroup + simpleSharingManagerImpl.resolveUser(userB); + simpleSharingManagerImpl.resolveUser(userC); + Optional<SimpleUserEntity> userBEntity = simpleUserRepository + .findByExternalIdAndSimpleTenant_ExternalId(userB.getUserId(), userB.getTenantId()); + assertTrue(userBEntity.isPresent()); + Optional<SimpleUserEntity> userCEntity = simpleUserRepository + .findByExternalIdAndSimpleTenant_ExternalId(userC.getUserId(), userC.getTenantId()); + assertTrue(userCEntity.isPresent()); + SimpleGroupEntity testGroupEntity = new SimpleGroupEntity(); + testGroupEntity.setName(testGroup.getGroupId()); + testGroupEntity.setExternalId(testGroup.getGroupId()); + testGroupEntity.getMemberUsers().addAll(Arrays.asList(userBEntity.get(), userCEntity.get())); + testGroupEntity.setSimpleTenant(userBEntity.get().getSimpleTenant()); + simpleGroupRepository.save(testGroupEntity); + + // Check that users B and C doesn't have READ access to the data product + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dataProductEntity.getExternalId()) // only need the data product id + .build(); + assertFalse(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertFalse(simpleSharingManagerImpl.userHasAccess(userC, dataProduct, Permission.READ)); + + // Grant READ access to testGroup for the data product + simpleSharingManagerImpl.grantPermissionToGroup(testGroup, dataProduct, Permission.READ, userA); + + // Check that users B and C now have READ access to the data product + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userC, dataProduct, Permission.READ)); + } + + @Test + public void testRevokePermissionFromGroup() 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(); + UserInfo userC = UserInfo.newBuilder().setTenantId("tenantId").setUserId("userC").build(); + + GroupInfo testGroup = GroupInfo.newBuilder().setGroupId("groupId").setTenantId("tenantId").build(); + + // Create a data product + DataProductEntity dataProductEntity = new DataProductEntity(); + dataProductEntity.setExternalId(UUID.randomUUID().toString()); + dataProductEntity.setOwner(testUserA); + dataProductEntity.setName("test data product"); + dataProductRepository.save(dataProductEntity); + + // Add users B and C to the testGroup + simpleSharingManagerImpl.resolveUser(userB); + simpleSharingManagerImpl.resolveUser(userC); + Optional<SimpleUserEntity> userBEntity = simpleUserRepository + .findByExternalIdAndSimpleTenant_ExternalId(userB.getUserId(), userB.getTenantId()); + assertTrue(userBEntity.isPresent()); + Optional<SimpleUserEntity> userCEntity = simpleUserRepository + .findByExternalIdAndSimpleTenant_ExternalId(userC.getUserId(), userC.getTenantId()); + assertTrue(userCEntity.isPresent()); + SimpleGroupEntity testGroupEntity = new SimpleGroupEntity(); + testGroupEntity.setName(testGroup.getGroupId()); + testGroupEntity.setExternalId(testGroup.getGroupId()); + testGroupEntity.getMemberUsers().addAll(Arrays.asList(userBEntity.get(), userCEntity.get())); + testGroupEntity.setSimpleTenant(userBEntity.get().getSimpleTenant()); + simpleGroupRepository.save(testGroupEntity); + + DataProduct dataProduct = DataProduct.newBuilder() + .setDataProductId(dataProductEntity.getExternalId()) // only need the data product id + .build(); + + // Grant READ access to testGroup for the data product + simpleSharingManagerImpl.grantPermissionToGroup(testGroup, dataProduct, Permission.READ, userA); + + // Check that users B and C now have READ access to the data product + assertTrue(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertTrue(simpleSharingManagerImpl.userHasAccess(userC, dataProduct, Permission.READ)); + + // Revoke READ access from testGroup + simpleSharingManagerImpl.revokePermissionFromGroup(testGroup, dataProduct, Permission.READ); + + // Check that users B and C don't have READ access to the data product + assertFalse(simpleSharingManagerImpl.userHasAccess(userB, dataProduct, Permission.READ)); + assertFalse(simpleSharingManagerImpl.userHasAccess(userC, dataProduct, Permission.READ)); + } }
