Skip to content

Commit

Permalink
Merge pull request #2742 from atlanhq/accesscontrolv2-nb
Browse files Browse the repository at this point in the history
Generic support to internal attributes for abac policies inMem evaluation
  • Loading branch information
nikhilbonte21 authored Jan 10, 2024
2 parents 59ec0a3 + 4d642b8 commit 88560a4
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@
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;
import org.elasticsearch.client.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -193,7 +199,7 @@ private static boolean validateResourcesForCreateEntityInMemory(List<RangerPolic
return false;
}

public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntity entity) {
public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntity entity, AtlasVertex vertex) {
AtlasPerfMetrics.MetricRecorder recorder = RequestContext.get().startMetricRecord("validateFilterCriteriaWithEntity");
String condition = data.get("condition").asText();
JsonNode criterion = data.get("criterion");
Expand All @@ -203,8 +209,6 @@ public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntit
}
boolean result = true;

Set<String> assetTypes = AuthorizerCommon.getTypeAndSupertypesList(entity.getTypeName());

for (JsonNode crit : criterion) {

result = true;
Expand All @@ -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")) {
Expand All @@ -234,25 +238,10 @@ public static boolean validateFilterCriteriaWithEntity(JsonNode data, AtlasEntit
return result;
}

private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity, Set<String> 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<String> 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", "");
Expand All @@ -263,63 +252,46 @@ private static boolean evaluateFilterCriteria(JsonNode crit, AtlasEntity entity,
List<String> 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<AtlasClassification> atlasClassifications = entity.getClassifications();
if (atlasClassifications != null && !atlasClassifications.isEmpty()) {
for (AtlasClassification atlasClassification : atlasClassifications) {
entityAttributeValues.add(atlasClassification.getTypeName());
List<AtlasClassification> 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<AtlasObjectId> atlasMeanings = (List<AtlasObjectId>) 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<? extends String>) entity.getAttribute(attributeName));
} else {
entityAttributeValues.add((String) entity.getAttribute(attributeName));
}
} else {
// try fetching from vertex
Collection <String> 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)) {
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,6 +26,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;
Expand Down Expand Up @@ -58,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;
Expand All @@ -68,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;
Expand Down Expand Up @@ -247,7 +254,7 @@ private static boolean validateResourcesForCreateRelationship(List<RangerPolicy>
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();
Expand Down Expand Up @@ -365,7 +372,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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down

0 comments on commit 88560a4

Please sign in to comment.