This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/master by this push: new 8fe3edd ATLAS-3622: added authorization for add/remove of labels, update of namespace attributes 8fe3edd is described below commit 8fe3edd2a7d480408ec3d43762cfb43887d5fa19 Author: Madhan Neethiraj <mad...@apache.org> AuthorDate: Sun Feb 16 17:15:34 2020 -0800 ATLAS-3622: added authorization for add/remove of labels, update of namespace attributes --- .../atlas/authorize/AtlasEntityAccessRequest.java | 101 +++++++++++++++++-- .../org/apache/atlas/authorize/AtlasPrivilege.java | 7 +- .../authorize/simple/AtlasSimpleAuthorizer.java | 13 ++- .../authorize/simple/AtlasSimpleAuthzPolicy.java | 24 +++++ .../main/resources/atlas-simple-authz-policy.json | 14 ++- .../simple/AtlasSimpleAuthorizerTest.java | 67 ++++++++++++ .../test/resources/atlas-simple-authz-policy.json | 14 ++- .../store/graph/v2/AtlasEntityStoreV2.java | 112 ++++++++++++++++++++- .../store/graph/v2/EntityGraphMapper.java | 2 +- .../store/graph/v2/EntityGraphRetriever.java | 53 ++++++---- 10 files changed, 366 insertions(+), 41 deletions(-) diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java index 951e5c9..f2e4838 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java @@ -28,45 +28,53 @@ public class AtlasEntityAccessRequest extends AtlasAccessRequest { private final AtlasEntityHeader entity; private final String entityId; private final AtlasClassification classification; + private final String label; + private final String namespaceName; private final String attributeName; private final AtlasTypeRegistry typeRegistry; private final Set<String> entityClassifications; public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action) { - this(typeRegistry, action, null, null, null, null, null); + this(typeRegistry, action, null, null, null, null, null, null, null); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity) { - this(typeRegistry, action, entity, null, null, null, null); + this(typeRegistry, action, entity, null, null, null, null, null, null); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification) { - this(typeRegistry, action, entity, classification, null, null, null); + this(typeRegistry, action, entity, classification, null, null, null, null, null); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String attributeName) { - this(typeRegistry, action, entity, null, attributeName, null, null); + this(typeRegistry, action, entity, null, attributeName, null, null, null, null); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String userName, Set<String> userGroups) { - this(typeRegistry, action, entity, null, null, userName, userGroups); + this(typeRegistry, action, entity, null, null, null, null, userName, userGroups); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String userName, Set<String> userGroups) { - this(typeRegistry, action, entity, classification, null, userName, userGroups); + this(typeRegistry, action, entity, classification, null, null, null, userName, userGroups); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, String attributeName, String userName, Set<String> userGroups) { - this(typeRegistry, action, entity, null, attributeName, userName, userGroups); + this(typeRegistry, action, entity, null, attributeName, null, null, userName, userGroups); } public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String attributeName, String userName, Set<String> userGroups) { + this(typeRegistry, action, entity, classification, attributeName, null, null, userName, userGroups); + } + + public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String attributeName, String label, String namespaceName, String userName, Set<String> userGroups) { super(action, userName, userGroups); this.entity = entity; this.entityId = super.getEntityId(entity, typeRegistry); this.classification = classification; + this.label = label; + this.namespaceName = namespaceName; this.attributeName = attributeName; this.typeRegistry = typeRegistry; this.entityClassifications = super.getClassificationNames(entity); @@ -84,6 +92,14 @@ public class AtlasEntityAccessRequest extends AtlasAccessRequest { return classification; } + public String getLabel() { + return label; + } + + public String getNamespaceName() { + return namespaceName; + } + public String getAttributeName() { return attributeName; } @@ -106,11 +122,80 @@ public class AtlasEntityAccessRequest extends AtlasAccessRequest { @Override public String toString() { - return "AtlasEntityAccessRequest[entity=" + entity + ", classification=" + classification + ", attributeName=" + attributeName + + return "AtlasEntityAccessRequest[entity=" + entity + ", classification=" + classification + ", label=" + label + ", namespaceName=" + namespaceName + ", attributeName=" + attributeName + ", action=" + getAction() + ", accessTime=" + getAccessTime() + ", user=" + getUser() + ", userGroups=" + getUserGroups() + ", clientIPAddress=" + getClientIPAddress() + ", forwardedAddresses=" + getForwardedAddresses() + ", remoteIPAddress=" + getRemoteIPAddress() + "]"; } + + public static class AtlasEntityAccessRequestBuilder { + private final AtlasTypeRegistry typeRegistry; + private final AtlasPrivilege action; + private String userName; + private Set<String> userGroups; + private AtlasEntityHeader entity; + private AtlasClassification classification; + private String label; + private String namespaceName; + private String attributeName; + + public AtlasEntityAccessRequestBuilder(AtlasTypeRegistry typeRegistry, AtlasPrivilege action) { + this.typeRegistry = typeRegistry; + this.action = action; + } + + public AtlasEntityAccessRequestBuilder(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity) { + this.typeRegistry = typeRegistry; + this.action = action; + this.entity = entity; + } + + public AtlasEntityAccessRequestBuilder setUserName(String userName) { + this.userName = userName; + + return this; + } + + public AtlasEntityAccessRequestBuilder setUserGroups(Set<String> userGroups) { + this.userGroups = userGroups; + + return this; + } + + public AtlasEntityAccessRequestBuilder setEntity(AtlasEntityHeader entity) { + this.entity = entity; + + return this; + } + + public AtlasEntityAccessRequestBuilder setClassification(AtlasClassification classification) { + this.classification = classification; + + return this; + } + + public AtlasEntityAccessRequestBuilder setLabel(String label) { + this.label = label; + + return this; + } + + public AtlasEntityAccessRequestBuilder setNamespaceName(String namespaceName) { + this.namespaceName = namespaceName; + + return this; + } + + public AtlasEntityAccessRequestBuilder setAttributeName(String attributeName) { + this.attributeName = attributeName; + + return this; + } + + public AtlasEntityAccessRequest build() { + return new AtlasEntityAccessRequest(typeRegistry, action, entity, classification, attributeName, label, namespaceName, userName, userGroups); + } + } } diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java index 38b68fa..7d81e22 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java @@ -37,7 +37,12 @@ public enum AtlasPrivilege { RELATIONSHIP_ADD("add-relationship"), RELATIONSHIP_UPDATE("update-relationship"), RELATIONSHIP_REMOVE("remove-relationship"), - ADMIN_PURGE("admin-purge"); + + ADMIN_PURGE("admin-purge"), + + ENTITY_ADD_LABEL("entity-add-label"), + ENTITY_REMOVE_LABEL("entity-remove-label"), + ENTITY_UPDATE_NAMESPACE("entity-update-namespace"); private final String type; diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java index e210958..5f0c7b2 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java @@ -238,8 +238,9 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { if (permissions != null) { for (AtlasEntityPermission permission : permissions) { - // match entity-type/entity-id/attribute - if (isMatchAny(entityTypes, permission.getEntityTypes()) && isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes())) { + // match entity-type/entity-id/lable/namespace/attribute + if (isMatchAny(entityTypes, permission.getEntityTypes()) && isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes()) + && isLabelMatch(request, permission) && isNamespaceMatch(request, permission)) { // match permission/classification if (!hasEntityAccess) { if (isMatch(action, permission.getPrivileges()) && isMatch(classification, permission.getClassifications())) { @@ -458,6 +459,14 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { } } } + + private boolean isLabelMatch(AtlasEntityAccessRequest request, AtlasEntityPermission permission) { + return (AtlasPrivilege.ENTITY_ADD_LABEL.equals(request.getAction()) || AtlasPrivilege.ENTITY_REMOVE_LABEL.equals(request.getAction())) ? isMatch(request.getLabel(), permission.getLabels()) : true; + } + + private boolean isNamespaceMatch(AtlasEntityAccessRequest request, AtlasEntityPermission permission) { + return AtlasPrivilege.ENTITY_UPDATE_NAMESPACE.equals(request.getAction()) ? isMatch(request.getNamespaceName(), permission.getNamespaces()) : true; + } } diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java index 485d4e8..899e386 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java @@ -209,16 +209,24 @@ public class AtlasSimpleAuthzPolicy implements Serializable { private List<String> entityTypes; // name of entity-type, wildcards supported private List<String> entityIds; // value of entity-unique attribute, wildcards supported private List<String> classifications; // name of classification-type, wildcards supported + private List<String> labels; // labels, wildcards supported + private List<String> namespaces; // name of namespace-type, wildcards supported private List<String> attributes; // name of entity-attribute, wildcards supported public AtlasEntityPermission() { } public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> attributes) { + this(privileges, entityTypes, entityIds, classifications, attributes, null, null); + } + + public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> labels, List<String> namespaces, List<String> attributes) { this.privileges = privileges; this.entityTypes = entityTypes; this.entityIds = entityIds; this.classifications = classifications; + this.labels = labels; + this.namespaces = namespaces; this.attributes = attributes; } @@ -254,6 +262,22 @@ public class AtlasSimpleAuthzPolicy implements Serializable { this.classifications = classifications; } + public List<String> getLabels() { + return labels; + } + + public void setLabels(List<String> labels) { + this.namespaces = labels; + } + + public List<String> getNamespaces() { + return namespaces; + } + + public void setNamespaces(List<String> namespaces) { + this.namespaces = namespaces; + } + public List<String> getAttributes() { return attributes; } diff --git a/authorization/src/main/resources/atlas-simple-authz-policy.json b/authorization/src/main/resources/atlas-simple-authz-policy.json index 0a5f0fa..bd08a6f 100644 --- a/authorization/src/main/resources/atlas-simple-authz-policy.json +++ b/authorization/src/main/resources/atlas-simple-authz-policy.json @@ -18,7 +18,9 @@ "privileges": [ ".*" ], "entityTypes": [ ".*" ], "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "classifications": [ ".*" ], + "labels": [ ".*" ], + "namespaces": [ ".*" ] } ], "relationshipPermissions": [ @@ -41,7 +43,9 @@ "privileges": [ "entity-read", "entity-read-classification" ], "entityTypes": [ ".*" ], "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "classifications": [ ".*" ], + "labels": [ ".*" ], + "namespaces": [ ".*" ] } ] }, @@ -49,10 +53,12 @@ "DATA_STEWARD": { "entityPermissions": [ { - "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], + "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-namespace" ], "entityTypes": [ ".*" ], "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "classifications": [ ".*" ], + "labels": [ ".*" ], + "namespaces": [ ".*" ] } ], "relationshipPermissions": [ diff --git a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java index 16c8c8c..e585e93 100644 --- a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java +++ b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java @@ -29,6 +29,10 @@ import java.util.Collections; public class AtlasSimpleAuthorizerTest { private static Logger LOG = LoggerFactory.getLogger(AtlasSimpleAuthorizerTest.class); + private static final String USER_DATA_SCIENTIST = "dataScientist1"; + private static final String USER_DATA_STEWARD = "dataSteward1"; + + private String originalConf; private AtlasAuthorizer authorizer; @@ -104,4 +108,67 @@ public class AtlasSimpleAuthorizerTest { AssertJUnit.fail(); } } + + @Test(enabled = true) + public void testLabels() { + try { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_LABEL); + + request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to add label", false, isAccessAllowed); + + + request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + + isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to add label", true, isAccessAllowed); + + + request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_REMOVE_LABEL); + + request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + + isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to remove label", false, isAccessAllowed); + + + request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + + isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to remove label", true, isAccessAllowed); + } catch (AtlasAuthorizationException e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testNamespaces() { + try { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_NAMESPACE); + + request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to update namespace", false, isAccessAllowed); + + request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + + isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to update namespace", true, isAccessAllowed); + } catch (AtlasAuthorizationException e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } } diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json b/authorization/src/test/resources/atlas-simple-authz-policy.json index 5743de1..379d42b 100644 --- a/authorization/src/test/resources/atlas-simple-authz-policy.json +++ b/authorization/src/test/resources/atlas-simple-authz-policy.json @@ -43,7 +43,9 @@ "privileges": [ "entity-read", "entity-read-classification" ], "entityTypes": [ ".*" ], "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "classifications": [ ".*" ], + "labels": [ ".*" ], + "namespaces": [ ".*" ] } ] }, @@ -51,10 +53,12 @@ "DATA_STEWARD": { "entityPermissions": [ { - "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], + "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification", "entity-add-label", "entity-remove-label", "entity-update-namespace" ], "entityTypes": [ ".*" ], "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "classifications": [ ".*" ], + "labels": [ ".*" ], + "namespaces": [ ".*" ] } ] } @@ -62,7 +66,9 @@ "userRoles": { "admin": [ "ROLE_ADMIN" ], - "rangertagsync": [ "DATA_SCIENTIST" ] + "rangertagsync": [ "DATA_SCIENTIST" ], + "dataScientist1": [ "DATA_SCIENTIST"], + "dataSteward1": [ "DATA_STEWARD"] }, "groupRoles": { 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 c536f3b..30f5e5a 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 @@ -25,6 +25,7 @@ import org.apache.atlas.annotation.GraphTransaction; import org.apache.atlas.authorize.AtlasAdminAccessRequest; import org.apache.atlas.authorize.AtlasAuthorizationUtils; import org.apache.atlas.authorize.AtlasEntityAccessRequest; +import org.apache.atlas.authorize.AtlasEntityAccessRequest.AtlasEntityAccessRequestBuilder; import org.apache.atlas.authorize.AtlasPrivilege; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.TypeCategory; @@ -66,6 +67,7 @@ import javax.inject.Inject; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -834,14 +836,44 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore { throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty"); } + if (MapUtils.isEmpty(entityNamespaces)) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "entityNamespaces is null/empty"); + } + AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid); if (entityVertex == null) { throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); } - String typeName = getTypeName(entityVertex); - AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName); + String typeName = getTypeName(entityVertex); + AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName); + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityVertex); + Map<String, Map<String, Object>> currNamespaces = entityRetriever.getEntityNamespaces(entityVertex); + Set<String> updatedNsNames = new HashSet<>(); + + for (String nsName : entityType.getNamespaceAttributes().keySet()) { + Map<String, Object> nsAttrs = entityNamespaces.get(nsName); + Map<String, Object> currNsAttrs = currNamespaces != null ? currNamespaces.get(nsName) : null; + + if (nsAttrs == null && !isOverwrite) { + continue; + } else if (MapUtils.isEmpty(nsAttrs) && MapUtils.isEmpty(currNsAttrs)) { // no change + continue; + } else if (Objects.equals(nsAttrs, currNsAttrs)) { // no change + continue; + } + + updatedNsNames.add(nsName); + } + + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_UPDATE_NAMESPACE, entityHeader); + + for (String nsName : updatedNsNames) { + requestBuilder.setNamespaceName(nsName); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "add/update namespace: guid=", guid, ", namespace=", nsName); + } validateNamespaceAttributes(entityVertex, entityType, entityNamespaces, isOverwrite); @@ -867,14 +899,27 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore { throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty"); } + if (MapUtils.isEmpty(entityNamespaces)) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "entityNamespaces is null/empty"); + } + AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid); if (entityVertex == null) { throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); } - String typeName = getTypeName(entityVertex); - AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName); + String typeName = getTypeName(entityVertex); + AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName); + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityVertex); + + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_UPDATE_NAMESPACE, entityHeader); + + for (String nsName : entityNamespaces.keySet()) { + requestBuilder.setNamespaceName(nsName); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "remove namespace: guid=", guid, ", namespace=", nsName); + } entityGraphMapper.removeNamespaceAttributes(entityVertex, entityType, entityNamespaces); @@ -902,6 +947,39 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore { validateLabels(labels); + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityVertex); + Set<String> addedLabels = Collections.emptySet(); + Set<String> removedLabels = Collections.emptySet(); + + if (CollectionUtils.isEmpty(entityHeader.getLabels())) { + addedLabels = labels; + } else if (CollectionUtils.isEmpty(labels)) { + removedLabels = entityHeader.getLabels(); + } else { + addedLabels = new HashSet<String>(CollectionUtils.subtract(labels, entityHeader.getLabels())); + removedLabels = new HashSet<String>(CollectionUtils.subtract(entityHeader.getLabels(), labels)); + } + + if (addedLabels != null) { + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_ADD_LABEL, entityHeader); + + for (String label : addedLabels) { + requestBuilder.setLabel(label); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "add label: guid=", guid, ", label=", label); + } + } + + if (removedLabels != null) { + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_REMOVE_LABEL, entityHeader); + + for (String label : removedLabels) { + requestBuilder.setLabel(label); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "remove label: guid=", guid, ", label=", label); + } + } + entityGraphMapper.setLabels(entityVertex, labels); if (LOG.isDebugEnabled()) { @@ -920,12 +998,25 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore { throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty"); } + if (CollectionUtils.isEmpty(labels)) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "labels is null/empty"); + } + AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid); if (entityVertex == null) { throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); } + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityVertex); + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_REMOVE_LABEL, entityHeader); + + for (String label : labels) { + requestBuilder.setLabel(label); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "remove label: guid=", guid, ", label=", label); + } + validateLabels(labels); entityGraphMapper.removeLabels(entityVertex, labels); @@ -946,12 +1037,25 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore { throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty"); } + if (CollectionUtils.isEmpty(labels)) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "labels is null/empty"); + } + AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid); if (entityVertex == null) { throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); } + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityVertex); + AtlasEntityAccessRequestBuilder requestBuilder = new AtlasEntityAccessRequestBuilder(typeRegistry, AtlasPrivilege.ENTITY_ADD_LABEL, entityHeader); + + for (String label : labels) { + requestBuilder.setLabel(label); + + AtlasAuthorizationUtils.verifyAccess(requestBuilder.build(), "add/update label: guid=", guid, ", label=", label); + } + validateLabels(labels); entityGraphMapper.addLabels(entityVertex, labels); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java index 7461931..2f3aad0 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java @@ -353,7 +353,7 @@ public class EntityGraphMapper { removedLabels = null; } else if (CollectionUtils.isEmpty(labels)) { addedLabels = null; - removedLabels = labels; + removedLabels = currentLabels; } else { addedLabels = new HashSet<String>(CollectionUtils.subtract(labels, currentLabels)); removedLabels = new HashSet<String>(CollectionUtils.subtract(currentLabels, labels)); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java index 3c22d9a..7533ebc 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java @@ -221,6 +221,41 @@ public class EntityGraphRetriever { return ret; } + public Map<String, Map<String, Object>> getEntityNamespaces(AtlasVertex entityVertex) throws AtlasBaseException { + Map<String, Map<String, Object>> ret = null; + String entityTypeName = getTypeName(entityVertex); + AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entityTypeName); + Map<String, Map<String, AtlasNamespaceAttribute>> entityTypeNamespaces = entityType != null ? entityType.getNamespaceAttributes() : null; + + if (MapUtils.isNotEmpty(entityTypeNamespaces)) { + for (Map.Entry<String, Map<String, AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) { + String nsName = entry.getKey(); + Map<String, AtlasNamespaceAttribute> nsAttributes = entry.getValue(); + Map<String, Object> entityNsAttrs = null; + + for (AtlasNamespaceAttribute nsAttribute : nsAttributes.values()) { + Object nsAttrValue = mapVertexToAttribute(entityVertex, nsAttribute, null, false, false); + + if (nsAttrValue != null) { + if (ret == null) { + ret = new HashMap<>(); + } + + if (entityNsAttrs == null) { + entityNsAttrs = new HashMap<>(); + + ret.put(nsName, entityNsAttrs); + } + + entityNsAttrs.put(nsAttribute.getName(), nsAttrValue); + } + } + } + } + + return ret; + } + public Object getEntityAttribute(AtlasVertex entityVertex, AtlasAttribute attribute) { Object ret = null; @@ -770,23 +805,7 @@ public class EntityGraphRetriever { } private void mapNamespaceAttributes(AtlasVertex entityVertex, AtlasEntity entity) throws AtlasBaseException { - AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entity.getTypeName()); - Map<String, Map<String, AtlasNamespaceAttribute>> entityTypeNamespaces = entityType != null ? entityType.getNamespaceAttributes() : null; - - if (MapUtils.isNotEmpty(entityTypeNamespaces)) { - for (Map.Entry<String, Map<String, AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) { - String nsName = entry.getKey(); - Map<String, AtlasNamespaceAttribute> nsAttributes = entry.getValue(); - - for (AtlasNamespaceAttribute nsAttribute : nsAttributes.values()) { - Object nsAttrValue = mapVertexToAttribute(entityVertex, nsAttribute, null, false, false); - - if (nsAttrValue != null) { - entity.setNamespaceAttribute(nsName, nsAttribute.getName(), nsAttrValue); - } - } - } - } + entity.setNamespaceAttributes(getEntityNamespaces(entityVertex)); } public List<AtlasClassification> getAllClassifications(AtlasVertex entityVertex) throws AtlasBaseException {