diff --git a/dev-support/checks/coverage.sh b/dev-support/checks/coverage.sh index eabf0a4a330..58a8a09bd2f 100755 --- a/dev-support/checks/coverage.sh +++ b/dev-support/checks/coverage.sh @@ -49,6 +49,10 @@ find . -type d -name 'target' -prune -exec find {} -type f \( -name 'ranger-*.ja -or -name '*shim*' -prune \ | xargs -n1 unzip -o -q -d target/coverage-classes +# Multi-release JARs (e.g. BouncyCastle) ship the same classes under +# META-INF/versions/* and at the root; JaCoCo fails with duplicate class names. +rm -rf target/coverage-classes/META-INF/versions || true + # get all source file paths src=$(find . -path '*/src/main/java' -o -path './target' -prune | sed 's/^/--sourcefiles /g' | xargs echo) 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 ab7eb5f67b3..6c8ede470c4 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 @@ -18,22 +18,18 @@ */ package org.apache.ranger.biz; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; 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.entity.XXAccessTypeDef; -import org.apache.ranger.entity.XXDataMaskTypeDef; +import org.apache.ranger.db.XXPolicyRefGroupDao; +import org.apache.ranger.db.XXPolicyRefRoleDao; +import org.apache.ranger.db.XXPolicyRefUserDao; import org.apache.ranger.entity.XXGroup; import org.apache.ranger.entity.XXPolicy; -import org.apache.ranger.entity.XXPolicyConditionDef; import org.apache.ranger.entity.XXPolicyRefAccessType; import org.apache.ranger.entity.XXPolicyRefCondition; import org.apache.ranger.entity.XXPolicyRefDataMaskType; @@ -41,7 +37,6 @@ import org.apache.ranger.entity.XXPolicyRefResource; import org.apache.ranger.entity.XXPolicyRefRole; import org.apache.ranger.entity.XXPolicyRefUser; -import org.apache.ranger.entity.XXResourceDef; import org.apache.ranger.entity.XXRole; import org.apache.ranger.entity.XXServiceDef; import org.apache.ranger.entity.XXUser; @@ -64,473 +59,781 @@ import javax.servlet.http.HttpServletResponse; -import static org.apache.ranger.service.RangerBaseModelService.OPERATION_CREATE_CONTEXT; +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; @Component public class PolicyRefUpdater { + private static final Logger LOG = LoggerFactory.getLogger(PolicyRefUpdater.class); + + @Autowired + RangerDaoManager daoMgr; + + @Autowired + XUserMgr xUserMgr; + + @Autowired + RoleDBStore roleStore; + + @Autowired + RangerBizUtil rangerBizUtil; + + @Autowired + XGroupService xGroupService; + + @Autowired + RangerTransactionSynchronizationAdapter rangerTransactionSynchronizationAdapter; + + @Autowired + RESTErrorUtil restErrorUtil; + + public static List> getAllPolicyItems(RangerPolicy policy) { + List> ret = new ArrayList<>(); + + if (CollectionUtils.isNotEmpty(policy.getPolicyItems())) { + ret.add(policy.getPolicyItems()); + } + + if (CollectionUtils.isNotEmpty(policy.getDenyPolicyItems())) { + ret.add(policy.getDenyPolicyItems()); + } + + if (CollectionUtils.isNotEmpty(policy.getAllowExceptions())) { + ret.add(policy.getAllowExceptions()); + } + + if (CollectionUtils.isNotEmpty(policy.getDenyExceptions())) { + ret.add(policy.getDenyExceptions()); + } + + if (CollectionUtils.isNotEmpty(policy.getDataMaskPolicyItems())) { + ret.add(policy.getDataMaskPolicyItems()); + } + + if (CollectionUtils.isNotEmpty(policy.getRowFilterPolicyItems())) { + ret.add(policy.getRowFilterPolicyItems()); + } + + return ret; + } + + public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy, XXServiceDef xServiceDef, boolean createPrincipalsIfAbsent, boolean isCleanupRefTablesNeeded) throws Exception { + if (policy == null) { + return; + } + + final Set resourceNames = policy.getResources().keySet(); + final Set roleNames = new HashSet<>(); + final Set groupNames = new HashSet<>(); + final Set userNames = new HashSet<>(); + final Set accessTypes = new HashSet<>(); + final Set conditionTypes = new HashSet<>(); + final Set dataMaskTypes = new HashSet<>(); + boolean oldBulkMode = RangerBizUtil.isBulkMode(); + final Long policyId = policy.getId(); + + List rangerPolicyConditions = policy.getConditions(); + + if (CollectionUtils.isNotEmpty(rangerPolicyConditions)) { + for (RangerPolicy.RangerPolicyItemCondition condition : rangerPolicyConditions) { + conditionTypes.add(condition.getType()); + } + } + + for (List policyItems : getAllPolicyItems(policy)) { + if (CollectionUtils.isEmpty(policyItems)) { + continue; + } + + for (RangerPolicyItem policyItem : policyItems) { + roleNames.addAll(policyItem.getRoles()); + groupNames.addAll(policyItem.getGroups()); + userNames.addAll(policyItem.getUsers()); + + if (CollectionUtils.isNotEmpty(policyItem.getAccesses())) { + for (RangerPolicyItemAccess access : policyItem.getAccesses()) { + accessTypes.add(access.getType()); + } + } + + if (CollectionUtils.isNotEmpty(policyItem.getConditions())) { + for (RangerPolicyItemCondition condition : policyItem.getConditions()) { + conditionTypes.add(condition.getType()); + } + } + + if (policyItem instanceof RangerDataMaskPolicyItem) { + RangerPolicyItemDataMaskInfo dataMaskInfo = ((RangerDataMaskPolicyItem) policyItem).getDataMaskInfo(); + + dataMaskTypes.add(dataMaskInfo.getDataMaskType()); + } + } + } + + if (isCleanupRefTablesNeeded) { + cleanupRefTablesForUpdate(policyId, userNames, roleNames, groupNames); + } + + if (CollectionUtils.isNotEmpty(resourceNames)) { + List xPolResources = new ArrayList<>(); + Map nameToId = daoMgr.getXXResourceDef().findResourceDefIdsByNameAndPolicyId(resourceNames, policy.getId()); + + for (String resource : resourceNames) { + Long resourceDefId = nameToId.get(resource); + + if (resourceDefId == null) { + throw new Exception(resource + ": is not a valid resource-type. policy='" + policy.getName() + "' service='" + policy.getService() + "'"); + } + + XXPolicyRefResource xPolRes = new XXPolicyRefResource(); + + xPolRes.setPolicyId(policy.getId()); + xPolRes.setResourceDefId(resourceDefId); + xPolRes.setResourceName(resource); + + xPolResources.add(xPolRes); + } + + batchInsert(xPolResources, daoMgr.getXXPolicyRefResource(), oldBulkMode); + } + + if (createPrincipalsIfAbsent && !rangerBizUtil.checkAdminAccess()) { + LOG.warn("policy={}: createPrincipalIfAbsent=true, but current user does not have admin privileges!", policy.getName()); + + createPrincipalsIfAbsent = false; + } + + if (CollectionUtils.isNotEmpty(roleNames)) { + LOG.debug("x_policy_ref_role - New role entries to insert for policy ID {}: {}", policyId, roleNames); + + Set filteredRoleNames = roleNames.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + + List xPolRoles = new ArrayList<>(); + Map nameToId = daoMgr.getXXRole().getIdsByRoleNames(filteredRoleNames); + + for (String roleName : filteredRoleNames) { + Long roleId = nameToId.get(roleName); + PolicyRoleAssociator associator = new PolicyRoleAssociator(roleName, roleId, xPolicy); + + if (roleId != null) { + XXPolicyRefRole roleRef = associator.getPolicyRef(); + + if (roleRef != null) { + xPolRoles.add(roleRef); + } + } else if (createPrincipalsIfAbsent) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + VXResponse gjResponse = new VXResponse(); + + gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); + gjResponse.setMsgDesc("Operation denied. Role name: " + roleName + " specified in policy does not exist in ranger admin."); + + throw restErrorUtil.generateRESTException(gjResponse); + } + } + + batchInsert(xPolRoles, daoMgr.getXXPolicyRefRole(), oldBulkMode); + } + + if (CollectionUtils.isNotEmpty(groupNames)) { + LOG.debug("x_policy_ref_group - New group entries to insert for policy ID {}: {}", policyId, groupNames); + + Set filteredGroupNames = groupNames.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + + List xPolGroups = new ArrayList<>(); + Map nameToId = daoMgr.getXXGroup().getIdsByGroupNames(filteredGroupNames); + + for (String groupName : filteredGroupNames) { + Long groupId = nameToId.get(groupName); + PolicyGroupAssociator associator = new PolicyGroupAssociator(groupName, groupId, xPolicy); + + if (groupId != null) { + XXPolicyRefGroup groupRef = associator.getPolicyRef(); + + if (groupRef != null) { + xPolGroups.add(groupRef); + } + } else if (createPrincipalsIfAbsent) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + VXResponse gjResponse = new VXResponse(); + + gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); + gjResponse.setMsgDesc("Operation denied. Group name: " + groupName + " specified in policy does not exist in ranger admin."); + + throw restErrorUtil.generateRESTException(gjResponse); + } + } + + batchInsert(xPolGroups, daoMgr.getXXPolicyRefGroup(), oldBulkMode); + } + + if (CollectionUtils.isNotEmpty(userNames)) { + LOG.debug("x_policy_ref_user - New user entries to insert for policy ID {}: {}", policyId, userNames); + + Set filteredUserNames = userNames.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + + List xPolUsers = new ArrayList<>(); + Map nameToId = daoMgr.getXXUser().getIdsByUserNames(filteredUserNames); + + for (String userName : filteredUserNames) { + Long userId = nameToId.get(userName); + PolicyUserAssociator associator = new PolicyUserAssociator(userName, userId, xPolicy); + + if (userId != null) { + XXPolicyRefUser userRef = associator.getPolicyRef(); + + if (userRef != null) { + xPolUsers.add(userRef); + } + } else if (createPrincipalsIfAbsent) { + rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); + } else { + VXResponse gjResponse = new VXResponse(); + + gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); + gjResponse.setMsgDesc("Operation denied. User name: " + userName + " specified in policy does not exist in ranger admin."); + + throw restErrorUtil.generateRESTException(gjResponse); + } + } + + batchInsert(xPolUsers, daoMgr.getXXPolicyRefUser(), oldBulkMode); + } + + // ignore built-in access-types while creating ref-table entries + accessTypes.removeAll(ServiceDefUtil.ACCESS_TYPE_MARKERS); + + if (CollectionUtils.isNotEmpty(accessTypes)) { + List xPolAccesses = new ArrayList<>(); + Map nameToId = daoMgr.getXXAccessTypeDef().findAccessTypeDefIdsByNamesAndServiceId(accessTypes, xPolicy.getService()); + + for (String accessType : accessTypes) { + Long accessDefId = nameToId.get(accessType); + + if (accessDefId == null) { + throw new Exception(accessType + ": is not a valid access-type. policy='" + policy.getName() + "' service='" + policy.getService() + "'"); + } + + XXPolicyRefAccessType xPolAccess = new XXPolicyRefAccessType(); + + xPolAccess.setPolicyId(policy.getId()); + xPolAccess.setAccessDefId(accessDefId); + xPolAccess.setAccessTypeName(accessType); + + xPolAccesses.add(xPolAccess); + } + + batchInsert(xPolAccesses, daoMgr.getXXPolicyRefAccessType(), oldBulkMode); + } + + if (CollectionUtils.isNotEmpty(conditionTypes)) { + List xPolConds = new ArrayList<>(); + Map nameToId = daoMgr.getXXPolicyConditionDef().findConditionDefIdsByServiceDefIdAndNames(xServiceDef.getId(), conditionTypes); + + for (String condition : conditionTypes) { + Long conditionDefId = nameToId.get(condition); + + if (conditionDefId == null) { + if (StringUtils.equalsIgnoreCase(condition, ServiceDefUtil.IMPLICIT_CONDITION_EXPRESSION_NAME)) { + continue; + } + + throw new Exception(condition + ": is not a valid condition-type. policy='" + xPolicy.getName() + "' service='" + xPolicy.getService() + "'"); + } + + XXPolicyRefCondition xPolCond = new XXPolicyRefCondition(); + + xPolCond.setPolicyId(policy.getId()); + xPolCond.setConditionDefId(conditionDefId); + xPolCond.setConditionName(condition); + + xPolConds.add(xPolCond); + } + + batchInsert(xPolConds, daoMgr.getXXPolicyRefCondition(), oldBulkMode); + } + + if (CollectionUtils.isNotEmpty(dataMaskTypes)) { + List xxDataMaskInfos = new ArrayList<>(); + Map nameToId = daoMgr.getXXDataMaskTypeDef().findDataMaskTypeDefIdsByNamesAndServiceId(dataMaskTypes, xPolicy.getService()); + + for (String dataMaskType : dataMaskTypes) { + Long dataMaskDefId = nameToId.get(dataMaskType); + + if (dataMaskDefId == null) { + throw new Exception(dataMaskType + ": is not a valid datamask-type. policy='" + policy.getName() + "' service='" + policy.getService() + "'"); + } + + XXPolicyRefDataMaskType xxDataMaskInfo = new XXPolicyRefDataMaskType(); + + xxDataMaskInfo.setPolicyId(policy.getId()); + xxDataMaskInfo.setDataMaskDefId(dataMaskDefId); + xxDataMaskInfo.setDataMaskTypeName(dataMaskType); + + xxDataMaskInfos.add(xxDataMaskInfo); + } + + batchInsert(xxDataMaskInfos, daoMgr.getXXPolicyRefDataMaskType(), oldBulkMode); + } + } + + public Boolean cleanupRefTables(RangerPolicy policy) { + final Long policyId = policy == null ? null : policy.getId(); + + if (policyId == null) { + return false; + } + + daoMgr.getXXPolicyRefResource().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefRole().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefGroup().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefUser().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefAccessType().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefCondition().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefDataMaskType().deleteByPolicyId(policyId); + + return true; + } + + /** + * Cleans up reference tables for a given policy before updating it. + * This includes handling policy reference users, roles, and other + * associated reference entities like resources, groups, access types, + * conditions, and data mask types. + * + * @param policyId ID of the policy being updated. + * @param policyUsers Set of usernames associated with the updated policy. + * @param policyRoles Set of role names associated with the updated policy. + * @param policyGroups Set of group names associated with the updated policy. + * @return true if cleanup was successful. + */ + public Boolean cleanupRefTablesForUpdate(Long policyId, Set policyUsers, Set policyRoles, Set policyGroups) { + cleanupPolicyRefUsers(policyUsers, policyId, daoMgr.getXXPolicyRefUser()); + cleanupPolicyRefRoles(policyRoles, policyId, daoMgr.getXXPolicyRefRole()); + cleanupPolicyRefGroups(policyGroups, policyId, daoMgr.getXXPolicyRefGroup()); + + daoMgr.getXXPolicyRefResource().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefAccessType().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefCondition().deleteByPolicyId(policyId); + daoMgr.getXXPolicyRefDataMaskType().deleteByPolicyId(policyId); + + return true; + } + + /** + * Identifies and deletes outdated user references for a given policy, + * and prepares a list of new users that need to be inserted. + * + * @param policyUsers Set of usernames from the new policy. + * @param policyId The ID of the policy. + * @param dao DAO for policy reference users. + */ + public void cleanupPolicyRefUsers(Set policyUsers, Long policyId, XXPolicyRefUserDao dao) { + Map policyUserNameIdMap = dao.findUserNameIdByPolicyId(policyId); + + if (policyUserNameIdMap != null && !policyUserNameIdMap.isEmpty()) { + Set existingPolicyRefUsers = policyUserNameIdMap.keySet(); + Set toDeletePolicyRefUsers = new HashSet<>(existingPolicyRefUsers); + Set commonUsers = new HashSet<>(policyUsers); + + // Identify users present in both new and existing sets + commonUsers.retainAll(toDeletePolicyRefUsers); + + // Identify users to delete (in DB but not in new set) + toDeletePolicyRefUsers.removeAll(commonUsers); + + // Remove already existing users from the new set (they don’t need to be inserted again) + policyUsers.removeAll(commonUsers); + + if (CollectionUtils.isNotEmpty(toDeletePolicyRefUsers)) { + List idsToDelete = toDeletePolicyRefUsers.stream() + .map(policyUserNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting user IDs from x_policy_ref_user table: {} for policy ID: {}", idsToDelete, policyId); + + dao.deletePolicyRefUserByIds(idsToDelete); + } + } + } + + /** + * Identifies and deletes outdated role references for a given policy, + * and prepares a list of new roles that need to be inserted. + * + * @param policyRoles Set of role names from the new policy. + * @param policyId The ID of the policy. + * @param dao DAO for policy reference roles. + */ + public void cleanupPolicyRefRoles(Set policyRoles, Long policyId, XXPolicyRefRoleDao dao) { + Map policyRoleNameIdMap = dao.findRoleNameIdByPolicyId(policyId); + + if (policyRoleNameIdMap != null && !policyRoleNameIdMap.isEmpty()) { + Set existingPolicyRefRoles = policyRoleNameIdMap.keySet(); + Set toDeletePolicyRefRoles = new HashSet<>(existingPolicyRefRoles); + Set commonRoles = new HashSet<>(policyRoles); + + // Identify roles present in both new and existing sets + commonRoles.retainAll(toDeletePolicyRefRoles); + + // Identify roles to delete (in DB but not in new set) + toDeletePolicyRefRoles.removeAll(commonRoles); + + // Remove already existing roles from the new set (they don’t need to be inserted again) + policyRoles.removeAll(commonRoles); + + if (CollectionUtils.isNotEmpty(toDeletePolicyRefRoles)) { + List idsToDelete = toDeletePolicyRefRoles.stream() + .map(policyRoleNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting Role IDs from x_policy_ref_role: {} for policy ID: {}", idsToDelete, policyId); + + dao.deletePolicyRefRoleByIds(idsToDelete); + } + } + } + + /** + * Identifies and deletes outdated group references for a given policy, + * and prepares a list of new groups that need to be inserted. + * + * @param policyGroups Set of group names from the new policy. + * @param policyId The ID of the policy. + * @param dao DAO for policy reference groups. + */ + public void cleanupPolicyRefGroups(Set policyGroups, Long policyId, XXPolicyRefGroupDao dao) { + Map policyGroupNameIdMap = dao.findGroupNameByPolicyId(policyId); + + if (policyGroupNameIdMap != null && !policyGroupNameIdMap.isEmpty()) { + Set existingPolicyRefGroups = policyGroupNameIdMap.keySet(); + Set toDeletePolicyRefGroups = new HashSet<>(existingPolicyRefGroups); + Set commonGroups = new HashSet<>(policyGroups); + + // Identify groups present in both new and existing sets + commonGroups.retainAll(toDeletePolicyRefGroups); + + // Identify groups to delete (in DB but not in new set) + toDeletePolicyRefGroups.removeAll(commonGroups); + + // Remove already existing groups from the new set (they don’t need to be inserted again) + policyGroups.removeAll(commonGroups); + + if (CollectionUtils.isNotEmpty(toDeletePolicyRefGroups)) { + List idsToDelete = toDeletePolicyRefGroups.stream() + .map(policyGroupNameIdMap::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + LOG.debug("Deleting Group IDs from x_policy_ref_group: {} for policy ID: {}", idsToDelete, policyId); + + dao.deletePolicyRefGroupByIds(idsToDelete); + } + } + } + + 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; + + PolicyRoleAssociator(String name, Long roleId, XXPolicy xPolicy) { + this.name = name; + this.roleId = roleId; + this.xPolicy = xPolicy; + } + + public XXPolicyRefRole getPolicyRef() { + Long id = resolveRoleId(false); + + if (id != null && doesPolicyExist(xPolicy)) { + XXPolicyRefRole xPolRole = new XXPolicyRefRole(); + + xPolRole.setPolicyId(xPolicy.getId()); + xPolRole.setRoleId(id); + xPolRole.setRoleName(name); + + return xPolRole; + } + + return null; + } + + public void createPolicyRef(Long id) { + if (doesPolicyExist(xPolicy)) { + XXPolicyRefRole xPolRole = new XXPolicyRefRole(); + + xPolRole.setPolicyId(xPolicy.getId()); + xPolRole.setRoleId(id); + xPolRole.setRoleName(name); + + daoMgr.getXXPolicyRefRole().create(xPolRole); + } else { + LOG.info("Policy with id ={} does not exist, skipping policy association!", xPolicy.getId()); + } + } + + @Override + public void run() { + Long id = resolveRoleId(true); + + if (id != null) { + createPolicyRef(id); + + LOG.debug("Associated ROLE:{} with policy id:[{}]", name, xPolicy.getId()); + } else { + throw new RuntimeException("Failed to associate ROLE:" + name + " with policy id:[" + xPolicy.getId() + "]"); + } + } + + private Long resolveRoleId(boolean createIfAbsent) { + Long ret = roleId; + + if (ret == null) { + XXRole xRole = daoMgr.getXXRole().findByRoleName(name); + + if (xRole != null) { + ret = xRole.getId(); + } else if (createIfAbsent) { + RangerBizUtil.setBulkMode(false); + + ret = createRole(); + } + } + + return ret; + } + + private Long createRole() { + LOG.warn("Role specified in policy 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); + + return createdRole.getId(); + } catch (Exception e) { + return null; + } + } + } + + private class PolicyGroupAssociator implements Runnable { + private final String name; + private final Long groupId; + private final XXPolicy xPolicy; + + PolicyGroupAssociator(String name, Long groupId, XXPolicy xPolicy) { + this.name = name; + this.groupId = groupId; + this.xPolicy = xPolicy; + } + + public XXPolicyRefGroup getPolicyRef() { + Long id = resolveGroupId(false); + + if (id != null && doesPolicyExist(xPolicy)) { + XXPolicyRefGroup xPolGroup = new XXPolicyRefGroup(); + + xPolGroup.setPolicyId(xPolicy.getId()); + xPolGroup.setGroupId(id); + xPolGroup.setGroupName(name); + + return xPolGroup; + } + + return null; + } + + public void createPolicyRef(Long id) { + if (doesPolicyExist(xPolicy)) { + XXPolicyRefGroup xPolGroup = new XXPolicyRefGroup(); + + xPolGroup.setPolicyId(xPolicy.getId()); + xPolGroup.setGroupId(id); + xPolGroup.setGroupName(name); + + daoMgr.getXXPolicyRefGroup().create(xPolGroup); + } else { + LOG.info("Policy with id ={} does not exist, skipping policy association!", xPolicy.getId()); + } + } + + @Override + public void run() { + Long id = resolveGroupId(true); + + if (id != null) { + createPolicyRef(id); + + LOG.debug("Associated GROUP:{} with policy id:[{}]", name, xPolicy.getId()); + } else { + throw new RuntimeException("Failed to associate GROUP:" + name + " with policy id:[" + xPolicy.getId() + "]"); + } + } + + private Long resolveGroupId(boolean createIfAbsent) { + Long ret = groupId; + + if (ret == null) { + XXGroup xGroup = daoMgr.getXXGroup().findByGroupName(name); + + if (xGroup != null) { + ret = xGroup.getId(); + } else if (createIfAbsent) { + ret = createGroup(); + } + } + + return ret; + } + + private Long createGroup() { + LOG.warn("Group specified in policy does not exist in ranger admin, creating new group, name = {}", name); + + VXGroup vxGroup = new VXGroup(); + + vxGroup.setName(name); + vxGroup.setDescription(name); + vxGroup.setGroupSource(RangerCommonEnums.GROUP_EXTERNAL); + + VXGroup vXGroup = xGroupService.createXGroupWithOutLogin(vxGroup); + + if (vXGroup != null) { + xGroupService.createTransactionLog(vXGroup, null, OPERATION_CREATE_CONTEXT, xPolicy.getAddedByUserId()); + + return vXGroup.getId(); + } + + return null; + } + } + + private class PolicyUserAssociator implements Runnable { + private final String name; + private final Long userId; + private final XXPolicy xPolicy; + + PolicyUserAssociator(String name, Long userId, XXPolicy xPolicy) { + this.name = name; + this.userId = userId; + this.xPolicy = xPolicy; + } + + public XXPolicyRefUser getPolicyRef() { + Long id = resolveUserId(false); + + if (id != null && doesPolicyExist(xPolicy)) { + XXPolicyRefUser xPolUser = new XXPolicyRefUser(); + + xPolUser.setPolicyId(xPolicy.getId()); + xPolUser.setUserId(id); + xPolUser.setUserName(name); + + return xPolUser; + } + + return null; + } + + public void createPolicyRef(Long id) { + if (doesPolicyExist(xPolicy)) { + XXPolicyRefUser xPolUser = new XXPolicyRefUser(); + + xPolUser.setPolicyId(xPolicy.getId()); + xPolUser.setUserId(id); + xPolUser.setUserName(name); + + daoMgr.getXXPolicyRefUser().create(xPolUser); + } else { + LOG.info("Policy with id ={} does not exist, skipping policy association!", xPolicy.getId()); + } + } + + @Override + public void run() { + Long id = resolveUserId(true); + + if (id != null) { + createPolicyRef(id); + + LOG.debug("Associated USER:{} with policy id:[{}]", name, xPolicy.getId()); + } else { + throw new RuntimeException("Failed to associate USER:" + name + " with policy id:[" + xPolicy.getId() + "]"); + } + } + + private Long resolveUserId(boolean createIfAbsent) { + Long ret = userId; + + if (ret == null) { + XXUser xUser = daoMgr.getXXUser().findByUserName(name); + + if (xUser != null) { + ret = xUser.getId(); + } else if (createIfAbsent) { + return createUser(); + } + } + + return ret; + } + + private Long createUser() { + LOG.warn("User specified in policy does not exist in ranger admin, creating new user, name = {}", name); - private static final Logger LOG = LoggerFactory.getLogger(PolicyRefUpdater.class); + VXUser vXUser = xUserMgr.createServiceConfigUser(name); - public enum PRINCIPAL_TYPE { USER, GROUP, ROLE } + if (vXUser != null) { + XXUser xUser = daoMgr.getXXUser().findByUserName(name); - @Autowired - RangerDaoManager daoMgr; + if (xUser == null) { + LOG.error("No User created!! Irrecoverable error! [{}]", name); + } else { + return xUser.getId(); + } + } else { + LOG.warn("serviceConfigUser:[{}] creation failed. This may be a transient/spurious condition that may correct itself when transaction is committed", name); + } - @Autowired - XUserMgr xUserMgr; + return null; + } + } - @Autowired - RoleDBStore roleStore; - - @Autowired - RangerBizUtil rangerBizUtil; - - @Autowired - XGroupService xGroupService; - - @Autowired - RangerTransactionSynchronizationAdapter rangerTransactionSynchronizationAdapter; - - @Autowired - RESTErrorUtil restErrorUtil; - - public void createNewPolMappingForRefTable(RangerPolicy policy, XXPolicy xPolicy, XXServiceDef xServiceDef, boolean createPrincipalsIfAbsent) throws Exception { - if(policy == null) { - return; - } - - cleanupRefTables(policy); - - final Set resourceNames = policy.getResources().keySet(); - final Set roleNames = new HashSet<>(); - final Set groupNames = new HashSet<>(); - final Set userNames = new HashSet<>(); - final Set accessTypes = new HashSet<>(); - final Set conditionTypes = new HashSet<>(); - final Set dataMaskTypes = new HashSet<>(); - boolean oldBulkMode = RangerBizUtil.isBulkMode(); - - List rangerPolicyConditions = policy.getConditions(); - if (CollectionUtils.isNotEmpty(rangerPolicyConditions)) { - for (RangerPolicy.RangerPolicyItemCondition condition : rangerPolicyConditions) { - conditionTypes.add(condition.getType()); - } - } - - for (List policyItems : getAllPolicyItems(policy)) { - if (CollectionUtils.isEmpty(policyItems)) { - continue; - } - - for (RangerPolicyItem policyItem : policyItems) { - roleNames.addAll(policyItem.getRoles()); - groupNames.addAll(policyItem.getGroups()); - userNames.addAll(policyItem.getUsers()); - - if (CollectionUtils.isNotEmpty(policyItem.getAccesses())) { - for (RangerPolicyItemAccess access : policyItem.getAccesses()) { - accessTypes.add(access.getType()); - } - } - - if (CollectionUtils.isNotEmpty(policyItem.getConditions())) { - for (RangerPolicyItemCondition condition : policyItem.getConditions()) { - conditionTypes.add(condition.getType()); - } - } - - if (policyItem instanceof RangerDataMaskPolicyItem) { - RangerPolicyItemDataMaskInfo dataMaskInfo = ((RangerDataMaskPolicyItem) policyItem).getDataMaskInfo(); - - dataMaskTypes.add(dataMaskInfo.getDataMaskType()); - } - } - } - - List xPolResources = new ArrayList<>(); - for (String resource : resourceNames) { - XXResourceDef xResDef = daoMgr.getXXResourceDef().findByNameAndPolicyId(resource, policy.getId()); - - if (xResDef == null) { - throw new Exception(resource + ": is not a valid resource-type. policy='"+ policy.getName() + "' service='"+ policy.getService() + "'"); - } - - XXPolicyRefResource xPolRes = new XXPolicyRefResource(); - - xPolRes.setPolicyId(policy.getId()); - xPolRes.setResourceDefId(xResDef.getId()); - xPolRes.setResourceName(resource); - - xPolResources.add(xPolRes); - } - daoMgr.getXXPolicyRefResource().batchCreate(xPolResources); - - if (createPrincipalsIfAbsent && !rangerBizUtil.checkAdminAccess()) { - LOG.warn("policy=" + policy.getName() + ": createPrincipalIfAbsent=true, but current user does not have admin privileges!"); - - createPrincipalsIfAbsent = false; - } - - List xPolRoles = new ArrayList<>(); - for (String role : roleNames) { - if (StringUtils.isBlank(role)) { - continue; - } - PolicyPrincipalAssociator associator = new PolicyPrincipalAssociator(PRINCIPAL_TYPE.ROLE, role, xPolicy); - if (!associator.doAssociate(false)) { - if (createPrincipalsIfAbsent) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - VXResponse gjResponse = new VXResponse(); - gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); - gjResponse.setMsgDesc("Operation denied. Role name: " + role + " specified in policy does not exist in ranger admin."); - throw restErrorUtil.generateRESTException(gjResponse); - } - } - } - RangerBizUtil.setBulkMode(oldBulkMode); - daoMgr.getXXPolicyRefRole().batchCreate(xPolRoles); - - for (String group : groupNames) { - if (StringUtils.isBlank(group)) { - continue; - } - - PolicyPrincipalAssociator associator = new PolicyPrincipalAssociator(PRINCIPAL_TYPE.GROUP, group, xPolicy); - if (!associator.doAssociate(false)) { - if (createPrincipalsIfAbsent) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - VXResponse gjResponse = new VXResponse(); - gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); - gjResponse.setMsgDesc("Operation denied. Group name: " + group + " specified in policy does not exist in ranger admin."); - throw restErrorUtil.generateRESTException(gjResponse); - } - } - } - - for (String user : userNames) { - if (StringUtils.isBlank(user)) { - continue; - } - PolicyPrincipalAssociator associator = new PolicyPrincipalAssociator(PRINCIPAL_TYPE.USER, user, xPolicy); - if (!associator.doAssociate(false)) { - if (createPrincipalsIfAbsent) { - rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(associator); - } else { - VXResponse gjResponse = new VXResponse(); - gjResponse.setStatusCode(HttpServletResponse.SC_BAD_REQUEST); - gjResponse.setMsgDesc("Operation denied. User name: " + user + " specified in policy does not exist in ranger admin."); - throw restErrorUtil.generateRESTException(gjResponse); - } - } - } - - List xPolAccesses = new ArrayList<>(); - - // ignore built-in access-types while creating ref-table entries - accessTypes.removeAll(ServiceDefUtil.ACCESS_TYPE_MARKERS); - - for (String accessType : accessTypes) { - XXAccessTypeDef xAccTypeDef = daoMgr.getXXAccessTypeDef().findByNameAndServiceId(accessType, xPolicy.getService()); - - if (xAccTypeDef == null) { - throw new Exception(accessType + ": is not a valid access-type. policy='" + policy.getName() + "' service='" + policy.getService() + "'"); - } - - XXPolicyRefAccessType xPolAccess = new XXPolicyRefAccessType(); - - xPolAccess.setPolicyId(policy.getId()); - xPolAccess.setAccessDefId(xAccTypeDef.getId()); - xPolAccess.setAccessTypeName(accessType); - - xPolAccesses.add(xPolAccess); - } - daoMgr.getXXPolicyRefAccessType().batchCreate(xPolAccesses); - - List xPolConds = new ArrayList<>(); - for (String condition : conditionTypes) { - XXPolicyConditionDef xPolCondDef = daoMgr.getXXPolicyConditionDef().findByServiceDefIdAndName(xServiceDef.getId(), condition); - - if (xPolCondDef == null) { - if (StringUtils.equalsIgnoreCase(condition, ServiceDefUtil.IMPLICIT_CONDITION_EXPRESSION_NAME)) { - continue; - } - - throw new Exception(condition + ": is not a valid condition-type. policy='"+ xPolicy.getName() + "' service='"+ xPolicy.getService() + "'"); - } - - XXPolicyRefCondition xPolCond = new XXPolicyRefCondition(); - - xPolCond.setPolicyId(policy.getId()); - xPolCond.setConditionDefId(xPolCondDef.getId()); - xPolCond.setConditionName(condition); - - xPolConds.add(xPolCond); - } - daoMgr.getXXPolicyRefCondition().batchCreate(xPolConds); - - List xxDataMaskInfos = new ArrayList<>(); - for (String dataMaskType : dataMaskTypes ) { - XXDataMaskTypeDef dataMaskDef = daoMgr.getXXDataMaskTypeDef().findByNameAndServiceId(dataMaskType, xPolicy.getService()); - - if (dataMaskDef == null) { - throw new Exception(dataMaskType + ": is not a valid datamask-type. policy='" + policy.getName() + "' service='" + policy.getService() + "'"); - } - - XXPolicyRefDataMaskType xxDataMaskInfo = new XXPolicyRefDataMaskType(); - - xxDataMaskInfo.setPolicyId(policy.getId()); - xxDataMaskInfo.setDataMaskDefId(dataMaskDef.getId()); - xxDataMaskInfo.setDataMaskTypeName(dataMaskType); - - xxDataMaskInfos.add(xxDataMaskInfo); - } - daoMgr.getXXPolicyRefDataMaskType().batchCreate(xxDataMaskInfos); - } - - private class PolicyPrincipalAssociator implements Runnable { - final PRINCIPAL_TYPE type; - final String name; - final XXPolicy xPolicy; - - public PolicyPrincipalAssociator(PRINCIPAL_TYPE type, String name, XXPolicy xPolicy) { - this.type = type; - this.name = name; - this.xPolicy = xPolicy; - } - - @Override - public void run() { - if (doAssociate(true)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Associated " + type.name() + ":" + name + " with policy id:[" + xPolicy.getId() + "]"); - } - } else { - throw new RuntimeException("Failed to associate " + type.name() + ":" + name + " with policy id:[" + xPolicy.getId() + "]"); - } - } - - boolean doAssociate(boolean isAdmin) { - if (LOG.isDebugEnabled()) { - LOG.debug("===> PolicyPrincipalAssociator.doAssociate(" + isAdmin + ")"); - } - final boolean ret; - - Long id = createOrGetPrincipal(isAdmin); - if (id != null) { - // associate with policy - createPolicyAssociation(id, name); - ret = true; - } else { - ret = false; - } - - if (LOG.isDebugEnabled()) { - LOG.debug("<=== PolicyPrincipalAssociator.doAssociate(" + isAdmin + ") : " + ret); - } - return ret; - } - - private Long createOrGetPrincipal(final boolean createIfAbsent) { - if (LOG.isDebugEnabled()) { - LOG.debug("===> PolicyPrincipalAssociator.createOrGetPrincipal(" + createIfAbsent + ")"); - } - - Long ret = null; - - switch (type) { - case USER: { - 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); - } - } - } - 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; - } - if (LOG.isDebugEnabled()) { - LOG.debug("<=== PolicyPrincipalAssociator.createOrGetPrincipal(" + createIfAbsent + ") : " + ret); - } - return ret; - } - - private Long createPrincipal(String user) { - LOG.warn("User specified in policy does not exist in ranger admin, creating new user, Type: " + type.name() + ", name = " + user); - - if (LOG.isDebugEnabled()) { - LOG.debug("===> PolicyPrincipalAssociator.createPrincipal(type=" + type.name() +", name=" + name + ")"); - } - - Long ret = null; - - switch (type) { - case USER: { - // Create External user - VXUser vXUser = xUserMgr.createServiceConfigUser(name); - if (vXUser != null) { - XXUser xUser = daoMgr.getXXUser().findByUserName(name); - - if (xUser == null) { - LOG.error("No User created!! Irrecoverable error! [" + name + "]"); - } else { - ret = xUser.getId(); - } - } else { - LOG.warn("serviceConfigUser:[" + name + "] creation failed. This may be a transient/spurious condition that may correct itself when transaction is committed"); - } - } - break; - case GROUP: { - // Create group - VXGroup vxGroup = new VXGroup(); - vxGroup.setName(name); - vxGroup.setDescription(name); - vxGroup.setGroupSource(RangerCommonEnums.GROUP_EXTERNAL); - VXGroup vXGroup = xGroupService.createXGroupWithOutLogin(vxGroup); - if (vXGroup != null) { - xGroupService.createTransactionLog(vXGroup, null, OPERATION_CREATE_CONTEXT, xPolicy.getAddedByUserId()); - - ret = vXGroup.getId(); - } - } - break; - case ROLE: { - try { - RangerRole rRole = new RangerRole(name, null, null, null, null); - RangerRole createdRole = roleStore.createRole(rRole, false); - ret = createdRole.getId(); - } catch (Exception e) { - // Ignore - } - } - break; - default: - break; - } - if (LOG.isDebugEnabled()) { - LOG.debug("<=== PolicyPrincipalAssociator.createPrincipal(type=" + type.name() + ", name=" + name + ") : " + ret); - } - return ret; - } - - private void createPolicyAssociation(Long id, String name) { - if(LOG.isDebugEnabled()) { - LOG.debug("===> PolicyPrincipalAssociator.createPolicyAssociation(policyId=" + xPolicy.getId() + ", type=" + type.name() + ", name=" + name + ", id=" + id + ")"); - } - switch (type) { - case USER: { - XXPolicyRefUser xPolUser = new XXPolicyRefUser(); - - xPolUser.setPolicyId(xPolicy.getId()); - xPolUser.setUserId(id); - xPolUser.setUserName(name); - daoMgr.getXXPolicyRefUser().create(xPolUser); - } - break; - case GROUP: { - XXPolicyRefGroup xPolGroup = new XXPolicyRefGroup(); - - xPolGroup.setPolicyId(xPolicy.getId()); - xPolGroup.setGroupId(id); - xPolGroup.setGroupName(name); - daoMgr.getXXPolicyRefGroup().create(xPolGroup); - } - break; - case ROLE: { - XXPolicyRefRole xPolRole = new XXPolicyRefRole(); - - xPolRole.setPolicyId(xPolicy.getId()); - xPolRole.setRoleId(id); - xPolRole.setRoleName(name); - daoMgr.getXXPolicyRefRole().create(xPolRole); - } - break; - default: - break; - } - if(LOG.isDebugEnabled()) { - LOG.debug("<=== PolicyPrincipalAssociator.createPolicyAssociation(policyId=" + xPolicy.getId() + ", type=" + type.name() + ", name=" + name + ", id=" + id + ")"); - } - } - } - - public Boolean cleanupRefTables(RangerPolicy policy) { - final Long policyId = policy == null ? null : policy.getId(); - - if (policyId == null) { - return false; - } - - daoMgr.getXXPolicyRefResource().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefRole().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefGroup().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefUser().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefAccessType().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefCondition().deleteByPolicyId(policyId); - daoMgr.getXXPolicyRefDataMaskType().deleteByPolicyId(policyId); - - return true; - } - - public static List> getAllPolicyItems(RangerPolicy policy) { - List> ret = new ArrayList<>(); - - if (CollectionUtils.isNotEmpty(policy.getPolicyItems())) { - ret.add(policy.getPolicyItems()); - } - - if (CollectionUtils.isNotEmpty(policy.getDenyPolicyItems())) { - ret.add(policy.getDenyPolicyItems()); - } - - if (CollectionUtils.isNotEmpty(policy.getAllowExceptions())) { - ret.add(policy.getAllowExceptions()); - } - - if (CollectionUtils.isNotEmpty(policy.getDenyExceptions())) { - ret.add(policy.getDenyExceptions()); - } - - if (CollectionUtils.isNotEmpty(policy.getDataMaskPolicyItems())) { - ret.add(policy.getDataMaskPolicyItems()); - } - - if (CollectionUtils.isNotEmpty(policy.getRowFilterPolicyItems())) { - ret.add(policy.getRowFilterPolicyItems()); - } - - return ret; - } + 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/biz/ServiceDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java index dc3802748f5..501d3e45466 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java @@ -2132,7 +2132,7 @@ public RangerPolicy createPolicy(RangerPolicy policy, boolean createPrincipalsIf } XXPolicy xCreatedPolicy = daoMgr.getXXPolicy().getById(policy.getId()); - policyRefUpdater.createNewPolMappingForRefTable(policy, xCreatedPolicy, xServiceDef, createPrincipalsIfAbsent); + policyRefUpdater.createNewPolMappingForRefTable(policy, xCreatedPolicy, xServiceDef, createPrincipalsIfAbsent, false); createOrMapLabels(xCreatedPolicy, uniquePolicyLabels); RangerPolicy createdPolicy = policyService.getPopulatedViewObject(xCreatedPolicy); @@ -2315,10 +2315,9 @@ public RangerPolicy updatePolicy(RangerPolicy policy) throws Exception { policy = policyService.update(policy); XXPolicy newUpdPolicy = daoMgr.getXXPolicy().getById(policy.getId()); - policyRefUpdater.cleanupRefTables(policy); deleteExistingPolicyLabel(policy); - policyRefUpdater.createNewPolMappingForRefTable(policy, newUpdPolicy, xServiceDef, bizUtil.getCreatePrincipalsIfAbsent()); + policyRefUpdater.createNewPolMappingForRefTable(policy, newUpdPolicy, xServiceDef, bizUtil.getCreatePrincipalsIfAbsent(), true); createOrMapLabels(newUpdPolicy, uniquePolicyLabels); RangerPolicy updPolicy = policyService.getPopulatedViewObject(newUpdPolicy); diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXAccessTypeDefDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXAccessTypeDefDao.java index 8f574985478..3fba90df0ac 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXAccessTypeDefDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXAccessTypeDefDao.java @@ -18,16 +18,25 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.NoResultException; +import org.apache.commons.collections.CollectionUtils; import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.entity.XXAccessTypeDef; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class XXAccessTypeDefDao extends BaseDao { + private static final Logger logger = LoggerFactory.getLogger(XXAccessTypeDefDao.class); public XXAccessTypeDefDao(RangerDaoManagerBase daoManager) { super(daoManager); @@ -60,4 +69,22 @@ public XXAccessTypeDef findByNameAndServiceId(String name, Long serviceId) { return null; } } + + public Map findAccessTypeDefIdsByNamesAndServiceId(Set names, Long serviceId) { + if (serviceId != null && CollectionUtils.isNotEmpty(names)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXAccessTypeDef.findAccessTypeDefIdsByNamesAndServiceId", Object[].class) + .setParameter("names", names) + .setParameter("serviceId", serviceId) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) object[1], object -> (Long) object[0], (a, b) -> a)); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXDataMaskTypeDefDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXDataMaskTypeDefDao.java index 83c28812716..b0fa0739619 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXDataMaskTypeDefDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXDataMaskTypeDefDao.java @@ -18,16 +18,25 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.NoResultException; +import org.apache.commons.collections.CollectionUtils; import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.entity.XXDataMaskTypeDef; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class XXDataMaskTypeDefDao extends BaseDao { + private static final Logger logger = LoggerFactory.getLogger(XXDataMaskTypeDefDao.class); public XXDataMaskTypeDefDao(RangerDaoManagerBase daoManager) { super(daoManager); @@ -60,4 +69,22 @@ public XXDataMaskTypeDef findByNameAndServiceId(String name, Long serviceId) { return null; } } + + public Map findDataMaskTypeDefIdsByNamesAndServiceId(Set names, Long serviceId) { + if (serviceId != null && CollectionUtils.isNotEmpty(names)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXDataMaskTypeDef.findDataMaskTypeDefIdsByNamesAndServiceId", Object[].class) + .setParameter("names", names) + .setParameter("serviceId", serviceId) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) object[1], object -> (Long) object[0], (a, b) -> a)); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXGroupDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXGroupDao.java index 12708f6a3f4..df7a11216ac 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXGroupDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXGroupDao.java @@ -21,10 +21,14 @@ import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ranger.authorization.utils.JsonUtils; import org.apache.ranger.common.RangerCommonEnums; @@ -117,6 +121,23 @@ public List getAllGroupsInfo() { return ret; } + public Map getIdsByGroupNames(Collection groupNames) { + if (CollectionUtils.isNotEmpty(groupNames)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXGroup.getIdsByGroupNames", Object[].class) + .setParameter("names", groupNames) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) (object[1]), object -> (Long) (object[0]))); + } catch (NoResultException excp) { + logger.debug(excp.getMessage()); + } + } + + return Collections.emptyMap(); + } + private GroupInfo toGroupInfo(Object[] row) { String name = (String) row[0]; String description = (String) row[1]; diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyConditionDefDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyConditionDefDao.java index de2c47dc420..bae897a6c54 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyConditionDefDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyConditionDefDao.java @@ -18,16 +18,25 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.NoResultException; +import org.apache.commons.collections.CollectionUtils; import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.entity.XXPolicyConditionDef; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class XXPolicyConditionDefDao extends BaseDao { + private static final Logger logger = LoggerFactory.getLogger(XXPolicyConditionDefDao.class); public XXPolicyConditionDefDao(RangerDaoManagerBase daoManager) { super(daoManager); @@ -61,5 +70,22 @@ public XXPolicyConditionDef findByServiceDefIdAndName(Long serviceDefId, String return null; } } - + + public Map findConditionDefIdsByServiceDefIdAndNames(Long serviceDefId, Set names) { + if (serviceDefId != null && CollectionUtils.isNotEmpty(names)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXPolicyConditionDef.findConditionDefIdsByServiceDefIdAndNames", Object[].class) + .setParameter("serviceDefId", serviceDefId) + .setParameter("names", names) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) object[1], object -> (Long) object[0], (a, b) -> a)); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefGroupDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefGroupDao.java index 3ce371306a7..8c5da614bf6 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefGroupDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefGroupDao.java @@ -20,8 +20,11 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.persistence.NoResultException; @@ -115,4 +118,30 @@ public void deleteByPolicyId(Long policyId) { batchDeleteByIds("XXPolicyRefGroup.deleteByIds", ids, "ids"); } + + public Map findGroupNameByPolicyId(Long policyId) { + Map ret = Collections.emptyMap(); + if (policyId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXPolicyRefGroup.findGroupNameByPolicyId", Object[].class) + .setParameter("policyId", policyId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1])); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + + public void deletePolicyRefGroupByIds(List ids) { + if (CollectionUtils.isEmpty(ids)) { + return; + } + batchDeleteByIds("XXPolicyRefGroup.deletePolicyRefGroupByIds", ids, "ids"); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java index 29d2bc4c94e..4dfe7372ea8 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java @@ -20,8 +20,11 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.persistence.NoResultException; @@ -127,5 +130,31 @@ public void deleteByPolicyId(Long policyId) { batchDeleteByIds("XXPolicyRefRole.deleteByIds", ids, "ids"); } + + public Map findRoleNameIdByPolicyId(Long policyId) { + Map ret = Collections.emptyMap(); + if (policyId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXPolicyRefRole.findRoleNameIdByPolicyId", Object[].class) + .setParameter("policyId", policyId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1])); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + + public void deletePolicyRefRoleByIds(List ids) { + if (CollectionUtils.isEmpty(ids)) { + return; + } + batchDeleteByIds("XXPolicyRefRole.deletePolicyRefRoleByIds", ids, "ids"); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefUserDao.java index 07d94ceb9ff..52543b2c36b 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefUserDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefUserDao.java @@ -20,8 +20,11 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.persistence.NoResultException; @@ -127,4 +130,30 @@ public void deleteByPolicyId(Long policyId) { batchDeleteByIds("XXPolicyRefUser.deleteByIds", ids, "ids"); } + + public Map findUserNameIdByPolicyId(Long policyId) { + Map ret = Collections.emptyMap(); + if (policyId != null) { + try { + Collection results = getEntityManager() + .createNamedQuery("XXPolicyRefUser.findUserNameIdByPolicyId", Object[].class) + .setParameter("policyId", policyId) + .getResultList(); + ret = results.stream().collect( + Collectors.toMap( + object -> (String) object[0], + object -> (Long) object[1])); + } catch (NoResultException e) { + // ignore + } + } + return ret; + } + + public void deletePolicyRefUserByIds(List ids) { + if (CollectionUtils.isEmpty(ids)) { + return; + } + batchDeleteByIds("XXPolicyRefUser.deletePolicyRefUserByIds", ids, "ids"); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXResourceDefDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXResourceDefDao.java index 56139027b81..df5d104ffe5 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXResourceDefDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXResourceDefDao.java @@ -18,16 +18,25 @@ package org.apache.ranger.db; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.NoResultException; +import org.apache.commons.collections.CollectionUtils; import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.entity.XXResourceDef; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @Service public class XXResourceDefDao extends BaseDao { + private static final Logger logger = LoggerFactory.getLogger(XXResourceDefDao.class); public XXResourceDefDao(RangerDaoManagerBase daoMgr) { super(daoMgr); @@ -99,4 +108,22 @@ public List findByParentResId(Long parentId) { return new ArrayList(); } } + + public Map findResourceDefIdsByNameAndPolicyId(Set names, Long policyId) { + if (policyId != null && CollectionUtils.isNotEmpty(names)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXResourceDef.findResourceDefIdsByNameAndPolicyId", Object[].class) + .setParameter("policyId", policyId) + .setParameter("names", names) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) object[1], object -> (Long) object[0], (a, b) -> a)); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java index 03e966934c0..1fb54895ed2 100644 --- a/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java @@ -17,18 +17,26 @@ package org.apache.ranger.db; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ranger.common.db.BaseDao; import org.apache.ranger.entity.XXRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.persistence.NoResultException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service public class XXRoleDao extends BaseDao { + private static final Logger logger = LoggerFactory.getLogger(XXRoleDao.class); /** * Default Constructor */ @@ -126,5 +134,22 @@ public List findByGroupId(Long groupId) { } return ret; } + + public Map getIdsByRoleNames(Collection roleNames) { + if (CollectionUtils.isNotEmpty(roleNames)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXRole.getIdsByRoleNames", Object[].class) + .setParameter("roleNames", roleNames) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) (object[1]), object -> (Long) (object[0]))); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } } diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java index 05c65322a63..61121788dee 100755 --- a/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java +++ b/security-admin/src/main/java/org/apache/ranger/db/XXUserDao.java @@ -21,6 +21,7 @@ import javax.persistence.NoResultException; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ranger.authorization.utils.JsonUtils; @@ -33,12 +34,15 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Set; -import java.util.HashSet; -import java.util.Map; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import static org.apache.ranger.plugin.util.RangerCommonConstants.*; @@ -186,6 +190,23 @@ public List getAllUsersInfo() { return ret; } + public Map getIdsByUserNames(Collection names) { + if (CollectionUtils.isNotEmpty(names)) { + try { + Collection result = getEntityManager() + .createNamedQuery("XXUser.getIdsByUserNames", Object[].class) + .setParameter("names", names) + .getResultList(); + + return result.stream().collect(Collectors.toMap(object -> (String) (object[1]), object -> (Long) (object[0]))); + } catch (NoResultException e) { + logger.debug(e.getMessage()); + } + } + + return Collections.emptyMap(); + } + private UserInfo toUserInfo(Object[] row) { String name = (String) row[0]; String description = (String) row[1]; diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml index 9db7bf1ca92..42d497792fc 100755 --- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml +++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml @@ -176,6 +176,10 @@ + + SELECT obj.id, obj.name FROM XXGroup obj WHERE obj.name IN :names + + SELECT user.name, group.name FROM XXUser user, XXGroup group, XXGroupUser groupUser @@ -193,12 +197,17 @@ + + SELECT obj.id, obj.name FROM XXUser obj WHERE obj.name IN :names + + SELECT p.principalName, p.principalType FROM VXXPrincipal p WHERE p.principalName LIKE :principalName AND p.isVisible = 1 ORDER BY p.principalName + SELECT user.name, user.description, user.otherAttributes, user.syncSource, pUser.userSource, pUser.emailAddress FROM XXUser user LEFT OUTER JOIN XXPortalUser pUser ON pUser.loginId = user.name @@ -582,6 +591,15 @@ and xSvc.id = xPol.service and xPol.id = :policyId and obj.name = :name order by obj.level + + SELECT obj.id, obj.name FROM XXResourceDef obj + WHERE obj.name IN :names AND obj.defId IN + (SELECT xSvcDef.id FROM XXServiceDef xSvcDef, XXService xSvc, XXPolicy xPol + WHERE xSvcDef.id = xSvc.type AND xSvc.id = xPol.service AND xPol.id = :policyId) + ORDER BY obj.level + + + select obj from XXResourceDef obj where obj.parent = :parentId @@ -635,6 +653,11 @@ obj.name = :name and xSvc.id = :serviceId and obj.defId = xSvc.type + + SELECT obj.id, obj.name FROM XXAccessTypeDef obj + WHERE obj.name IN :names AND obj.defId IN (SELECT xSvc.type FROM XXService xSvc WHERE xSvc.id = :serviceId) + + select obj from XXPolicyConditionDef obj where obj.defId = :serviceDefId order by obj.order @@ -644,6 +667,10 @@ select obj from XXPolicyConditionDef obj where obj.defId = :serviceDefId and obj.name = :name order by obj.order + + select obj.id, obj.name from XXPolicyConditionDef obj where obj.defId = :serviceDefId and obj.name IN :names order by obj.order + + select obj from XXContextEnricherDef obj where obj.defId = :serviceDefId order by obj.order @@ -669,6 +696,10 @@ obj.name = :name and xSvc.id = :serviceId and obj.defId = xSvc.type + + select obj.id, obj.name from XXDataMaskTypeDef obj, XXService xSvc where obj.name IN :names and xSvc.id = :serviceId and obj.defId = xSvc.type + + select obj from XXServiceConfigMap obj where obj.serviceId = :serviceId @@ -897,6 +928,14 @@ select obj from XXPolicyRefGroup obj where obj.groupName = :groupName + + select obj.groupName, obj.id from XXPolicyRefGroup obj where obj.policyId = :policyId + + + + DELETE FROM XXPolicyRefGroup obj WHERE obj.id IN :ids + + select obj from XXPolicyRefGroup obj where obj.groupId = :groupId and obj.policyId = :policyId @@ -1103,6 +1142,14 @@ DELETE FROM XXPolicyRefUser obj WHERE obj.id IN :ids + + SELECT obj.userName, obj.id FROM XXPolicyRefUser obj WHERE obj.policyId = :policyId + + + + DELETE FROM XXPolicyRefUser obj WHERE obj.id IN :ids + + @@ -1927,6 +1974,10 @@ select obj.name from XXRole obj + + SELECT obj.id, obj.name FROM XXRole obj WHERE obj.name IN :roleNames + + @@ -1997,6 +2048,14 @@ select obj from XXPolicyRefRole obj where obj.policyId = :policyId + + SELECT obj.roleName, obj.id FROM XXPolicyRefRole obj WHERE obj.policyId = :policyId + + + + DELETE FROM XXPolicyRefRole obj WHERE obj.id IN :ids + + select obj.id from XXPolicyRefRole obj where obj.policyId = :policyId @@ -2172,4 +2231,5 @@ select obj from XXPolicy obj where obj.zoneId = :zoneId + 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 new file mode 100644 index 00000000000..f84be0025c3 --- /dev/null +++ b/security-admin/src/test/java/org/apache/ranger/biz/TestPolicyRefUpdater.java @@ -0,0 +1,423 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ranger.biz; + +import org.apache.ranger.common.RESTErrorUtil; +import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter; +import org.apache.ranger.db.RangerDaoManager; +import org.apache.ranger.db.XXAccessTypeDefDao; +import org.apache.ranger.db.XXDataMaskTypeDefDao; +import org.apache.ranger.db.XXGroupDao; +import org.apache.ranger.db.XXPolicyConditionDefDao; +import org.apache.ranger.db.XXPolicyRefAccessTypeDao; +import org.apache.ranger.db.XXPolicyRefConditionDao; +import org.apache.ranger.db.XXPolicyRefDataMaskTypeDao; +import org.apache.ranger.db.XXPolicyRefGroupDao; +import org.apache.ranger.db.XXPolicyRefResourceDao; +import org.apache.ranger.db.XXPolicyRefRoleDao; +import org.apache.ranger.db.XXPolicyRefUserDao; +import org.apache.ranger.db.XXResourceDefDao; +import org.apache.ranger.db.XXRoleDao; +import org.apache.ranger.db.XXUserDao; +import org.apache.ranger.entity.XXPolicy; +import org.apache.ranger.entity.XXPolicyRefGroup; +import org.apache.ranger.entity.XXPolicyRefRole; +import org.apache.ranger.entity.XXPolicyRefUser; +import org.apache.ranger.entity.XXServiceDef; +import org.apache.ranger.entity.XXUser; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerPolicy.RangerDataMaskPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo; +import org.apache.ranger.plugin.model.RangerPolicy.RangerRowFilterPolicyItem; +import org.apache.ranger.plugin.model.RangerRole; +import org.apache.ranger.service.RangerAuditFields; +import org.apache.ranger.service.XGroupService; +import org.apache.ranger.view.VXGroup; +import org.apache.ranger.view.VXUser; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** +* @generated by Cursor +* @description +*/ +@RunWith(MockitoJUnitRunner.class) +public class TestPolicyRefUpdater { + @InjectMocks + PolicyRefUpdater updater; + + @Mock + RangerDaoManager daoMgr; + @Mock + RangerAuditFields rangerAuditFields; + @Mock + XUserMgr xUserMgr; + @Mock + RoleDBStore roleStore; + @Mock + RangerBizUtil rangerBizUtil; + @Mock + XGroupService xGroupService; + @Mock + RangerTransactionSynchronizationAdapter rangerTransactionSynchronizationAdapter; + @Mock + RESTErrorUtil restErrorUtil; + + @Test + public void testGetAllPolicyItemsAggregates() { + RangerPolicy p = new RangerPolicy(); + p.setPolicyItems(Arrays.asList(new RangerPolicyItem())); + p.setDenyPolicyItems(Arrays.asList(new RangerPolicyItem())); + p.setAllowExceptions(Arrays.asList(new RangerPolicyItem())); + p.setDenyExceptions(Arrays.asList(new RangerPolicyItem())); + p.setDataMaskPolicyItems(Arrays.asList(new RangerDataMaskPolicyItem())); + p.setRowFilterPolicyItems(Arrays.asList(new RangerRowFilterPolicyItem())); + List> items = PolicyRefUpdater.getAllPolicyItems(p); + Assert.assertEquals(6, items.size()); + } + + @Test + public void testCreateNewPolMappingForRefTable_NullPolicyNoop() throws Exception { + updater.createNewPolMappingForRefTable(null, null, null, false, false); + } + + @Test + public void testCreateNewPolMappingForRefTable_ValidEverything() throws Exception { + // Prepare policy with resources and items + RangerPolicy policy = new RangerPolicy(); + policy.setId(5L); + policy.setName("p"); + policy.setService("svc"); + policy.setResources(Collections.singletonMap("db", + new RangerPolicy.RangerPolicyResource(Collections.singletonList("db1"), false, false))); + RangerPolicyItem item = new RangerPolicyItem(); + item.setUsers(Arrays.asList("u1")); + item.setGroups(Arrays.asList("g1")); + item.setRoles(Arrays.asList("r1")); + RangerPolicyItemAccess acc = new RangerPolicyItemAccess(); + acc.setType("select"); + item.setAccesses(Collections.singletonList(acc)); + RangerPolicyItemCondition cond = new RangerPolicyItemCondition(); + cond.setType("time"); + item.setConditions(Collections.singletonList(cond)); + RangerDataMaskPolicyItem dmItem = new RangerDataMaskPolicyItem(); + RangerPolicyItemDataMaskInfo dm = new RangerPolicyItemDataMaskInfo(); + dm.setDataMaskType("MASK"); + dmItem.setDataMaskInfo(dm); + policy.setPolicyItems(Arrays.asList(item)); + policy.setDataMaskPolicyItems(Arrays.asList(dmItem)); + policy.setConditions(Collections.singletonList(cond)); + + XXPolicy xPolicy = new XXPolicy(); + xPolicy.setId(5L); + xPolicy.setName("p"); + xPolicy.setService(9L); + XXServiceDef xSvc = new XXServiceDef(); + xSvc.setId(9L); + + // Stubs for DAO lookups and batch create calls + XXResourceDefDao resDefDao = mock(XXResourceDefDao.class); + when(daoMgr.getXXResourceDef()).thenReturn(resDefDao); + Map xxResourceDefIdMap = new HashMap<>(); + xxResourceDefIdMap.put("db", 1L); + when(resDefDao.findResourceDefIdsByNameAndPolicyId(Mockito.anySet(), Mockito.eq(5L))).thenReturn(xxResourceDefIdMap); + Mockito.lenient().when(rangerAuditFields.populateAuditFields(Mockito.any(), Mockito.any())) + .thenAnswer(inv -> inv.getArgument(0)); + XXPolicyRefResourceDao polResDao = mock(XXPolicyRefResourceDao.class); + when(daoMgr.getXXPolicyRefResource()).thenReturn(polResDao); + XXPolicyRefRoleDao polRoleDao = mock(XXPolicyRefRoleDao.class); + when(daoMgr.getXXPolicyRefRole()).thenReturn(polRoleDao); + XXPolicyRefGroupDao polGroupDao = mock(XXPolicyRefGroupDao.class); + when(daoMgr.getXXPolicyRefGroup()).thenReturn(polGroupDao); + XXPolicyRefUserDao polUserDao = mock(XXPolicyRefUserDao.class); + when(daoMgr.getXXPolicyRefUser()).thenReturn(polUserDao); + XXAccessTypeDefDao accDefDao = mock(XXAccessTypeDefDao.class); + when(daoMgr.getXXAccessTypeDef()).thenReturn(accDefDao); + Map xAccMap = new HashMap<>(); + xAccMap.put("select", 2L); + when(accDefDao.findAccessTypeDefIdsByNamesAndServiceId(Mockito.anySet(), Mockito.eq(9L))).thenReturn(xAccMap); + XXPolicyRefAccessTypeDao polAccDao = mock(XXPolicyRefAccessTypeDao.class); + when(daoMgr.getXXPolicyRefAccessType()).thenReturn(polAccDao); + XXPolicyConditionDefDao condDefDao = mock(XXPolicyConditionDefDao.class); + when(daoMgr.getXXPolicyConditionDef()).thenReturn(condDefDao); + Map xCondMap = new HashMap<>(); + xCondMap.put("time", 3L); + when(condDefDao.findConditionDefIdsByServiceDefIdAndNames(Mockito.eq(9L), Mockito.anySet())).thenReturn(xCondMap); + XXPolicyRefConditionDao polCondDao = mock(XXPolicyRefConditionDao.class); + when(daoMgr.getXXPolicyRefCondition()).thenReturn(polCondDao); + XXDataMaskTypeDefDao dmDefDao = mock(XXDataMaskTypeDefDao.class); + when(daoMgr.getXXDataMaskTypeDef()).thenReturn(dmDefDao); + Map xxDataMaskTypeDefIdMap = new HashMap<>(); + xxDataMaskTypeDefIdMap.put("MASK", 4L); + when(dmDefDao.findDataMaskTypeDefIdsByNamesAndServiceId(Mockito.anySet(), Mockito.eq(9L))).thenReturn(xxDataMaskTypeDefIdMap); + XXPolicyRefDataMaskTypeDao polDmDao = mock(XXPolicyRefDataMaskTypeDao.class); + when(daoMgr.getXXPolicyRefDataMaskType()).thenReturn(polDmDao); + when(rangerBizUtil.checkAdminAccess()).thenReturn(true); + + 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); + + XXUserDao userDao = mock(XXUserDao.class); + when(daoMgr.getXXUser()).thenReturn(userDao); + when(userDao.getIdsByUserNames(Mockito.anySet())).thenReturn(Collections.singletonMap("u1", 30L)); + + XXGroupDao groupDao = mock(XXGroupDao.class); + when(daoMgr.getXXGroup()).thenReturn(groupDao); + when(groupDao.getIdsByGroupNames(Mockito.anySet())).thenReturn(Collections.singletonMap("g1", 20L)); + + XXRoleDao roleDao = mock(XXRoleDao.class); + when(daoMgr.getXXRole()).thenReturn(roleDao); + when(roleDao.getIdsByRoleNames(Mockito.anySet())).thenReturn(Collections.singletonMap("r1", 10L)); + + updater.createNewPolMappingForRefTable(policy, xPolicy, xSvc, true, false); + // no exceptions indicates success across branches + } + + @Test + public void testCreateNewPolMappingForRefTable_InvalidResourceDef() throws Exception { + RangerPolicy policy = new RangerPolicy(); + policy.setId(6L); + policy.setName("p2"); + policy.setService("svc"); + policy.setResources(Collections.singletonMap("invalid", + new RangerPolicy.RangerPolicyResource(Collections.singletonList("v"), false, false))); + XXPolicy xPolicy = new XXPolicy(); + xPolicy.setId(6L); + XXServiceDef xSvc = new XXServiceDef(); + xSvc.setId(9L); + XXResourceDefDao resDefDao = mock(XXResourceDefDao.class); + when(daoMgr.getXXResourceDef()).thenReturn(resDefDao); + when(resDefDao.findResourceDefIdsByNameAndPolicyId(Mockito.anySet(), Mockito.eq(6L))).thenReturn(Collections.emptyMap()); + try { + updater.createNewPolMappingForRefTable(policy, xPolicy, xSvc, false, false); + Assert.fail("Expected exception"); + } catch (Exception expected) { + // expected + } + } + + @Test + public void testCleanupRefTablesForUpdate_SelectivePrincipalCleanup() { + final Long policyId = 100L; + + Set policyUsers = new HashSet<>(Arrays.asList("alice", "bob", "carol")); + Set policyRoles = new HashSet<>(Arrays.asList("roleA", "roleB", "roleNew")); + Set policyGroups = new 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); + + XXPolicyRefUserDao userDao = mock(XXPolicyRefUserDao.class); + XXPolicyRefRoleDao roleDao = mock(XXPolicyRefRoleDao.class); + XXPolicyRefGroupDao groupDao = mock(XXPolicyRefGroupDao.class); + XXPolicyRefResourceDao resourceDao = mock(XXPolicyRefResourceDao.class); + XXPolicyRefAccessTypeDao accessDao = mock(XXPolicyRefAccessTypeDao.class); + XXPolicyRefConditionDao conditionDao = mock(XXPolicyRefConditionDao.class); + XXPolicyRefDataMaskTypeDao dataMaskDao = mock(XXPolicyRefDataMaskTypeDao.class); + + when(daoMgr.getXXPolicyRefUser()).thenReturn(userDao); + when(daoMgr.getXXPolicyRefRole()).thenReturn(roleDao); + when(daoMgr.getXXPolicyRefGroup()).thenReturn(groupDao); + when(daoMgr.getXXPolicyRefResource()).thenReturn(resourceDao); + when(daoMgr.getXXPolicyRefAccessType()).thenReturn(accessDao); + when(daoMgr.getXXPolicyRefCondition()).thenReturn(conditionDao); + when(daoMgr.getXXPolicyRefDataMaskType()).thenReturn(dataMaskDao); + + when(userDao.findUserNameIdByPolicyId(policyId)).thenReturn(existingUsers); + when(roleDao.findRoleNameIdByPolicyId(policyId)).thenReturn(existingRoles); + when(groupDao.findGroupNameByPolicyId(policyId)).thenReturn(existingGroups); + + Assert.assertTrue(updater.cleanupRefTablesForUpdate(policyId, policyUsers, policyRoles, policyGroups)); + + verify(userDao).deletePolicyRefUserByIds(Collections.singletonList(4L)); + Assert.assertEquals(Collections.singleton("carol"), policyUsers); + + verify(roleDao).deletePolicyRefRoleByIds(Collections.singletonList(12L)); + Assert.assertEquals(new HashSet<>(Arrays.asList("roleB", "roleNew")), policyRoles); + + verify(groupDao).deletePolicyRefGroupByIds(Collections.singletonList(22L)); + Assert.assertEquals(new HashSet<>(Arrays.asList("grp2", "grpNew")), policyGroups); + + verify(resourceDao).deleteByPolicyId(policyId); + verify(accessDao).deleteByPolicyId(policyId); + verify(conditionDao).deleteByPolicyId(policyId); + verify(dataMaskDao).deleteByPolicyId(policyId); + + verify(userDao, never()).deleteByPolicyId(policyId); + verify(roleDao, never()).deleteByPolicyId(policyId); + verify(groupDao, never()).deleteByPolicyId(policyId); + } + + @Test + public void testCleanupRefTables() { + when(daoMgr.getXXPolicyRefResource()).thenReturn(mock(XXPolicyRefResourceDao.class)); + when(daoMgr.getXXPolicyRefRole()).thenReturn(mock(XXPolicyRefRoleDao.class)); + when(daoMgr.getXXPolicyRefGroup()).thenReturn(mock(XXPolicyRefGroupDao.class)); + when(daoMgr.getXXPolicyRefUser()).thenReturn(mock(XXPolicyRefUserDao.class)); + when(daoMgr.getXXPolicyRefAccessType()).thenReturn(mock(XXPolicyRefAccessTypeDao.class)); + when(daoMgr.getXXPolicyRefCondition()).thenReturn(mock(XXPolicyRefConditionDao.class)); + when(daoMgr.getXXPolicyRefDataMaskType()).thenReturn(mock(XXPolicyRefDataMaskTypeDao.class)); + + RangerPolicy p = new RangerPolicy(); + p.setId(77L); + Assert.assertEquals(true, updater.cleanupRefTables(p)); + Assert.assertEquals(false, updater.cleanupRefTables(null)); + } + + @Test + public void testCreatePrincipal_User_Group_Role_Paths() throws Exception { + // Common setup: policy and xPolicy for audit fields + XXPolicy xPolicy = new XXPolicy(); + 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)); + + // USER path: user not found, xUserMgr creates, then XXUser lookup returns id + XXUserDao userDao = mock(XXUserDao.class); + when(daoMgr.getXXUser()).thenReturn(userDao); + when(userDao.findByUserName("uNew")).thenReturn(null).thenReturn(new XXUser() { + { + setId(11L); + } + }); + VXUser createdVX = new VXUser(); + when(xUserMgr.createServiceConfigUser("uNew")).thenReturn(createdVX); + XXPolicyRefUserDao polUserDao = mock(XXPolicyRefUserDao.class); + when(daoMgr.getXXPolicyRefUser()).thenReturn(polUserDao); + + // Reflectively construct inner class PolicyUserAssociator for USER + Class userAssociatorClass = null; + for (Class c : PolicyRefUpdater.class.getDeclaredClasses()) { + if (c.getSimpleName().equals("PolicyUserAssociator")) { + userAssociatorClass = c; + break; + } + } + Assert.assertNotNull(userAssociatorClass); + Constructor userCtor = userAssociatorClass.getDeclaredConstructor( + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + userCtor.setAccessible(true); + Object associatorUser = userCtor.newInstance(updater, "uNew", null, xPolicy); + Method runUser = userAssociatorClass.getDeclaredMethod("run"); + runUser.setAccessible(true); + runUser.invoke(associatorUser); + verify(daoMgr.getXXPolicyRefUser(), Mockito.times(1)) + .create(Mockito.any(XXPolicyRefUser.class)); + + // GROUP path: group not found, xGroupService creates and logs, verify ref + // created + XXGroupDao groupDao = mock(XXGroupDao.class); + when(daoMgr.getXXGroup()).thenReturn(groupDao); + when(groupDao.findByGroupName("gNew")).thenReturn(null); + VXGroup vXGroup = new VXGroup(); + vXGroup.setId(22L); + when(xGroupService.createXGroupWithOutLogin(Mockito.any(VXGroup.class))).thenReturn(vXGroup); + XXPolicyRefGroupDao polGroupDao = mock(XXPolicyRefGroupDao.class); + when(daoMgr.getXXPolicyRefGroup()).thenReturn(polGroupDao); + + Class groupAssociatorClass = null; + for (Class c : PolicyRefUpdater.class.getDeclaredClasses()) { + if (c.getSimpleName().equals("PolicyGroupAssociator")) { + groupAssociatorClass = c; + break; + } + } + Assert.assertNotNull(groupAssociatorClass); + Constructor groupCtor = groupAssociatorClass.getDeclaredConstructor( + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + groupCtor.setAccessible(true); + Object associatorGroup = groupCtor.newInstance(updater, "gNew", null, xPolicy); + Method runGroup = groupAssociatorClass.getDeclaredMethod("run"); + runGroup.setAccessible(true); + runGroup.invoke(associatorGroup); + verify(daoMgr.getXXPolicyRefGroup(), Mockito.times(1)) + .create(Mockito.any(XXPolicyRefGroup.class)); + + // ROLE path: role not found, roleStore.createRole returns id, verify ref + // created + XXRoleDao roleDao = mock(XXRoleDao.class); + when(daoMgr.getXXRole()).thenReturn(roleDao); + 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); + XXPolicyRefRoleDao polRoleDao = mock(XXPolicyRefRoleDao.class); + when(daoMgr.getXXPolicyRefRole()).thenReturn(polRoleDao); + + Class roleAssociatorClass = null; + for (Class c : PolicyRefUpdater.class.getDeclaredClasses()) { + if (c.getSimpleName().equals("PolicyRoleAssociator")) { + roleAssociatorClass = c; + break; + } + } + Assert.assertNotNull(roleAssociatorClass); + Constructor roleCtor = roleAssociatorClass.getDeclaredConstructor( + PolicyRefUpdater.class, String.class, Long.class, XXPolicy.class); + roleCtor.setAccessible(true); + Object associatorRole = roleCtor.newInstance(updater, "rNew", null, xPolicy); + Method runRole = roleAssociatorClass.getDeclaredMethod("run"); + runRole.setAccessible(true); + runRole.invoke(associatorRole); + verify(daoMgr.getXXPolicyRefRole(), Mockito.times(1)).create(Mockito.any(XXPolicyRefRole.class)); + } +} diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java index 9238122f5a0..434a64ee797 100644 --- a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java +++ b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java @@ -1688,7 +1688,7 @@ public void test26createPolicy() throws Exception { Mockito.when(daoManager.getXXPolicy()).thenReturn(xPolicyDao); Mockito.when(xPolicyDao.getById(Id)).thenReturn(xPolicy); - Mockito.doNothing().when(policyRefUpdater).createNewPolMappingForRefTable(rangerPolicy, xPolicy, xServiceDef, false); + Mockito.doNothing().when(policyRefUpdater).createNewPolMappingForRefTable(rangerPolicy, xPolicy, xServiceDef, false, false); Mockito.when(policyService.getPopulatedViewObject(xPolicy)).thenReturn(rangerPolicy); Mockito.when(daoManager.getXXService()).thenReturn(xServiceDao); @@ -1835,10 +1835,11 @@ public void tess28updatePolicy() throws Exception { Mockito.when(factory.createPolicyResourceSignature(rangerPolicy)) .thenReturn(signature); Mockito.when(!bizUtil.hasAccess(xService, null)).thenReturn(true); - Mockito.when(policyRefUpdater.cleanupRefTables(rangerPolicy)).thenReturn(true); - + Mockito.doNothing().when(policyRefUpdater).createNewPolMappingForRefTable( + Mockito.eq(rangerPolicy), Mockito.eq(xPolicy), Mockito.eq(xServiceDef), + Mockito.anyBoolean(), Mockito.eq(true)); - RangerPolicy dbRangerPolicy = serviceDBStore.updatePolicy(rangerPolicy); + RangerPolicy dbRangerPolicy = serviceDBStore.updatePolicy(rangerPolicy); Assert.assertNotNull(dbRangerPolicy); Assert.assertEquals(dbRangerPolicy, rangerPolicy); Assert.assertEquals(dbRangerPolicy.getId(), rangerPolicy.getId());