From 37740b2e9170f8828cf10a6bcbbb9b92002bead6 Mon Sep 17 00:00:00 2001 From: Nikhil P Bonte Date: Tue, 9 Jan 2024 19:01:19 +0530 Subject: [PATCH 1/2] Use entity Authorizer evaluator --- .../org/apache/atlas/authorizer/RelationshipAuthorizer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java b/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java index 33a75c4969..5954330bd9 100644 --- a/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java +++ b/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java @@ -24,6 +24,7 @@ import static org.apache.atlas.authorizer.AuthorizerCommon.POLICY_TYPE_ALLOW; import static org.apache.atlas.authorizer.AuthorizerCommon.arrayListContains; import static org.apache.atlas.authorizer.AuthorizerCommon.getMap; +import static org.apache.atlas.authorizer.EntityAuthorizer.validateFilterCriteriaWithEntity; import static org.apache.atlas.authorizer.ListAuthorizer.getDSLForResources; import static org.apache.atlas.model.TypeCategory.ARRAY; import static org.apache.atlas.repository.Constants.QUALIFIED_NAME; @@ -247,7 +248,7 @@ private static boolean validateResourcesForCreateRelationship(List return false; } - public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntity entity) { + /*public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntity entity) { AtlasPerfMetrics.MetricRecorder recorder = RequestContext.get().startMetricRecord("RelationshipAuthorizer.validateFilterCriteriaWithEntity"); String condition = data.get("condition").asText(); @@ -365,7 +366,7 @@ public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntit RequestContext.get().endMetricRecord(recorder); return result; - } + }*/ public static boolean isRelationshipAccessAllowed(String action, String endOneGuid, String endTwoGuid) throws AtlasBaseException { AtlasPerfMetrics.MetricRecorder recorder = RequestContext.get().startMetricRecord("RelationshipAuthorizer.isRelationshipAccessAllowed"); From 4d642b87a47c751ba1451de0d9d75aa8695b46d7 Mon Sep 17 00:00:00 2001 From: Nikhil P Bonte Date: Wed, 10 Jan 2024 15:24:50 +0530 Subject: [PATCH 2/2] Generic support to internal attributes for abac policies inMem evaluation --- .../atlas/authorizer/EntityAuthorizer.java | 108 +++++++----------- .../authorizer/JsonToElasticsearchQuery.java | 64 +++++++---- .../authorizer/RelationshipAuthorizer.java | 10 +- .../store/graph/v2/AtlasEntityStoreV2.java | 1 + 4 files changed, 94 insertions(+), 89 deletions(-) diff --git a/repository/src/main/java/org/apache/atlas/authorizer/EntityAuthorizer.java b/repository/src/main/java/org/apache/atlas/authorizer/EntityAuthorizer.java index 959f3ab3b2..a78f648217 100644 --- a/repository/src/main/java/org/apache/atlas/authorizer/EntityAuthorizer.java +++ b/repository/src/main/java/org/apache/atlas/authorizer/EntityAuthorizer.java @@ -14,7 +14,9 @@ import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasRelatedObjectId; import org.apache.atlas.plugin.model.RangerPolicy; +import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.repository.graphdb.janus.AtlasElasticsearchQuery; +import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2; import org.apache.atlas.type.*; import org.apache.atlas.utils.AtlasPerfMetrics; import org.apache.commons.collections.CollectionUtils; @@ -22,6 +24,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @@ -58,6 +62,8 @@ public static boolean isAccessAllowedInMemory(AtlasEntity entity, String action, filterCriteriaList.add(filterCriteria); } } + AtlasVertex vertex = AtlasGraphUtilsV2.findByGuid(entity.getGuid()); + ObjectMapper mapper = new ObjectMapper(); boolean ret = false; boolean eval; @@ -71,7 +77,7 @@ public static boolean isAccessAllowedInMemory(AtlasEntity entity, String action, } if (filterCriteriaNode != null && filterCriteriaNode.get("entity") != null) { JsonNode entityFilterCriteriaNode = filterCriteriaNode.get("entity"); - eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, entity); + eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, entity, vertex); } ret = ret || eval; if (ret) { @@ -193,7 +199,7 @@ private static boolean validateResourcesForCreateEntityInMemory(List assetTypes = AuthorizerCommon.getTypeAndSupertypesList(entity.getTypeName()); - for (JsonNode crit : criterion) { result = true; @@ -214,9 +218,9 @@ public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntit boolean evaluation = false; if (crit.has("condition")) { - evaluation = validateFilterCriteriaWithEntity(crit, entity); + evaluation = validateFilterCriteriaWithEntity(crit, entity, vertex); } else { - evaluation = evaluateFilterCriteria(crit, entity, assetTypes); + evaluation = evaluateFilterCriteria(crit, entity, vertex); } if (condition.equals("AND")) { @@ -234,25 +238,10 @@ public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntit return result; } - private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity, Set assetTypes) { + private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity, AtlasVertex vertex) { AtlasPerfMetrics.MetricRecorder recorder = RequestContext.get().startMetricRecord("evaluateFilterCriteria"); - String operator = crit.get("operator").asText(); - String attributeName = crit.get("attributeName").asText(); - String attributeValue = crit.get("attributeValue").asText(); -// List attributeValues = new ArrayList<>(); -// if (operator.equals("IN") || operator.equals("NOT_IN")) { -// for (JsonNode valueNode : crit.get("attributeValue")) { -// ObjectMapper mapper = new ObjectMapper(); -// String value = null; -// try { -// value = mapper.treeToValue(valueNode, String.class); -// } catch (JsonProcessingException e) { -// e.printStackTrace(); -// } -// attributeValues.add(value); -// } -// } + String attributeName = crit.get("attributeName").asText(); if (attributeName.endsWith(".text")) { attributeName = attributeName.replace(".text", ""); @@ -263,63 +252,46 @@ private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity, List entityAttributeValues = new ArrayList<>(); switch (attributeName) { - case "__superTypeNames": - entityAttributeValues.addAll(assetTypes); - - break; - case "__typeName": - entityAttributeValues.add(entity.getTypeName()); - - break; - case "__guid": - entityAttributeValues.add(entity.getGuid()); - - break; case "__traitNames": - List atlasClassifications = entity.getClassifications(); - if (atlasClassifications != null && !atlasClassifications.isEmpty()) { - for (AtlasClassification atlasClassification : atlasClassifications) { - entityAttributeValues.add(atlasClassification.getTypeName()); + List tags = entity.getClassifications(); + if (tags != null) { + for (AtlasClassification tag: tags) { + if (tag.getEntityGuid().isEmpty() || tag.getEntityGuid().equals(entity.getGuid())) { + entityAttributeValues.add(tag.getTypeName()); + } } } break; - case "__meanings": - List atlasMeanings = (List) entity.getRelationshipAttribute("meanings"); - if (CollectionUtils.isNotEmpty(atlasMeanings)) { - for (AtlasObjectId atlasMeaning : atlasMeanings) { - entityAttributeValues.add((String) atlasMeaning.getUniqueAttributes().get(QUALIFIED_NAME)); + + case "__propagatedTraitNames": + tags = entity.getClassifications(); + if (tags != null) { + for (AtlasClassification tag: tags) { + if (!tag.getEntityGuid().isEmpty() && !tag.getEntityGuid().equals(entity.getGuid())) { + entityAttributeValues.add(tag.getTypeName()); + } } } break; - /*case "__meaningNames": - atlasMeanings = entity.getMeanings(); - for (AtlasTermAssignmentHeader atlasMeaning : atlasMeanings) { - entityAttributeValues.add(atlasMeaning.getDisplayText()); - } - break;*/ - default: - String typeName = entity.getTypeName(); - boolean isArrayOfPrimitiveType = false; - boolean isArrayOfEnum = false; - AtlasEntityType entityType = AuthorizerCommon.getEntityTypeByName(typeName); - AtlasStructType.AtlasAttribute atlasAttribute = entityType.getAttribute(attributeName); - if (atlasAttribute != null && atlasAttribute.getAttributeType().getTypeCategory().equals(ARRAY)) { - AtlasArrayType attributeType = (AtlasArrayType) atlasAttribute.getAttributeType(); - AtlasType elementType = attributeType.getElementType(); - isArrayOfPrimitiveType = elementType.getTypeCategory().equals(TypeCategory.PRIMITIVE); - isArrayOfEnum = elementType.getTypeCategory().equals(TypeCategory.ENUM); - } - if (entity.getAttribute(attributeName) != null) { - if (isArrayOfEnum || isArrayOfPrimitiveType) { + default: + Object attrValue = entity.getAttribute(attributeName); + if (attrValue != null) { + if (attrValue instanceof Collection) { entityAttributeValues.addAll((Collection) entity.getAttribute(attributeName)); } else { entityAttributeValues.add((String) entity.getAttribute(attributeName)); } + } else { + // try fetching from vertex + Collection attrValues = vertex.getPropertyValues(attributeName, String.class); + entityAttributeValues.addAll(attrValues); } - break; } + String operator = crit.get("operator").asText(); + String attributeValue = crit.get("attributeValue").asText(); + switch (operator) { case "EQUALS": if (entityAttributeValues.contains(attributeValue)) { @@ -346,6 +318,12 @@ private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity, return true; } break; +/* + case "IN": + break; + case "NOT_IN": + break; +*/ default: LOG.warn("Found unknown operator {}", operator); } diff --git a/repository/src/main/java/org/apache/atlas/authorizer/JsonToElasticsearchQuery.java b/repository/src/main/java/org/apache/atlas/authorizer/JsonToElasticsearchQuery.java index 6ee7f0b363..c26ee4a0cb 100644 --- a/repository/src/main/java/org/apache/atlas/authorizer/JsonToElasticsearchQuery.java +++ b/repository/src/main/java/org/apache/atlas/authorizer/JsonToElasticsearchQuery.java @@ -2,17 +2,24 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.atlas.RequestContext; import org.apache.atlas.utils.AtlasPerfMetrics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class JsonToElasticsearchQuery { + private static final Logger LOG = LoggerFactory.getLogger(JsonToElasticsearchQuery.class); - public static JsonNode convertConditionToQuery(String condition, JsonNode criterion, ObjectMapper mapper) { + private static JsonNode convertConditionToQuery(String condition, JsonNode criterion, ObjectMapper mapper) { if (condition.equals("AND")) { return mapper.createObjectNode().set("bool", mapper.createObjectNode().set("filter", mapper.createArrayNode())); } else if (condition.equals("OR")) { - JsonNode node = mapper.createObjectNode().set("bool", mapper.createObjectNode()); - return mapper.createObjectNode().set("bool", mapper.createObjectNode().set("should", mapper.createArrayNode())); + //JsonNode node = mapper.createObjectNode().set("bool", mapper.createObjectNode()); + return mapper.createObjectNode() + .set("bool", mapper.createObjectNode() + .set("should", mapper.createArrayNode())); } else { throw new IllegalArgumentException("Unsupported condition: " + condition); } @@ -38,26 +45,39 @@ public static JsonNode convertJsonToQuery(JsonNode data, ObjectMapper mapper) { String attributeName = crit.get("attributeName").asText(); String attributeValue = crit.get("attributeValue").asText(); - if (operator.equals("EQUALS")) { - com.fasterxml.jackson.databind.node.ObjectNode termNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - termNode.putObject("term").put(attributeName, attributeValue); - } else if (operator.equals("NOT_EQUALS")) { - com.fasterxml.jackson.databind.node.ObjectNode termNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - termNode.putObject("bool").putObject("must_not").putObject("term").put(attributeName, attributeValue); - } else if (operator.equals("STARTS_WITH")) { - com.fasterxml.jackson.databind.node.ObjectNode wildcardNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - wildcardNode.putObject("wildcard").put(attributeName, attributeValue + "*"); - } else if (operator.equals("ENDS_WITH")) { - com.fasterxml.jackson.databind.node.ObjectNode wildcardNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - wildcardNode.putObject("wildcard").put(attributeName, "*" + attributeValue); - } else if (operator.equals("IN")) { - com.fasterxml.jackson.databind.node.ObjectNode termsNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - termsNode.putObject("terms").set(attributeName, crit.get("attributeValue")); - } else if (operator.equals("NOT_IN")) { - com.fasterxml.jackson.databind.node.ObjectNode termsNode = ((com.fasterxml.jackson.databind.node.ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); - termsNode.putObject("bool").putObject("must_not").putObject("terms").put(attributeName, crit.get("attributeValue")); - } + switch (operator) { + case "EQUALS": + ObjectNode termNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + termNode.putObject("term").put(attributeName, attributeValue); + break; + + case "NOT_EQUALS": + termNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + termNode.putObject("bool").putObject("must_not").putObject("term").put(attributeName, attributeValue); + break; + + case "STARTS_WITH": + ObjectNode wildcardNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + wildcardNode.putObject("wildcard").put(attributeName, attributeValue + "*"); + break; + + case "ENDS_WITH": + wildcardNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + wildcardNode.putObject("wildcard").put(attributeName, "*" + attributeValue); + break; + case "IN": + ObjectNode termsNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + termsNode.putObject("terms").set(attributeName, crit.get("attributeValue")); + break; + + case "NOT_IN": + termsNode = ((ArrayNode) query.get("bool").get(condition.equals("AND") ? "filter" : "should")).addObject(); + termsNode.putObject("bool").putObject("must_not").putObject("terms").put(attributeName, crit.get("attributeValue")); + break; + + default: LOG.warn("Found unknown operator {}", operator); + } } } RequestContext.get().endMetricRecord(convertJsonToQueryMetrics); diff --git a/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java b/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java index 5954330bd9..416e6b093a 100644 --- a/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java +++ b/repository/src/main/java/org/apache/atlas/authorizer/RelationshipAuthorizer.java @@ -11,7 +11,9 @@ import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntityHeader; import org.apache.atlas.plugin.model.RangerPolicy; +import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.repository.graphdb.janus.AtlasElasticsearchQuery; +import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2; import org.apache.atlas.type.*; import org.apache.atlas.utils.AtlasPerfMetrics; import org.elasticsearch.client.RestClient; @@ -59,6 +61,10 @@ public static boolean checkRelationshipAccessAllowedInMemory(String action, Stri ObjectMapper mapper = new ObjectMapper(); boolean ret = false; boolean eval; + + AtlasVertex oneVertex = AtlasGraphUtilsV2.findByGuid(endOneEntity.getGuid()); + AtlasVertex twoVertex = AtlasGraphUtilsV2.findByGuid(endTwoEntity.getGuid()); + for (String filterCriteria: filterCriteriaList) { eval = false; JsonNode filterCriteriaNode = null; @@ -69,11 +75,11 @@ public static boolean checkRelationshipAccessAllowedInMemory(String action, Stri } if (filterCriteriaNode != null && filterCriteriaNode.get("endOneEntity") != null) { JsonNode entityFilterCriteriaNode = filterCriteriaNode.get("endOneEntity"); - eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, new AtlasEntity(endOneEntity)); + eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, new AtlasEntity(endOneEntity), oneVertex); if (eval) { entityFilterCriteriaNode = filterCriteriaNode.get("endTwoEntity"); - eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, new AtlasEntity(endTwoEntity)); + eval = validateFilterCriteriaWithEntity(entityFilterCriteriaNode, new AtlasEntity(endTwoEntity), twoVertex); } } ret = ret || eval; diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java index 117e4fb60e..d0d6eacb9e 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java @@ -1490,6 +1490,7 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean if (!PreProcessor.skipInitialAuthCheckTypes.contains(entity.getTypeName())) { /*AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_CREATE, new AtlasEntityHeader(entity)), "create entity: type=", entity.getTypeName());*/ + //AuthorizerUtils.verifyEntityCreateAccess(entity, context.getVertex(entity.getGuid()), AtlasPrivilege.ENTITY_CREATE); AuthorizerUtils.verifyEntityCreateAccess(entity, AtlasPrivilege.ENTITY_CREATE); } }