diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java index f0942e509e3..7f65c3179cc 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java @@ -28,9 +28,9 @@ public interface RoleStore { void init() throws Exception; - RangerRole createRole(RangerRole role, Boolean createNonExistUserGroup) throws Exception; + RangerRole createRole(RangerRole role, Boolean createNonExistUserGroup, Boolean isRefTableCleanupRequired) throws Exception; - RangerRole updateRole(RangerRole role, Boolean createNonExistUserGroup) throws Exception; + RangerRole updateRole(RangerRole role, Boolean createNonExistUserGroup, Boolean isRefTableCleanupRequired) throws Exception; void deleteRole(String roleName) throws Exception; diff --git a/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java b/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java index 6c8ede470c4..31ae8a4a007 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java @@ -210,6 +210,9 @@ public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy createPrincipalsIfAbsent = false; } + final boolean policyExists = xPolicy != null && xPolicy.getId() != null + && daoMgr.getXXPolicy().getById(xPolicy.getId()) != null; + if (CollectionUtils.isNotEmpty(roleNames)) { LOG.debug("x_policy_ref_role - New role entries to insert for policy ID {}: {}", policyId, roleNames); @@ -222,7 +225,7 @@ public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy for (String roleName : filteredRoleNames) { Long roleId = nameToId.get(roleName); - PolicyRoleAssociator associator = new PolicyRoleAssociator(roleName, roleId, xPolicy); + PolicyRoleAssociator associator = new PolicyRoleAssociator(roleName, roleId, xPolicy, policyExists); if (roleId != null) { XXPolicyRefRole roleRef = associator.getPolicyRef(); @@ -257,7 +260,7 @@ public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy for (String groupName : filteredGroupNames) { Long groupId = nameToId.get(groupName); - PolicyGroupAssociator associator = new PolicyGroupAssociator(groupName, groupId, xPolicy); + PolicyGroupAssociator associator = new PolicyGroupAssociator(groupName, groupId, xPolicy, policyExists); if (groupId != null) { XXPolicyRefGroup groupRef = associator.getPolicyRef(); @@ -292,7 +295,7 @@ public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy for (String userName : filteredUserNames) { Long userId = nameToId.get(userName); - PolicyUserAssociator associator = new PolicyUserAssociator(userName, userId, xPolicy); + PolicyUserAssociator associator = new PolicyUserAssociator(userName, userId, xPolicy, policyExists); if (userId != null) { XXPolicyRefUser userRef = associator.getPolicyRef(); @@ -551,25 +554,23 @@ public void cleanupPolicyRefGroups(Set policyGroups, Long policyId, XXPo public enum PRINCIPAL_TYPE { USER, GROUP, ROLE } - private boolean doesPolicyExist(XXPolicy policy) { - return daoMgr.getXXPolicy().getById(policy.getId()) != null; - } - private class PolicyRoleAssociator implements Runnable { private final String name; private final Long roleId; private final XXPolicy xPolicy; + private final boolean policyExists; - PolicyRoleAssociator(String name, Long roleId, XXPolicy xPolicy) { - this.name = name; - this.roleId = roleId; - this.xPolicy = xPolicy; + PolicyRoleAssociator(String name, Long roleId, XXPolicy xPolicy, boolean policyExists) { + this.name = name; + this.roleId = roleId; + this.xPolicy = xPolicy; + this.policyExists = policyExists; } public XXPolicyRefRole getPolicyRef() { Long id = resolveRoleId(false); - if (id != null && doesPolicyExist(xPolicy)) { + if (id != null && policyExists) { XXPolicyRefRole xPolRole = new XXPolicyRefRole(); xPolRole.setPolicyId(xPolicy.getId()); @@ -583,7 +584,7 @@ public XXPolicyRefRole getPolicyRef() { } public void createPolicyRef(Long id) { - if (doesPolicyExist(xPolicy)) { + if (policyExists) { XXPolicyRefRole xPolRole = new XXPolicyRefRole(); xPolRole.setPolicyId(xPolicy.getId()); @@ -632,7 +633,7 @@ private Long createRole() { try { RangerRole rRole = new RangerRole(name, null, null, null, null); - RangerRole createdRole = roleStore.createRole(rRole, false); + RangerRole createdRole = roleStore.createRole(rRole, false, false); return createdRole.getId(); } catch (Exception e) { @@ -645,17 +646,19 @@ private class PolicyGroupAssociator implements Runnable { private final String name; private final Long groupId; private final XXPolicy xPolicy; + private final boolean policyExists; - PolicyGroupAssociator(String name, Long groupId, XXPolicy xPolicy) { - this.name = name; - this.groupId = groupId; - this.xPolicy = xPolicy; + PolicyGroupAssociator(String name, Long groupId, XXPolicy xPolicy, boolean policyExists) { + this.name = name; + this.groupId = groupId; + this.xPolicy = xPolicy; + this.policyExists = policyExists; } public XXPolicyRefGroup getPolicyRef() { Long id = resolveGroupId(false); - if (id != null && doesPolicyExist(xPolicy)) { + if (id != null && policyExists) { XXPolicyRefGroup xPolGroup = new XXPolicyRefGroup(); xPolGroup.setPolicyId(xPolicy.getId()); @@ -669,7 +672,7 @@ public XXPolicyRefGroup getPolicyRef() { } public void createPolicyRef(Long id) { - if (doesPolicyExist(xPolicy)) { + if (policyExists) { XXPolicyRefGroup xPolGroup = new XXPolicyRefGroup(); xPolGroup.setPolicyId(xPolicy.getId()); @@ -736,17 +739,19 @@ private class PolicyUserAssociator implements Runnable { private final String name; private final Long userId; private final XXPolicy xPolicy; + private final boolean policyExists; - PolicyUserAssociator(String name, Long userId, XXPolicy xPolicy) { - this.name = name; - this.userId = userId; - this.xPolicy = xPolicy; + PolicyUserAssociator(String name, Long userId, XXPolicy xPolicy, boolean policyExists) { + this.name = name; + this.userId = userId; + this.xPolicy = xPolicy; + this.policyExists = policyExists; } public XXPolicyRefUser getPolicyRef() { Long id = resolveUserId(false); - if (id != null && doesPolicyExist(xPolicy)) { + if (id != null && policyExists) { XXPolicyRefUser xPolUser = new XXPolicyRefUser(); xPolUser.setPolicyId(xPolicy.getId()); @@ -760,7 +765,7 @@ public XXPolicyRefUser getPolicyRef() { } public void createPolicyRef(Long id) { - if (doesPolicyExist(xPolicy)) { + if (policyExists) { XXPolicyRefUser xPolUser = new XXPolicyRefUser(); xPolUser.setPolicyId(xPolicy.getId()); diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java index c89609eb9e2..6a606fc09c2 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java @@ -95,7 +95,7 @@ public class RoleDBStore implements RoleStore { public void init() throws Exception {} @Override - public RangerRole createRole(RangerRole role, Boolean createNonExistUserGroupRole) throws Exception { + public RangerRole createRole(RangerRole role, Boolean createNonExistUserGroupRole, Boolean isRefTableCleanupRequired) throws Exception { LOG.debug("==> RoleDBStore.createRole()"); XXRole xxRole = daoMgr.getXXRole().findByRoleName(role.getName()); @@ -115,7 +115,7 @@ public RangerRole createRole(RangerRole role, Boolean createNonExistUserGroupRol throw new Exception("Cannot create role:[" + role + "]"); } - roleRefUpdater.createNewRoleMappingForRefTable(createdRole, createNonExistUserGroupRole); + roleRefUpdater.createNewRoleMappingForRefTable(createdRole, createNonExistUserGroupRole, isRefTableCleanupRequired); roleService.createTransactionLog(createdRole, null, RangerBaseModelService.OPERATION_CREATE_CONTEXT); @@ -123,7 +123,7 @@ public RangerRole createRole(RangerRole role, Boolean createNonExistUserGroupRol } @Override - public RangerRole updateRole(RangerRole role, Boolean createNonExistUserGroupRole) throws Exception { + public RangerRole updateRole(RangerRole role, Boolean createNonExistUserGroupRole, Boolean isRefTableCleanupRequired) throws Exception { XXRole xxRole = daoMgr.getXXRole().findByRoleId(role.getId()); if (xxRole == null) { @@ -150,7 +150,7 @@ public RangerRole updateRole(RangerRole role, Boolean createNonExistUserGroupRol throw new Exception("Cannot update role:[" + role + "]"); } - roleRefUpdater.createNewRoleMappingForRefTable(updatedRole, createNonExistUserGroupRole); + roleRefUpdater.createNewRoleMappingForRefTable(updatedRole, createNonExistUserGroupRole, isRefTableCleanupRequired); roleService.updatePolicyVersions(updatedRole.getId()); diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java index c83e0c31f20..683ab248e11 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java @@ -24,6 +24,7 @@ import org.apache.ranger.common.MessageEnums; import org.apache.ranger.common.RESTErrorUtil; import org.apache.ranger.common.RangerCommonEnums; +import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter; import org.apache.ranger.db.RangerDaoManager; import org.apache.ranger.db.XXRoleRefGroupDao; @@ -44,9 +45,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import static org.apache.ranger.service.RangerBaseModelService.OPERATION_CREATE_CONTEXT; @@ -79,15 +84,16 @@ public RangerDaoManager getRangerDaoManager() { return daoMgr; } - public void createNewRoleMappingForRefTable(RangerRole rangerRole, Boolean createNonExistUserGroupRole) { + public void createNewRoleMappingForRefTable(RangerRole rangerRole, Boolean createNonExistUserGroupRole, Boolean isRefTableCleanupRequired) { if (rangerRole == null) { return; } - cleanupRefTables(rangerRole); + boolean oldBulkMode = RangerBizUtil.isBulkMode(); - final Long roleId = rangerRole.getId(); - final Set roleUsers = new HashSet<>(); + final Long roleId = rangerRole.getId(); + final boolean roleExists = roleId != null && daoMgr.getXXRole().getById(roleId) != null; + final Set roleUsers = new HashSet<>(); final Set roleGroups = new HashSet<>(); final Set roleRoles = new HashSet<>(); @@ -103,60 +109,100 @@ public void createNewRoleMappingForRefTable(RangerRole rangerRole, Boolean creat roleRoles.add(role.getName()); } + if (isRefTableCleanupRequired) { + cleanupRefTablesForUpdate(rangerRole, roleUsers, roleGroups, roleRoles); + } + final boolean isCreateNonExistentUGRs = createNonExistUserGroupRole && xaBizUtil.checkAdminAccess(); if (CollectionUtils.isNotEmpty(roleUsers)) { - for (String roleUser : roleUsers) { - if (StringUtils.isBlank(roleUser)) { - continue; - } + LOG.debug("New user entries to be inserted into x_role_ref_user for role ID {}: {}", roleId, roleUsers); + + Set filteredUserNames = roleUsers.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + + List xxRoleRefUsers = new ArrayList<>(); + Map userNameIdMap = daoMgr.getXXUser().getIdsByUserNames(filteredUserNames); - RolePrincipalAssociator associator = new RolePrincipalAssociator(PolicyRefUpdater.PRINCIPAL_TYPE.USER, roleUser, roleId); + for (String userName : filteredUserNames) { + Long userId = userNameIdMap.get(userName); + RoleUserAssociator associator = new RoleUserAssociator(userName, userId, roleId, roleExists); - if (!associator.doAssociate(false)) { - if (isCreateNonExistentUGRs) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - throw restErrorUtil.createRESTException("user with name: " + roleUser + " does not exist ", MessageEnums.INVALID_INPUT_DATA); + if (userId != null) { + XXRoleRefUser userRef = associator.getRoleRef(); + + if (userRef != null) { + xxRoleRefUsers.add(userRef); } + } else if (isCreateNonExistentUGRs) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + throw restErrorUtil.createRESTException("user with name: " + userName + " does not exist ", MessageEnums.INVALID_INPUT_DATA); } } + + batchInsert(xxRoleRefUsers, daoMgr.getXXRoleRefUser(), oldBulkMode); } if (CollectionUtils.isNotEmpty(roleGroups)) { - for (String roleGroup : roleGroups) { - if (StringUtils.isBlank(roleGroup)) { - continue; - } + LOG.debug("New group entries to be inserted into x_role_ref_group for role ID {}: {}", roleId, roleGroups); + + Set filteredGroupNames = roleGroups.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); - RolePrincipalAssociator associator = new RolePrincipalAssociator(PolicyRefUpdater.PRINCIPAL_TYPE.GROUP, roleGroup, roleId); + List xxRoleRefGroups = new ArrayList<>(); + Map groupNameIdMap = daoMgr.getXXGroup().getIdsByGroupNames(filteredGroupNames); - if (!associator.doAssociate(false)) { - if (isCreateNonExistentUGRs) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - throw restErrorUtil.createRESTException("Group with name: " + roleGroup + " does not exist ", MessageEnums.INVALID_INPUT_DATA); + for (String groupName : filteredGroupNames) { + Long groupId = groupNameIdMap.get(groupName); + RoleGroupAssociator associator = new RoleGroupAssociator(groupName, groupId, roleId, roleExists); + + if (groupId != null) { + XXRoleRefGroup groupRef = associator.getRoleRef(); + + if (groupRef != null) { + xxRoleRefGroups.add(groupRef); } + } else if (isCreateNonExistentUGRs) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + throw restErrorUtil.createRESTException("Group with name: " + groupName + " does not exist ", MessageEnums.INVALID_INPUT_DATA); } } + + batchInsert(xxRoleRefGroups, daoMgr.getXXRoleRefGroup(), oldBulkMode); } if (CollectionUtils.isNotEmpty(roleRoles)) { - for (String roleRole : roleRoles) { - if (StringUtils.isBlank(roleRole)) { - continue; - } + LOG.debug("New sub role entries to be inserted into x_role_ref_role for role ID {}: {}", roleId, roleRoles); - RolePrincipalAssociator associator = new RolePrincipalAssociator(PolicyRefUpdater.PRINCIPAL_TYPE.ROLE, roleRole, roleId); + Set filteredSubRoleNames = roleRoles.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); - if (!associator.doAssociate(false)) { - if (isCreateNonExistentUGRs) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - throw restErrorUtil.createRESTException("Role with name: " + roleRole + " does not exist ", MessageEnums.INVALID_INPUT_DATA); + List xxRoleRefRoles = new ArrayList<>(); + Map subRoleNameIdMap = daoMgr.getXXRole().getIdsByRoleNames(filteredSubRoleNames); + + for (String subRoleName : filteredSubRoleNames) { + Long subRoleId = subRoleNameIdMap.get(subRoleName); + RoleRoleAssociator associator = new RoleRoleAssociator(subRoleName, subRoleId, roleId, roleExists); + + if (subRoleId != null) { + XXRoleRefRole roleRef = associator.getRoleRef(); + + if (roleRef != null) { + xxRoleRefRoles.add(roleRef); } + } else if (isCreateNonExistentUGRs) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + throw restErrorUtil.createRESTException("Role with name: " + subRoleName + " does not exist ", MessageEnums.INVALID_INPUT_DATA); } } + + batchInsert(xxRoleRefRoles, daoMgr.getXXRoleRefRole(), oldBulkMode); } } @@ -186,203 +232,461 @@ public Boolean cleanupRefTables(RangerRole rangerRole) { return true; } - private class RolePrincipalAssociator implements Runnable { - final PolicyRefUpdater.PRINCIPAL_TYPE type; - final String name; - final Long roleId; + public Boolean cleanupRefTablesForUpdate(RangerRole rangerRole, Set roleUsers, Set roleGroups, Set roleRoles) { + final Long roleId = rangerRole.getId(); + if (roleId == null) { + return false; + } + + cleanupRoleUsers(roleUsers, roleId, daoMgr.getXXRoleRefUser()); + cleanupRoleGroups(roleGroups, roleId, daoMgr.getXXRoleRefGroup()); + cleanupRoleRoles(roleRoles, roleId, daoMgr.getXXRoleRefRole()); + + return true; + } - public RolePrincipalAssociator(PolicyRefUpdater.PRINCIPAL_TYPE type, String name, Long roleId) { - this.type = type; - this.name = name; - this.roleId = roleId; + /** + * Synchronizes the role-user associations for a given role by identifying and removing + * users who are no longer associated with the role in the incoming data. + *

+ * This method compares the current set of users assigned to the role (`roleUsers`) + * with the existing role-user mappings stored in the database (`userNameIdMap`). + * It determines which users should be deleted (present in the DB but not in `roleUsers`) + * and removes their associations using the DAO. + *

+ * After execution: + *

    + *
  • Users present in both the database and `roleUsers` (i.e., common users) are left unchanged.
  • + *
  • Users present in the database but not in `roleUsers` are deleted.
  • + *
  • The `roleUsers` set is modified to remove users that are already associated, leaving only new users to be inserted (if needed later).
  • + *
+ * + * @param roleUsers Set of usernames that should be currently associated with the role. + * This is the source of truth, typically coming from an external request. + * @param roleId ID of the role for which the cleanup is being performed. + * @param dao DAO for role reference users. + */ + private void cleanupRoleUsers(Set roleUsers, Long roleId, XXRoleRefUserDao dao) { + Map userNameIdMap = dao.findUserNameIdMapByRoleId(roleId); + if (userNameIdMap != null && !userNameIdMap.isEmpty()) { + Set existingUsers = userNameIdMap.keySet(); + Set toDeleteUsers = new HashSet<>(existingUsers); + Set commonUsers = new HashSet<>(roleUsers); + + // Identify users present in both new and existing sets + commonUsers.retainAll(toDeleteUsers); + + // Identify users to delete (in DB but not in new set) + toDeleteUsers.removeAll(commonUsers); + + // Remove already existing users from the new set (they don’t need to be inserted again) + roleUsers.removeAll(commonUsers); + if (CollectionUtils.isNotEmpty(toDeleteUsers)) { + List idsToDelete = toDeleteUsers.stream() + .map(userNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting user IDs from x_role_ref_user table: {} for role ID: {}", idsToDelete, roleId); + dao.deleteRoleRefUserByIds(idsToDelete); + } } + } - @Override - public void run() { - if (doAssociate(true)) { - LOG.debug("Associated {}:{} with role id:[{}]", type.name(), name, roleId); - } else { - throw new RuntimeException("Failed to associate " + type.name() + ":" + name + " with role id:[" + roleId + "]"); + /** + * Synchronizes role-group associations for a given role by identifying and removing + * groups that are no longer associated with the role in the incoming data. + *

+ * This method compares the current set of groups that should be associated with a role + * (`roleGroups`) against the existing group-role mappings from the database (`groupNameIdMap`). + * It determines which group associations should be deleted (present in DB but not in input set), + * and deletes those associations using the DAO. + *

+ * After execution: + *

    + *
  • Groups present in both the input and DB (i.e., common groups) are preserved.
  • + *
  • Groups present in the DB but not in the input set are deleted.
  • + *
  • The `roleGroups` input set is modified to only include new groups to be inserted later (if any).
  • + *
+ * + * @param roleGroups Set of group names that should be associated with the role. + * This is the latest source of truth (e.g., from an API or external input). + * @param roleId The ID of the role for which associations are being synced. + * @param dao DAO for role reference groups. + */ + private void cleanupRoleGroups(Set roleGroups, Long roleId, XXRoleRefGroupDao dao) { + Map groupNameIdMap = dao.findGroupNameIdByRoleId(roleId); + if (groupNameIdMap != null && !groupNameIdMap.isEmpty()) { + // All groups currently associated in the DB + Set existingGroups = groupNameIdMap.keySet(); + + // Create a mutable set to track deletions + Set toDeleteGroups = new HashSet<>(existingGroups); + + // Identify common groups between input and existing + Set commonGroups = new HashSet<>(roleGroups); + commonGroups.retainAll(toDeleteGroups); + + // Remove common groups from both sets to isolate only new and obsolete entries + toDeleteGroups.removeAll(commonGroups); // only those to be deleted + roleGroups.removeAll(commonGroups); // only those to be newly inserted + + if (CollectionUtils.isNotEmpty(toDeleteGroups)) { + List idsToDelete = toDeleteGroups.stream() + .map(groupNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting group IDs from x_role_ref_group table: {} for role ID: {}", idsToDelete, roleId); + dao.deleteRoleRefGroupByIds(idsToDelete); + } + } + } + + /** + * Synchronizes sub-role associations for a given parent role by identifying and removing + * sub-roles that are no longer associated with the parent role in the incoming data. + *

+ * This method compares the current set of sub-roles that should be associated with a role + * (`roleRoles`) against the existing role-role mappings stored in the database (`subRoleNameIdMap`). + * It determines which sub-role associations should be removed (those present in the DB but not in the new set) + * and deletes them using the provided DAO. + *

+ * After execution: + *

    + *
  • Sub-roles that are present in both the input set and DB (common roles) are preserved.
  • + *
  • Sub-roles that are present in the DB but missing from the input set are deleted.
  • + *
  • The input set `roleRoles` is modified to retain only new sub-roles that may be inserted later.
  • + *
+ * + * @param roleRoles A set of sub-role names that should currently be associated with the parent role. + * This represents the latest state (e.g., from an external request). + * @param roleId The ID of the parent role for which sub-role associations are being updated. + * @param dao DAO for role reference roles. + */ + private void cleanupRoleRoles(Set roleRoles, Long roleId, XXRoleRefRoleDao dao) { + Map subRoleNameIdMap = dao.findSubRoleNameIdByRoleId(roleId); + if (subRoleNameIdMap != null && !subRoleNameIdMap.isEmpty()) { + // Get the current set of associated sub-roles from DB + Set existingRoles = subRoleNameIdMap.keySet(); + + // Prepare to identify obsolete sub-roles + Set toDeleteRoles = new HashSet<>(existingRoles); + + // Identify roles that are common in both new and existing sets + Set commonRoles = new HashSet<>(roleRoles); + commonRoles.retainAll(toDeleteRoles); + + // Remove common roles from the deletion list and the new input set + toDeleteRoles.removeAll(commonRoles); + roleRoles.removeAll(commonRoles); + + // Delete obsolete sub-role associations + if (!toDeleteRoles.isEmpty()) { + List idsToDelete = toDeleteRoles.stream() + .map(subRoleNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting role IDs from x_role_ref_role table: {} for role ID: {}", idsToDelete, roleId); + dao.deleteRoleRefRoleByIds(idsToDelete); } } + } + + private class RoleUserAssociator implements Runnable { + private final String name; + private final Long userId; + private final Long roleId; + private final boolean roleExists; + + RoleUserAssociator(String name, Long userId, Long roleId, boolean roleExists) { + this.name = name; + this.userId = userId; + this.roleId = roleId; + this.roleExists = roleExists; + } + + public XXRoleRefUser getRoleRef() { + Long id = resolveUserId(false); - boolean doAssociate(boolean isAdmin) { - LOG.debug("===> RolePrincipalAssociator.doAssociate({})", isAdmin); + if (id != null && roleExists) { + XXRoleRefUser xRoleRefUser = new XXRoleRefUser(); - final boolean ret; + xRoleRefUser.setRoleId(roleId); + xRoleRefUser.setUserId(id); + xRoleRefUser.setUserName(name); + xRoleRefUser.setUserType(0); + + return xRoleRefUser; + } + + return null; + } - Long id = createOrGetPrincipal(isAdmin); + public void createRoleRef(Long id) { + if (roleExists) { + XXRoleRefUser xRoleRefUser = new XXRoleRefUser(); + + xRoleRefUser.setRoleId(roleId); + xRoleRefUser.setUserId(id); + xRoleRefUser.setUserName(name); + xRoleRefUser.setUserType(0); + + daoMgr.getXXRoleRefUser().create(xRoleRefUser); + } else { + LOG.info("Role with id ={} does not exist, skipping role association!", roleId); + } + } + + @Override + public void run() { + Long id = resolveUserId(true); if (id != null) { - // associate with role - createRoleAssociation(id, name); + createRoleRef(id); - ret = true; + LOG.debug("Associated USER:{} with role id:[{}]", name, roleId); } else { - ret = false; + throw new RuntimeException("Failed to associate USER:" + name + " with role id:[" + roleId + "]"); } + } + + private Long resolveUserId(boolean createIfAbsent) { + Long ret = userId; - LOG.debug("<=== RolePrincipalAssociator.doAssociate({}) : {}", isAdmin, ret); + if (ret == null) { + XXUser xUser = daoMgr.getXXUser().findByUserName(name); + + if (xUser != null) { + ret = xUser.getId(); + } else if (createIfAbsent) { + ret = createUser(); + } + } return ret; } - private Long createOrGetPrincipal(final boolean createIfAbsent) { - LOG.debug("===> RolePrincipalAssociator.createOrGetPrincipal({})", createIfAbsent); + private Long createUser() { + LOG.warn("User specified in role does not exist in ranger admin, creating new user, name = {}", name); - Long ret = null; + VXUser vXUser = xUserMgr.createServiceConfigUser(name); - switch (type) { - case USER: { - XXUser xUser = daoMgr.getXXUser().findByUserName(name); + if (vXUser != null) { + XXUser xUser = daoMgr.getXXUser().findByUserName(name); - if (xUser != null) { - ret = xUser.getId(); - } else { - if (createIfAbsent) { - ret = createPrincipal(name); - } - } - } - break; - case GROUP: { - XXGroup xGroup = daoMgr.getXXGroup().findByGroupName(name); - - if (xGroup != null) { - ret = xGroup.getId(); - } else { - if (createIfAbsent) { - ret = createPrincipal(name); - } - } + if (xUser == null) { + LOG.error("No User created!! Irrecoverable error! [{}]", name); + } else { + return xUser.getId(); } - break; - case ROLE: { - XXRole xRole = daoMgr.getXXRole().findByRoleName(name); - - if (xRole != null) { - ret = xRole.getId(); - } else { - if (createIfAbsent) { - RangerBizUtil.setBulkMode(false); - ret = createPrincipal(name); - } - } - } - break; - default: - break; + } else { + LOG.warn("serviceConfigUser:[{}] creation failed. This may be a transient/spurious condition that may correct itself when transaction is committed", name); } - LOG.debug("<=== RolePrincipalAssociator.createOrGetPrincipal({}) : {}", createIfAbsent, ret); + return null; + } + } - return ret; + private class RoleGroupAssociator implements Runnable { + private final String name; + private final Long groupId; + private final Long roleId; + private final boolean roleExists; + + RoleGroupAssociator(String name, Long groupId, Long roleId, boolean roleExists) { + this.name = name; + this.groupId = groupId; + this.roleId = roleId; + this.roleExists = roleExists; } - private Long createPrincipal(String user) { - LOG.warn("{} specified in role does not exist in ranger admin, creating new {}, Type: {}, name = {}", type.name(), type.name(), type.name(), user); + public XXRoleRefGroup getRoleRef() { + Long id = resolveGroupId(false); - LOG.debug("===> RolePrincipalAssociator.createPrincipal(type={}, name={})", type.name(), name); + if (id != null && roleExists) { + XXRoleRefGroup xRoleRefGroup = new XXRoleRefGroup(); - Long ret = null; + xRoleRefGroup.setRoleId(roleId); + xRoleRefGroup.setGroupId(id); + xRoleRefGroup.setGroupName(name); + xRoleRefGroup.setGroupType(0); - switch (type) { - case USER: { - // Create External user - VXUser vXUser = xUserMgr.createServiceConfigUser(name); - if (vXUser != null) { - XXUser xUser = daoMgr.getXXUser().findByUserName(name); + return xRoleRefGroup; + } - if (xUser == null) { - LOG.error("No User created!! Irrecoverable error! [{}]", name); - } else { - ret = xUser.getId(); - } - } else { - LOG.warn("serviceConfigUser:[{}] creation failed. This may be a transient/spurious condition that may correct itself when transaction is committed", name); - } - } - break; - case GROUP: { - // Create group - VXGroup vxGroup = new VXGroup(); + return null; + } - vxGroup.setName(name); - vxGroup.setDescription(name); - vxGroup.setGroupSource(RangerCommonEnums.GROUP_EXTERNAL); + public void createRoleRef(Long id) { + if (roleExists) { + XXRoleRefGroup xRoleRefGroup = new XXRoleRefGroup(); - VXGroup vXGroup = xGroupService.createXGroupWithOutLogin(vxGroup); + xRoleRefGroup.setRoleId(roleId); + xRoleRefGroup.setGroupId(id); + xRoleRefGroup.setGroupName(name); + xRoleRefGroup.setGroupType(0); - if (vXGroup != null) { - xGroupService.createTransactionLog(vXGroup, null, OPERATION_CREATE_CONTEXT); + daoMgr.getXXRoleRefGroup().create(xRoleRefGroup); + } else { + LOG.info("Role with id ={} does not exist, skipping role association!", roleId); + } + } - ret = vXGroup.getId(); - } - } - break; - case ROLE: { - // Create role - try { - RangerRole rRole = new RangerRole(name, null, null, null, null); - RangerRole createdRole = roleStore.createRole(rRole, false); - - ret = createdRole.getId(); - } catch (Exception e) { - LOG.error("Failed to create Role {}", type.name()); - } - } - break; - default: - break; + @Override + public void run() { + Long id = resolveGroupId(true); + + if (id != null) { + createRoleRef(id); + + LOG.debug("Associated GROUP:{} with role id:[{}]", name, roleId); + } else { + throw new RuntimeException("Failed to associate GROUP:" + name + " with role id:[" + roleId + "]"); } + } + + private Long resolveGroupId(boolean createIfAbsent) { + Long ret = groupId; - LOG.debug("<=== RolePrincipalAssociator.createPrincipal(type={}, name={}) : {}", type.name(), name, ret); + if (ret == null) { + XXGroup xGroup = daoMgr.getXXGroup().findByGroupName(name); + + if (xGroup != null) { + ret = xGroup.getId(); + } else if (createIfAbsent) { + ret = createGroup(); + } + } return ret; } - private void createRoleAssociation(Long id, String name) { - LOG.debug("===> RolePrincipalAssociator.createRoleAssociation(roleId={}, type={}, name={}, id={})", roleId, type.name(), name, id); + private Long createGroup() { + LOG.warn("Group specified in role does not exist in ranger admin, creating new group, name = {}", name); - switch (type) { - case USER: { - XXRoleRefUser xRoleRefUser = new XXRoleRefUser(); + VXGroup vxGroup = new VXGroup(); - xRoleRefUser.setRoleId(roleId); - xRoleRefUser.setUserId(id); - xRoleRefUser.setUserName(name); - xRoleRefUser.setUserType(0); + vxGroup.setName(name); + vxGroup.setDescription(name); + vxGroup.setGroupSource(RangerCommonEnums.GROUP_EXTERNAL); - daoMgr.getXXRoleRefUser().create(xRoleRefUser); - } - break; - case GROUP: { - XXRoleRefGroup xRoleRefGroup = new XXRoleRefGroup(); + VXGroup vXGroup = xGroupService.createXGroupWithOutLogin(vxGroup); - xRoleRefGroup.setRoleId(roleId); - xRoleRefGroup.setGroupId(id); - xRoleRefGroup.setGroupName(name); - xRoleRefGroup.setGroupType(0); + if (vXGroup != null) { + xGroupService.createTransactionLog(vXGroup, null, OPERATION_CREATE_CONTEXT); - daoMgr.getXXRoleRefGroup().create(xRoleRefGroup); - } - break; - case ROLE: { - XXRoleRefRole xRoleRefRole = new XXRoleRefRole(); + return vXGroup.getId(); + } + + return null; + } + } + + private class RoleRoleAssociator implements Runnable { + private final String name; + private final Long subRoleId; + private final Long roleId; + private final boolean roleExists; + + RoleRoleAssociator(String name, Long subRoleId, Long roleId, boolean roleExists) { + this.name = name; + this.subRoleId = subRoleId; + this.roleId = roleId; + this.roleExists = roleExists; + } + + public XXRoleRefRole getRoleRef() { + Long id = resolveSubRoleId(false); - xRoleRefRole.setRoleId(roleId); - xRoleRefRole.setSubRoleId(id); - xRoleRefRole.setSubRoleName(name); - xRoleRefRole.setSubRoleType(0); + if (id != null && roleExists) { + XXRoleRefRole xRoleRefRole = new XXRoleRefRole(); - daoMgr.getXXRoleRefRole().create(xRoleRefRole); + xRoleRefRole.setRoleId(roleId); + xRoleRefRole.setSubRoleId(id); + xRoleRefRole.setSubRoleName(name); + xRoleRefRole.setSubRoleType(0); + + return xRoleRefRole; + } + + return null; + } + + public void createRoleRef(Long id) { + if (roleExists) { + XXRoleRefRole xRoleRefRole = new XXRoleRefRole(); + + xRoleRefRole.setRoleId(roleId); + xRoleRefRole.setSubRoleId(id); + xRoleRefRole.setSubRoleName(name); + xRoleRefRole.setSubRoleType(0); + + daoMgr.getXXRoleRefRole().create(xRoleRefRole); + } else { + LOG.info("Role with id ={} does not exist, skipping role association!", roleId); + } + } + + @Override + public void run() { + Long id = resolveSubRoleId(true); + + if (id != null) { + createRoleRef(id); + + LOG.debug("Associated ROLE:{} with role id:[{}]", name, roleId); + } else { + throw new RuntimeException("Failed to associate ROLE:" + name + " with role id:[" + roleId + "]"); + } + } + + private Long resolveSubRoleId(boolean createIfAbsent) { + Long ret = subRoleId; + + if (ret == null) { + XXRole xRole = daoMgr.getXXRole().findByRoleName(name); + + if (xRole != null) { + ret = xRole.getId(); + } else if (createIfAbsent) { + RangerBizUtil.setBulkMode(false); + + ret = createSubRole(); } - break; - default: - break; } - LOG.debug("<=== RolePrincipalAssociator.createRoleAssociation(roleId={}, type={}, name={}, id={})", roleId, type.name(), name, id); + return ret; + } + + private Long createSubRole() { + LOG.warn("Sub-role specified in role does not exist in ranger admin, creating new role, name = {}", name); + + try { + RangerRole rRole = new RangerRole(name, null, null, null, null); + RangerRole createdRole = roleStore.createRole(rRole, false, false); + + return createdRole.getId(); + } catch (Exception e) { + LOG.error("Failed to create sub-role {}", name, e); + + return null; + } + } + } + + private void batchInsert(List entities, BaseDao dao, boolean oldBulkMode) { + if (CollectionUtils.isNotEmpty(entities)) { + long startTimeMs = System.currentTimeMillis(); + + LOG.debug("Batch insert started for create/update {} with {} records.", dao.getClass().getSimpleName(), entities.size()); + + RangerBizUtil.setBulkMode(false); + dao.batchCreate(entities); + RangerBizUtil.setBulkMode(oldBulkMode); + + LOG.debug("Batch insert completed for create/update {} with {} records in {} ms.", dao.getClass().getSimpleName(), entities.size(), (System.currentTimeMillis() - startTimeMs)); } } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java index 5a7e008af02..2897aee06b5 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java @@ -26,8 +26,11 @@ import javax.persistence.NoResultException; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service public class XXRoleRefGroupDao extends BaseDao { @@ -92,6 +95,26 @@ public List findByGroupName(String groupName) { } } + public Map findGroupNameIdByRoleId(Long roleId) { + Map ret = Collections.emptyMap(); + if (roleId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXRoleRefGroup.findGroupNameIdByRoleId", Object[].class) + .setParameter("roleId", roleId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1], + (existing, replacement) -> existing)); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + public void deleteRoleRefGroupByIds(List ids) { if (CollectionUtils.isNotEmpty(ids)) { batchDeleteByIds("XXRoleRefGroup.deleteRoleRefGroupByIds", ids, "ids"); diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java index 2416a301d82..92b28acd4a6 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java @@ -26,10 +26,13 @@ import javax.persistence.NoResultException; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; @Service public class XXRoleRefRoleDao extends BaseDao { @@ -124,6 +127,26 @@ public Set getContainingRoles(Long subRoleId) { return ret; } + public Map findSubRoleNameIdByRoleId(Long roleId) { + Map ret = Collections.emptyMap(); + if (roleId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXRoleRefRole.findSubRoleNameIdByRoleId", Object[].class) + .setParameter("roleId", roleId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1], + (existing, replacement) -> existing)); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + public void deleteRoleRefRoleByIds(List ids) { if (CollectionUtils.isNotEmpty(ids)) { batchDeleteByIds("XXRoleRefRole.deleteRoleRefRoleByIds", ids, "ids"); diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java index 8e276a7b527..4c336446e1c 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java @@ -26,8 +26,11 @@ import javax.persistence.NoResultException; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service public class XXRoleRefUserDao extends BaseDao { @@ -65,6 +68,26 @@ public List findIdsByRoleId(Long roleId) { return ret; } + public Map findUserNameIdMapByRoleId(Long roleId) { + Map ret = Collections.emptyMap(); + if (roleId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXRoleRefUser.findUserNameIdByRoleId", Object[].class) + .setParameter("roleId", roleId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1], + (existing, replacement) -> existing)); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + public List findByUserId(Long userId) { if (userId == null) { return Collections.emptyList(); diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java index 471fbfbdd8a..1011f6d717d 100644 --- a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java +++ b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java @@ -172,7 +172,7 @@ public RangerRole createRole(@QueryParam("serviceName") String serviceName, Rang throw new Exception("Invalid role user(s)"); } - ret = roleStore.createRole(role, createNonExistUserGroup); + ret = roleStore.createRole(role, createNonExistUserGroup, false); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -226,7 +226,7 @@ public RangerRole updateRole(@PathParam("id") Long roleId, RangerRole role, @Def throw new Exception("Invalid role user(s)"); } - ret = roleStore.updateRole(role, createNonExistUserGroup); + ret = roleStore.updateRole(role, createNonExistUserGroup, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -520,7 +520,7 @@ public RESTResponse importRolesFromFile(@Context HttpServletRequest request, @Fo LOG.debug("Ignoring Roles from provided role in Json file... {}", roleNameInJson); } else { - roleStore.updateRole(roleInJson, createNonExistUserGroupRole); + roleStore.updateRole(roleInJson, createNonExistUserGroupRole, true); totalRoleUpdate++; } @@ -540,7 +540,7 @@ public RESTResponse importRolesFromFile(@Context HttpServletRequest request, @Fo ret.setStatusCode(RESTResponse.STATUS_SUCCESS); } else if (!roleNameList.contains(roleNameInJson) && (!roleNameInJson.isEmpty())) { try { - roleStore.createRole(roleInJson, createNonExistUserGroupRole); + roleStore.createRole(roleInJson, createNonExistUserGroupRole, false); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -720,7 +720,7 @@ public RangerRole addUsersAndGroups(@PathParam("id") Long roleId, @QueryParam("u role.setUsers(new ArrayList<>(roleUsers)); role.setGroups(new ArrayList<>(roleGroups)); - role = roleStore.updateRole(role, false); + role = roleStore.updateRole(role, false, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -786,7 +786,7 @@ public RangerRole removeUsersAndGroups(@PathParam("id") Long roleId, @QueryParam } } - role = roleStore.updateRole(role, false); + role = roleStore.updateRole(role, false, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -840,7 +840,7 @@ public RangerRole removeAdminFromUsersAndGroups(@PathParam("id") Long roleId, @Q } } - role = roleStore.updateRole(role, false); + role = roleStore.updateRole(role, false, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -1486,7 +1486,7 @@ private RangerRole addUsersGroupsAndRoles(RangerRole role, Set users, Se role.setGroups(new ArrayList<>(roleGroups)); role.setRoles(new ArrayList<>(roleRoles)); - role = roleStore.updateRole(role, false); + role = roleStore.updateRole(role, false, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -1548,7 +1548,7 @@ private RangerRole removeUsersGroupsAndRoles(RangerRole role, Set users, } } - role = roleStore.updateRole(role, false); + role = roleStore.updateRole(role, false, true); } catch (WebApplicationException excp) { throw excp; } catch (Throwable excp) { @@ -1595,7 +1595,7 @@ private RangerRole removeAdminFromUsersGroupsAndRoles(RangerRole role, Setselect obj.id from XXRoleRefUser obj where obj.roleId = :roleId + + SELECT obj.userName, obj.id FROM XXRoleRefUser obj WHERE obj.roleId = :roleId + + select obj from XXRoleRefUser obj where obj.userId = :userId @@ -2040,6 +2044,10 @@ select obj from XXRoleRefGroup obj where obj.groupName = :groupName + + SELECT obj.groupName, obj.id FROM XXRoleRefGroup obj WHERE obj.roleId = :roleId + + select obj from XXRoleRefRole obj where obj.roleId = :roleId @@ -2060,6 +2068,10 @@ select count(obj.roleId) from XXRoleRefRole obj where obj.subRoleName = :subRoleName + + SELECT obj.subRoleName, obj.id FROM XXRoleRefRole obj WHERE obj.roleId = :roleId + + DELETE FROM XXRoleRefGroup obj WHERE obj.id IN :ids diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestPolicyRefUpdater.java b/security-admin/src/test/java/org/apache/ranger/biz/TestPolicyRefUpdater.java index d4da4e98283..6855b009106 100644 --- a/security-admin/src/test/java/org/apache/ranger/biz/TestPolicyRefUpdater.java +++ b/security-admin/src/test/java/org/apache/ranger/biz/TestPolicyRefUpdater.java @@ -323,11 +323,6 @@ public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { xPolicy.setId(10L); xPolicy.setService(100L); - // FIX: Mock policy DAO hierarchy to satisfy doesPolicyExist(xPolicy) checks - org.apache.ranger.db.XXPolicyDao policyDao = mock(org.apache.ranger.db.XXPolicyDao.class); - when(daoMgr.getXXPolicy()).thenReturn(policyDao); - when(policyDao.getById(xPolicy.getId())).thenReturn(xPolicy); - // Mock audit population to be identity Mockito.lenient().when(rangerAuditFields.populateAuditFields(Mockito.any(), Mockito.any())) .thenAnswer(inv -> inv.getArgument(0)); @@ -355,9 +350,9 @@ public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { } assertNotNull(userAssociatorClass); Constructor userCtor = userAssociatorClass.getDeclaredConstructor( - PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class, boolean.class); userCtor.setAccessible(true); - Object associatorUser = userCtor.newInstance(updater, "uNew", null, xPolicy); + Object associatorUser = userCtor.newInstance(updater, "uNew", null, xPolicy, true); Method runUser = userAssociatorClass.getDeclaredMethod("run"); runUser.setAccessible(true); runUser.invoke(associatorUser); @@ -384,9 +379,9 @@ public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { } assertNotNull(groupAssociatorClass); Constructor groupCtor = groupAssociatorClass.getDeclaredConstructor( - PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class, boolean.class); groupCtor.setAccessible(true); - Object associatorGroup = groupCtor.newInstance(updater, "gNew", null, xPolicy); + Object associatorGroup = groupCtor.newInstance(updater, "gNew", null, xPolicy, true); Method runGroup = groupAssociatorClass.getDeclaredMethod("run"); runGroup.setAccessible(true); runGroup.invoke(associatorGroup); @@ -400,7 +395,7 @@ public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { when(roleDao.findByRoleName("rNew")).thenReturn(null); RangerRole createdRole = new RangerRole("rNew", null, null, null, null); createdRole.setId(33L); - when(roleStore.createRole(Mockito.any(RangerRole.class), Mockito.eq(false))).thenReturn(createdRole); + when(roleStore.createRole(Mockito.any(RangerRole.class), Mockito.eq(false), Mockito.eq(false))).thenReturn(createdRole); XXPolicyRefRoleDao polRoleDao = mock(XXPolicyRefRoleDao.class); when(daoMgr.getXXPolicyRefRole()).thenReturn(polRoleDao); @@ -413,9 +408,9 @@ public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { } assertNotNull(roleAssociatorClass); Constructor roleCtor = roleAssociatorClass.getDeclaredConstructor( - PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class, boolean.class); roleCtor.setAccessible(true); - Object associatorRole = roleCtor.newInstance(updater, "rNew", null, xPolicy); + Object associatorRole = roleCtor.newInstance(updater, "rNew", null, xPolicy, true); Method runRole = roleAssociatorClass.getDeclaredMethod("run"); runRole.setAccessible(true); runRole.invoke(associatorRole); diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestRoleDBStore.java b/security-admin/src/test/java/org/apache/ranger/biz/TestRoleDBStore.java index e6a0cdc3184..75f8a722373 100644 --- a/security-admin/src/test/java/org/apache/ranger/biz/TestRoleDBStore.java +++ b/security-admin/src/test/java/org/apache/ranger/biz/TestRoleDBStore.java @@ -389,7 +389,7 @@ public void testCreateRoleWhenTheRoleExists() throws Exception { Mockito.when(daoMgr.getXXRole()).thenReturn(xxRoleDao); Mockito.when(xxRoleDao.findByRoleName(roleName)).thenReturn(xxRole); Mockito.when(restErrorUtil.createRESTException(Mockito.anyString(), Mockito.any())).thenThrow(new WebApplicationException()); - Assertions.assertThrows(WebApplicationException.class, () -> roleDBStore.createRole(rangerRole, true)); + Assertions.assertThrows(WebApplicationException.class, () -> roleDBStore.createRole(rangerRole, true, false)); } @Test @@ -403,10 +403,10 @@ public void testCreateRole() throws Exception { Mockito.when(roleService.create(rangerRole)).thenReturn(rangerRole); Mockito.when(roleService.read(xxRole.getId())).thenReturn(rangerRole); Mockito.doNothing().when(transactionSynchronizationAdapter).executeOnTransactionCommit(Mockito.any()); - Mockito.doNothing().when(roleRefUpdater).createNewRoleMappingForRefTable(Mockito.any(), Mockito.anyBoolean()); + Mockito.doNothing().when(roleRefUpdater).createNewRoleMappingForRefTable(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean()); Mockito.doNothing().when(roleService).createTransactionLog(Mockito.any(), Mockito.any(), Mockito.anyInt()); - roleDBStore.createRole(rangerRole, true); + roleDBStore.createRole(rangerRole, true, false); } @Test @@ -417,7 +417,7 @@ public void testUpdateRoleWhenTheRoleNotExists() throws Exception { Mockito.when(daoMgr.getXXRole()).thenReturn(xxRoleDao); Mockito.when(xxRoleDao.findByRoleId(rangerRole.getId())).thenReturn(null); Mockito.when(restErrorUtil.createRESTException(Mockito.anyString())).thenThrow(new WebApplicationException()); - Assertions.assertThrows(WebApplicationException.class, () -> roleDBStore.updateRole(rangerRole, true)); + Assertions.assertThrows(WebApplicationException.class, () -> roleDBStore.updateRole(rangerRole, true, true)); } @Test @@ -430,11 +430,11 @@ public void testUpdateRole() throws Exception { Mockito.when(xxRoleDao.findByRoleId(rangerRole.getId())).thenReturn(xxRole); Mockito.doNothing().when(transactionSynchronizationAdapter).executeOnTransactionCommit(Mockito.any()); Mockito.when(roleService.update(rangerRole)).thenReturn(rangerRole); - Mockito.doNothing().when(roleRefUpdater).createNewRoleMappingForRefTable(Mockito.any(), Mockito.anyBoolean()); + Mockito.doNothing().when(roleRefUpdater).createNewRoleMappingForRefTable(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean()); Mockito.doNothing().when(roleService).updatePolicyVersions(rangerRole.getId()); Mockito.doNothing().when(roleService).createTransactionLog(Mockito.any(), Mockito.any(), Mockito.anyInt()); - roleDBStore.updateRole(rangerRole, true); + roleDBStore.updateRole(rangerRole, true, true); } @Test @@ -544,7 +544,7 @@ public void testUpdateRole_nameChangeNotAllowed_dueToPolicyReference() throws Ex toUpdate.setName("new-name"); try { - roleDBStore.updateRole(toUpdate, true); + roleDBStore.updateRole(toUpdate, true, true); Assertions.fail("Expected exception for name change not allowed"); } catch (Exception expected) { Assertions.assertTrue(expected.getMessage().contains("can not be updated")); diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestRoleRefUpdater.java b/security-admin/src/test/java/org/apache/ranger/biz/TestRoleRefUpdater.java index 96cb3a6ef84..8d1a5ef999e 100644 --- a/security-admin/src/test/java/org/apache/ranger/biz/TestRoleRefUpdater.java +++ b/security-admin/src/test/java/org/apache/ranger/biz/TestRoleRefUpdater.java @@ -44,9 +44,12 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -137,16 +140,28 @@ public void test02_createNewRoleMapping_createsAssociationsForExistingPrincipals xg.setId(22L); XXRole xr = new XXRole(); xr.setId(33L); - when(xUserDao.findByUserName("u1")).thenReturn(xu); - when(xGroupDao.findByGroupName("g1")).thenReturn(xg); - when(xRoleDao.findByRoleName("r1")).thenReturn(xr); + XXRole parentRole = new XXRole(); + parentRole.setId(5L); + when(xRoleDao.getById(5L)).thenReturn(parentRole); + when(urd.findUserNameIdMapByRoleId(5L)).thenReturn(Collections.emptyMap()); + when(grd.findGroupNameIdByRoleId(5L)).thenReturn(Collections.emptyMap()); + when(rrd.findSubRoleNameIdByRoleId(5L)).thenReturn(Collections.emptyMap()); + Map userIds = new HashMap<>(); + userIds.put("u1", 11L); + Map groupIds = new HashMap<>(); + groupIds.put("g1", 22L); + Map roleIds = new HashMap<>(); + roleIds.put("r1", 33L); + when(xUserDao.getIdsByUserNames(anySet())).thenReturn(userIds); + when(xGroupDao.getIdsByGroupNames(anySet())).thenReturn(groupIds); + when(xRoleDao.getIdsByRoleNames(anySet())).thenReturn(roleIds); RangerRole role = buildRole(5L, Collections.singletonList("u1"), Collections.singletonList("g1"), Collections.singletonList("r1")); - updater.createNewRoleMappingForRefTable(role, true); - verify(urd, times(1)).create(any(XXRoleRefUser.class)); - verify(grd, times(1)).create(any(XXRoleRefGroup.class)); - verify(rrd, times(1)).create(any(XXRoleRefRole.class)); + updater.createNewRoleMappingForRefTable(role, true, true); + verify(urd, times(1)).batchCreate(any()); + verify(grd, times(1)).batchCreate(any()); + verify(rrd, times(1)).batchCreate(any()); } @Test @@ -154,6 +169,7 @@ public void test03_createNewRoleMapping_missingPrincipalThrowsUnlessCreateAllowe RoleRefUpdater updater = new RoleRefUpdater(); RangerDaoManager dao = mock(RangerDaoManager.class); XXUserDao xUserDao = mock(XXUserDao.class); + XXRoleDao xRoleDao = mock(XXRoleDao.class); RESTErrorUtil rest = mock(RESTErrorUtil.class); RangerTransactionSynchronizationAdapter adapter = mock(RangerTransactionSynchronizationAdapter.class); RangerBizUtil biz = mock(RangerBizUtil.class); @@ -165,23 +181,76 @@ public void test03_createNewRoleMapping_missingPrincipalThrowsUnlessCreateAllowe setField(updater, RoleRefUpdater.class, "rangerTransactionSynchronizationAdapter", adapter); setField(updater, RoleRefUpdater.class, "xaBizUtil", biz); when(dao.getXXUser()).thenReturn(xUserDao); + when(dao.getXXRole()).thenReturn(xRoleDao); + XXRole parentRole = new XXRole(); + parentRole.setId(7L); + when(xRoleDao.getById(7L)).thenReturn(parentRole); when(dao.getXXRoleRefUser()).thenReturn(urd); when(dao.getXXRoleRefGroup()).thenReturn(grd); when(dao.getXXRoleRefRole()).thenReturn(rrd); - when(urd.findIdsByRoleId(7L)).thenReturn(Collections.emptyList()); - when(grd.findIdsByRoleId(7L)).thenReturn(Collections.emptyList()); - when(rrd.findIdsByRoleId(7L)).thenReturn(Collections.emptyList()); + when(urd.findUserNameIdMapByRoleId(7L)).thenReturn(Collections.emptyMap()); + when(grd.findGroupNameIdByRoleId(7L)).thenReturn(Collections.emptyMap()); + when(rrd.findSubRoleNameIdByRoleId(7L)).thenReturn(Collections.emptyMap()); + when(xUserDao.getIdsByUserNames(anySet())).thenReturn(Collections.emptyMap()); when(biz.checkAdminAccess()).thenReturn(false); RangerRole role = buildRole(7L, Collections.singletonList("missingUser"), Collections.emptyList(), Collections.emptyList()); RuntimeException expected = new RuntimeException("missing"); when(rest.createRESTException(anyString(), any())).thenThrow(expected); - Assertions.assertThrows(RuntimeException.class, () -> updater.createNewRoleMappingForRefTable(role, false)); + Assertions.assertThrows(RuntimeException.class, () -> updater.createNewRoleMappingForRefTable(role, false, false)); - // allow creation: should schedule associator + // allow creation: should schedule associator (principal creation runs on transaction commit) when(biz.checkAdminAccess()).thenReturn(true); - updater.createNewRoleMappingForRefTable(role, true); + updater.createNewRoleMappingForRefTable(role, true, true); verify(adapter, times(1)).executeOnTransactionCommit(any(Runnable.class)); } + + @Test + public void test04_cleanupRefTablesForUpdate_selectivePrincipalCleanup() throws Exception { + RoleRefUpdater updater = new RoleRefUpdater(); + RangerDaoManager dao = mock(RangerDaoManager.class); + XXRoleRefUserDao urd = mock(XXRoleRefUserDao.class); + XXRoleRefGroupDao grd = mock(XXRoleRefGroupDao.class); + XXRoleRefRoleDao rrd = mock(XXRoleRefRoleDao.class); + when(dao.getXXRoleRefUser()).thenReturn(urd); + when(dao.getXXRoleRefGroup()).thenReturn(grd); + when(dao.getXXRoleRefRole()).thenReturn(rrd); + setField(updater, RoleRefUpdater.class, "daoMgr", dao); + + final Long roleId = 100L; + java.util.Set roleUsers = new java.util.HashSet<>(Arrays.asList("alice", "bob", "carol")); + java.util.Set roleRoles = new java.util.HashSet<>(Arrays.asList("roleA", "roleB", "roleNew")); + java.util.Set roleGroups = new java.util.HashSet<>(Arrays.asList("grp1", "grp2", "grpNew")); + + Map existingUsers = new HashMap<>(); + existingUsers.put("alice", 1L); + existingUsers.put("bob", 2L); + existingUsers.put("dave", 4L); + + Map existingRoles = new HashMap<>(); + existingRoles.put("roleA", 10L); + existingRoles.put("roleOld", 12L); + + Map existingGroups = new HashMap<>(); + existingGroups.put("grp1", 20L); + existingGroups.put("grpOld", 22L); + + when(urd.findUserNameIdMapByRoleId(roleId)).thenReturn(existingUsers); + when(rrd.findSubRoleNameIdByRoleId(roleId)).thenReturn(existingRoles); + when(grd.findGroupNameIdByRoleId(roleId)).thenReturn(existingGroups); + + RangerRole role = new RangerRole("role", null, null, null, null); + role.setId(roleId); + Assertions.assertTrue(updater.cleanupRefTablesForUpdate(role, roleUsers, roleGroups, roleRoles)); + + verify(urd).deleteRoleRefUserByIds(Collections.singletonList(4L)); + Assertions.assertEquals(Collections.singleton("carol"), roleUsers); + + verify(rrd).deleteRoleRefRoleByIds(Collections.singletonList(12L)); + Assertions.assertEquals(new java.util.HashSet<>(Arrays.asList("roleB", "roleNew")), roleRoles); + + verify(grd).deleteRoleRefGroupByIds(Collections.singletonList(22L)); + Assertions.assertEquals(new java.util.HashSet<>(Arrays.asList("grp2", "grpNew")), roleGroups); + } } diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestRoleREST.java b/security-admin/src/test/java/org/apache/ranger/rest/TestRoleREST.java index ff692d637d4..e5806d3dcc8 100644 --- a/security-admin/src/test/java/org/apache/ranger/rest/TestRoleREST.java +++ b/security-admin/src/test/java/org/apache/ranger/rest/TestRoleREST.java @@ -176,11 +176,12 @@ public void destroySession() { @Test public void test1CreateRole() { boolean createNonExistUserGroup = true; + boolean isRefTableCleanupRequired = false; Mockito.when(validatorFactory.getRangerRoleValidator(roleStore)).thenReturn(Mockito.mock(RangerRoleValidator.class)); Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); RangerRole rangerRole = createRole(); try { - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); } catch (Exception e) { throw new RuntimeException(e); } @@ -194,6 +195,7 @@ public void test1CreateRole() { @Test public void test2UpdateRole() { Boolean createNonExistUserGroup = Boolean.TRUE; + boolean isRefTableCleanupRequired = true; RangerRole rangerRole = createRole(); RangerRole rangerRoleOld = createRoleOld(); Mockito.when(validatorFactory.getRangerRoleValidator(roleStore)).thenReturn(Mockito.mock(RangerRoleValidator.class)); @@ -205,7 +207,7 @@ public void test2UpdateRole() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).thenReturn(rangerRole); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); } catch (Exception e) { throw new RuntimeException(e); } @@ -310,6 +312,7 @@ public void test10AddUsersAndGroups() { List users = new ArrayList<>(Arrays.asList("test-role", "admin")); List groups = new ArrayList<>(Arrays.asList("group1", "group2")); Boolean isAdmin = true; + boolean isRefTableCleanupRequired = true; Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRole); @@ -317,7 +320,7 @@ public void test10AddUsersAndGroups() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired) )).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -330,6 +333,7 @@ public void test10AddUsersAndGroups() { @Test public void test10aAddUsersAndGroupsJsonBodyOverridesQuery() { RangerRole rangerRole = createRole(); + boolean isRefTableCleanupRequired = true; RoleUsersGroupsRequest body = new RoleUsersGroupsRequest(); body.setUsers(new ArrayList<>(Arrays.asList("body-user"))); body.setGroups(new ArrayList<>()); @@ -337,7 +341,7 @@ public void test10aAddUsersAndGroupsJsonBodyOverridesQuery() { Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRole); - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -354,6 +358,7 @@ public void test11RemoveUsersAndGroups() { List users = new ArrayList<>(Arrays.asList("test-role", "admin")); List groups = new ArrayList<>(Arrays.asList("test-group", "admin")); List createdRoleUsers = new ArrayList<>(); + boolean isRefTableCleanupRequired = true; for (RangerRole.RoleMember roleMember : rangerRole.getUsers()) { createdRoleUsers.add(roleMember.getName()); } @@ -368,7 +373,7 @@ public void test11RemoveUsersAndGroups() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -383,6 +388,7 @@ public void test11RemoveUsersAndGroups() { @Test public void test12RemoveAdminFromUsersAndGroups() { RangerRole rangerRole = createRoleWithUsersAndGroups(); + boolean isRefTableCleanupRequired = true; for (RangerRole.RoleMember role : rangerRole.getUsers()) { Assertions.assertTrue(role.getIsAdmin()); } @@ -406,7 +412,7 @@ public void test12RemoveAdminFromUsersAndGroups() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -426,10 +432,11 @@ public void test12RemoveAdminFromUsersAndGroups() { public void test13GrantRole() { RangerRole rangerRole = createRole(); String serviceName = "serviceName"; + boolean isRefTableCleanupRequired = true; GrantRevokeRoleRequest grantRevokeRoleRequest = createGrantRevokeRoleRequest(); Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true, true, true); try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -449,13 +456,14 @@ public void test14RevokeRole() { String serviceName = "serviceName"; GrantRevokeRoleRequest grantRevokeRoleRequest = createGrantRevokeRoleRequest(); Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true, true, true); + boolean isRefTableCleanupRequired = true; try { Mockito.when(roleStore.getRole(Mockito.anyString())).thenReturn(rangerRole, rangerRole, rangerRole, rangerRole); } catch (Exception e) { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -645,6 +653,7 @@ public void test10bAddUsersAndGroups() { List users = new ArrayList<>(Arrays.asList("test-role2", "test-role3")); List groups = new ArrayList<>(Arrays.asList("test-group2", "test-group3")); Boolean isAdmin = Boolean.TRUE; + boolean isRefTableCleanupRequired = true; Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRole); @@ -652,7 +661,7 @@ public void test10bAddUsersAndGroups() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -719,6 +728,7 @@ public void test14bRevokeRole() { String serviceName = "serviceName"; GrantRevokeRoleRequest grantRevokeRoleRequest = createGrantRevokeRoleRequest(); grantRevokeRoleRequest.setGrantOption(Boolean.TRUE); + boolean isRefTableCleanupRequired = true; Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true, true, true); try { Mockito.when(roleStore.getRole(Mockito.anyString())).thenReturn(rangerRole, rangerRole, rangerRole, rangerRole); @@ -726,7 +736,7 @@ public void test14bRevokeRole() { throw new RuntimeException(e); } try { - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -1156,10 +1166,11 @@ public void test20importRolesFromFile() throws Exception { FormDataContentDisposition fileDetail = FormDataContentDisposition.name("file").fileName(jsonRoleFile.getName()).size(uploadedInputStream.toString().length()).build(); boolean updateIfExists = false; boolean createNonExistUserGroupRole = false; + boolean isRefTableCleanupRequired = false; Mockito.when(searchUtil.getSearchFilter(request, roleService.sortFields)).thenReturn(filter); Mockito.when(roleStore.getRoleNames(Mockito.any(SearchFilter.class))).thenReturn(roleList); - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); RESTResponse resp = roleRest.importRolesFromFile(request, uploadedInputStream, fileDetail, updateIfExists, createNonExistUserGroupRole); Assertions.assertNotNull(resp); @@ -1183,10 +1194,11 @@ public void test20bimportRolesFromFile() throws Exception { FormDataContentDisposition fileDetail = FormDataContentDisposition.name("file").fileName(jsonRoleFile.getName()).size(uploadedInputStream.toString().length()).build(); boolean updateIfExists = false; boolean createNonExistUserGroupRole = true; + boolean isRefTableCleanupRequired = false; Mockito.when(searchUtil.getSearchFilter(request, roleService.sortFields)).thenReturn(filter); Mockito.when(roleStore.getRoleNames(Mockito.any(SearchFilter.class))).thenReturn(roleList); - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); RESTResponse resp = roleRest.importRolesFromFile(request, uploadedInputStream, fileDetail, updateIfExists, createNonExistUserGroupRole); Assertions.assertNotNull(resp); @@ -1214,7 +1226,8 @@ public void test20cimportRolesFromFileWithUpdate() throws Exception { Mockito.when(searchUtil.getSearchFilter(request, roleService.sortFields)).thenReturn(filter); Mockito.when(roleStore.getRoleNames(Mockito.any(SearchFilter.class))).thenReturn(roleList); Mockito.when(roleStore.getRole(Mockito.anyString())).thenReturn(rangerRole); - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole), eq(false))).thenReturn(rangerRole); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroupRole), eq(true))).thenReturn(rangerRole); RESTResponse resp = roleRest.importRolesFromFile(request, uploadedInputStream, fileDetail, updateIfExists, createNonExistUserGroupRole); Assertions.assertNotNull(resp); @@ -1455,12 +1468,12 @@ public void test23CreateRoleWithNullUsers() { boolean createNonExistUserGroup = true; RangerRole rangerRole = createRole(); rangerRole.setUsers(null); // Set users to null - + boolean isRefTableCleanupRequired = false; Mockito.when(validatorFactory.getRangerRoleValidator(roleStore)).thenReturn(Mockito.mock(RangerRoleValidator.class)); Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); } catch (Exception e) { throw new RuntimeException(e); } @@ -1473,6 +1486,7 @@ public void test23CreateRoleWithNullUsers() { @Test public void test24CreateRoleWithEmptyUsers() { boolean createNonExistUserGroup = true; + boolean isRefTableCleanupRequired = false; RangerRole rangerRole = createRole(); rangerRole.setUsers(new ArrayList<>()); // Set users to empty list @@ -1480,7 +1494,7 @@ public void test24CreateRoleWithEmptyUsers() { Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { - Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup))).thenReturn(rangerRole); + Mockito.when(roleStore.createRole(Mockito.any(RangerRole.class), eq(createNonExistUserGroup), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); } catch (Exception e) { throw new RuntimeException(e); } @@ -1493,6 +1507,7 @@ public void test24CreateRoleWithEmptyUsers() { @Test public void test25UpdateRoleWithConcurrentModification() { Boolean createNonExistUserGroup = Boolean.TRUE; + boolean isRefTableCleanupRequired = true; RangerRole rangerRole = createRole(); RangerRole rangerRoleOld = createRoleOld(); rangerRoleOld.setVersion(1L); @@ -1504,7 +1519,7 @@ public void test25UpdateRoleWithConcurrentModification() { try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRoleOld); - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).thenReturn(rangerRole); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).thenReturn(rangerRole); } catch (Exception e) { throw new RuntimeException(e); } @@ -1532,6 +1547,7 @@ public void test26GetRoleByNameNotFound() throws Exception { @Test public void test27AddUsersAndGroupsWithDuplicates() { RangerRole rangerRole = createRoleWithUsersAndGroups(); + boolean isRefTableCleanupRequired = true; List users = new ArrayList<>(Arrays.asList("test-role", "admin")); // Duplicate users List groups = new ArrayList<>(Arrays.asList("test-group", "admin")); // Duplicate groups Boolean isAdmin = true; @@ -1540,7 +1556,7 @@ public void test27AddUsersAndGroupsWithDuplicates() { try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRole); - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -1554,12 +1570,12 @@ public void test28RemoveUsersAndGroupsNonExistent() { RangerRole rangerRole = createRoleWithUsersAndGroups(); List users = new ArrayList<>(Arrays.asList("non-existent-user")); List groups = new ArrayList<>(Arrays.asList("non-existent-group")); - + boolean isRefTableCleanupRequired = true; Mockito.when(bizUtil.isUserRangerAdmin(Mockito.anyString())).thenReturn(true); try { Mockito.when(roleStore.getRole(Mockito.anyLong())).thenReturn(rangerRole); - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); } @@ -1583,6 +1599,7 @@ public void test29GrantRoleWithEmptyTargetRoles() { public void test30RevokeRoleWithNullGrantor() { RangerRole rangerRole = createRole(); String serviceName = "serviceName"; + boolean isRefTableCleanupRequired = true; GrantRevokeRoleRequest grantRevokeRoleRequest = createGrantRevokeRoleRequest(); grantRevokeRoleRequest.setGrantor(null); // Null grantor @@ -1590,7 +1607,7 @@ public void test30RevokeRoleWithNullGrantor() { try { Mockito.when(roleStore.getRole(Mockito.anyString())).thenReturn(rangerRole); - Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean())).then(AdditionalAnswers.returnsFirstArg()); + Mockito.when(roleStore.updateRole(Mockito.any(RangerRole.class), Mockito.anyBoolean(), eq(isRefTableCleanupRequired))).then(AdditionalAnswers.returnsFirstArg()); } catch (Exception e) { throw new RuntimeException(e); }