diff --git a/security-admin/src/main/java/org/apache/ranger/patch/PatchForAtlasPolicyUpdateForEntityRead_J10064.java b/security-admin/src/main/java/org/apache/ranger/patch/PatchForAtlasPolicyUpdateForEntityRead_J10064.java index fe20dbbb4e..b78a659f1d 100644 --- a/security-admin/src/main/java/org/apache/ranger/patch/PatchForAtlasPolicyUpdateForEntityRead_J10064.java +++ b/security-admin/src/main/java/org/apache/ranger/patch/PatchForAtlasPolicyUpdateForEntityRead_J10064.java @@ -17,6 +17,7 @@ package org.apache.ranger.patch; +import org.apache.commons.collections.CollectionUtils; import org.apache.ranger.biz.ServiceDBStore; import org.apache.ranger.db.RangerDaoManager; import org.apache.ranger.entity.XXPolicy; @@ -24,27 +25,41 @@ import org.apache.ranger.entity.XXServiceDef; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil; +import org.apache.ranger.rest.ServiceRESTUtil; import org.apache.ranger.util.CLIUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; +import java.util.stream.Collectors; @Component public class PatchForAtlasPolicyUpdateForEntityRead_J10064 extends org.apache.ranger.patch.BaseLoader { private static final Logger logger = LoggerFactory.getLogger(PatchForAtlasPolicyUpdateForEntityRead_J10064.class); - private static final String RESOURCE_ENTITY_TYPE = "entity-type"; private static final String ENTITY_READ = "entity-read"; + + private static final String RESOURCE_ENTITY_TYPE = "entity-type"; private static final String RESOURCE_ENTITY_LABEL = "entity-label"; private static final String RESOURCE_ENTITY_BUSINESS_METADATA = "entity-business-metadata"; + private static final String POLICY_NAME_ENTITY_BASE = "all - entity-type, entity-classification, entity"; + private static final String POLICY_NAME_ENTITY_CLASSIFICATION = "all - entity-type, entity-classification, entity, classification"; + + private static final List ATLAS_RESOURCE_ENTITY = new ArrayList<>(Arrays.asList("entity-type", "entity-classification", "entity")); + private static final List CLASSIFICATION_ACCESS_TYPES = new ArrayList<>(Arrays.asList("entity-remove-classification", "entity-add-classification", "entity-update-classification")); + @Autowired RangerDaoManager daoMgr; @@ -88,7 +103,7 @@ public void execLoad() { logger.info("==> PatchForAtlasPolicyUpdateForEntityRead_J10064.execLoad()"); try { - updateAtlasPolicyForEntityReadAccessType(); + updateAtlasPolicyForAccessType(); } catch (Exception e) { throw new RuntimeException("Error while updating " + EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_ATLAS_NAME + " service-def", e); } @@ -96,18 +111,13 @@ public void execLoad() { logger.info("<== PatchForAtlasPolicyUpdateForEntityRead_J10064.execLoad()"); } - private boolean removeIfEntityReadPermissionExist(RangerPolicyItem item) { - return item.getAccesses().removeIf(itemAccess -> itemAccess.getType().equals(ENTITY_READ)); - } - - private void updateAtlasPolicyForEntityReadAccessType() throws Exception { - logger.info("==> updateAtlasPolicyForEntityReadAccessType() "); + private void updateAtlasPolicyForAccessType() throws Exception { + logger.info("==> updateAtlasPolicyForAccessType()"); XXServiceDef xXServiceDefObj = daoMgr.getXXServiceDef().findByName(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_ATLAS_NAME); if (xXServiceDefObj == null) { - logger.debug("ServiceDef not found with name :{}", EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_ATLAS_NAME); - + logger.debug("ServiceDef not found with name: {}", EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_ATLAS_NAME); return; } @@ -117,39 +127,164 @@ private void updateAtlasPolicyForEntityReadAccessType() throws Exception { for (XXService xxService : xxServices) { List xxPolicies = daoMgr.getXXPolicy().findByServiceId(xxService.getId()); + List defaultEntityReadItems = new ArrayList<>(); + List defaultClassificationItems = new ArrayList<>(); + for (XXPolicy xxPolicy : xxPolicies) { RangerPolicy rPolicy = svcDBStore.getPolicy(xxPolicy.getId()); - final Map policyResources = rPolicy.getResources(); - final boolean isNonEntityResourceType = policyResources.containsKey(RESOURCE_ENTITY_LABEL) - || policyResources.containsKey(RESOURCE_ENTITY_BUSINESS_METADATA); - boolean isUpdated = false; - - if (policyResources.containsKey(RESOURCE_ENTITY_TYPE) && isNonEntityResourceType) { - List policyItems = rPolicy.getPolicyItems(); - if (policyItems != null) { - Iterator itemIterator = policyItems.iterator(); - while (itemIterator.hasNext()) { - RangerPolicyItem item = itemIterator.next(); - if (removeIfEntityReadPermissionExist(item)) { - if (item.getAccesses().isEmpty()) { - itemIterator.remove(); - logger.debug("Removing empty policy item from policy ID: {}", rPolicy.getId()); - } - isUpdated = true; - } - } - } - } + boolean isUpdated = processPolicyForAccessUpdate(rPolicy, defaultEntityReadItems, defaultClassificationItems); if (isUpdated) { svcDBStore.updatePolicy(rPolicy); - logger.info("PatchForAtlasPolicyUpdateForEntityRead_J10064: updated policy (id={}, name={}) to remove {} permission", - rPolicy.getId(), rPolicy.getName(), ENTITY_READ); + logger.info("PatchForAtlasPolicyUpdateForEntityRead_J10064: updated policy (id={}, name={}) for service {} to remove/filter permissions", + rPolicy.getId(), rPolicy.getName(), xxService.getName()); } } + + applyAggregatedDefaultPolicyUpdate(POLICY_NAME_ENTITY_BASE, defaultEntityReadItems, xxService); + applyAggregatedDefaultPolicyUpdate(POLICY_NAME_ENTITY_CLASSIFICATION, defaultClassificationItems, xxService); + } + + logger.info("<== updateAtlasPolicyForAccessType()"); + } + + private boolean processPolicyForAccessUpdate(RangerPolicy rPolicy, List entityReadDefaults, List classificationDefaults) { + final Map policyResources = rPolicy.getResources(); + + if (policyResources == null) { + return false; + } + + final boolean isNonEntityResourceType = policyResources.containsKey(RESOURCE_ENTITY_TYPE) && + (policyResources.containsKey(RESOURCE_ENTITY_LABEL) || policyResources.containsKey(RESOURCE_ENTITY_BUSINESS_METADATA)); + + if (isNonEntityResourceType) { + return removeEntityReadAccess(rPolicy, entityReadDefaults); + } + + if (isEntityResource(policyResources)) { + return filterClassificationAccess(rPolicy, classificationDefaults); + } + + return false; + } + + private boolean isEntityResource(Map policyResources) { + if (policyResources == null || policyResources.size() != ATLAS_RESOURCE_ENTITY.size()) { + return false; + } + + return policyResources.keySet().containsAll(ATLAS_RESOURCE_ENTITY); + } + + private boolean removeEntityReadAccess(RangerPolicy rPolicy, List defaultEntityReadItems) { + List policyItems = rPolicy.getPolicyItems(); + if (CollectionUtils.isEmpty(policyItems)) { + return false; } - logger.info("<== updateAtlasPolicyForEntityReadAccessType() "); + boolean isUpdated = false; + Iterator itemIterator = policyItems.iterator(); + while (itemIterator.hasNext()) { + RangerPolicyItem item = itemIterator.next(); + + boolean wasAccessRemoved = item.getAccesses().removeIf(itemAccess -> ENTITY_READ.equals(itemAccess.getType())); + + if (wasAccessRemoved) { + isUpdated = true; + + RangerPolicyItem policyItemForentityRead = new RangerPolicyItem(); + policyItemForentityRead.setUsers(item.getUsers()); + policyItemForentityRead.setGroups(item.getGroups()); + policyItemForentityRead.setRoles(item.getRoles()); + policyItemForentityRead.setAccesses(Collections.singletonList(new RangerPolicyItemAccess(ENTITY_READ))); + policyItemForentityRead.setDelegateAdmin(item.getDelegateAdmin()); + + if (!defaultEntityReadItems.contains(policyItemForentityRead)) { + defaultEntityReadItems.add(policyItemForentityRead); + } + + if (item.getAccesses().isEmpty()) { + itemIterator.remove(); + logger.debug("Removing empty policy item from policy ID: {}", rPolicy.getId()); + } + } + } + return isUpdated; + } + + private boolean filterClassificationAccess(RangerPolicy policy, List defaultClassificationItems) { + List policyItems = policy.getPolicyItems(); + if (CollectionUtils.isEmpty(policyItems)) { + return false; + } + + boolean isUpdated = false; + ListIterator policyItemIterator = policyItems.listIterator(); + + while (policyItemIterator.hasNext()) { + RangerPolicyItem policyItem = policyItemIterator.next(); + List accesses = policyItem.getAccesses(); + + if (CollectionUtils.isNotEmpty(accesses)) { + List accessesToRemove = accesses.stream() + .filter(access -> CLASSIFICATION_ACCESS_TYPES.contains(access.getType())).collect(Collectors.toList()); + + boolean removed = accesses.removeAll(accessesToRemove); + + if (removed) { + isUpdated = true; + + RangerPolicyItem policyItemForClassification = new RangerPolicyItem(); + policyItemForClassification.setUsers(policyItem.getUsers()); + policyItemForClassification.setGroups(policyItem.getGroups()); + policyItemForClassification.setRoles(policyItem.getRoles()); + policyItemForClassification.setAccesses(accessesToRemove); + policyItemForClassification.setDelegateAdmin(policyItem.getDelegateAdmin()); + + if (!defaultClassificationItems.contains(policyItemForClassification)) { + defaultClassificationItems.add(policyItemForClassification); + } + } + + // Remove the policy item if all accesses were filtered out + if (accesses.isEmpty()) { + policyItemIterator.remove(); + logger.debug("Removing empty policy item from policy ID: {}", policy.getId()); + } + } + } + + return isUpdated; + } + + private void applyAggregatedDefaultPolicyUpdate(String policyName, List itemsToAdd, XXService service) { + if (CollectionUtils.isEmpty(itemsToAdd)) { + return; + } + + try { + XXPolicy xxPolicy = daoMgr.getXXPolicy().findByNameAndServiceId(policyName, service.getId()); + + if (xxPolicy == null) { + return; + } + + RangerPolicy existingPolicy = svcDBStore.getPolicy(xxPolicy.getId()); + + RangerPolicy appliedPolicy = new RangerPolicy(); + appliedPolicy.setPolicyItems(itemsToAdd); + + // Merge itemsToAdd into the existingPolicy + ServiceRESTUtil.mergeExactMatchPolicyForResource(existingPolicy, appliedPolicy); + + svcDBStore.updatePolicy(existingPolicy); + + logger.info("Successfully Added {} policy-items to default policy (id={}, name={}) for service {}", + itemsToAdd.size(), existingPolicy.getId(), existingPolicy.getName(), service.getName()); + } catch (Exception e) { + logger.error("Error updating default policy '{}' for service {}", policyName, service.getName(), e); + } } }