Repository: atlas Updated Branches: refs/heads/branch-1.0 e218c9ed5 -> f2a0dc2c7
ATLAS-2809: updated authorization model to authorize add/update/remove of relationships Signed-off-by: Madhan Neethiraj <mad...@apache.org> (cherry picked from commit da967ea8be923102c3485a4cbf55c958f57e23fd) Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/f2a0dc2c Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/f2a0dc2c Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/f2a0dc2c Branch: refs/heads/branch-1.0 Commit: f2a0dc2c798ee8fb2cd22158b3da3eb9b3952332 Parents: e218c9e Author: nixonrodrigues <ni...@apache.org> Authored: Mon Jul 30 18:32:23 2018 +0530 Committer: Madhan Neethiraj <mad...@apache.org> Committed: Sat Aug 4 15:34:33 2018 -0700 ---------------------------------------------------------------------- .../atlas/authorize/AtlasAccessRequest.java | 69 ++++++++++ .../authorize/AtlasAuthorizationUtils.java | 30 +++++ .../apache/atlas/authorize/AtlasAuthorizer.java | 12 +- .../authorize/AtlasEntityAccessRequest.java | 47 ++----- .../atlas/authorize/AtlasNoneAuthorizer.java | 5 + .../apache/atlas/authorize/AtlasPrivilege.java | 6 +- .../AtlasRelationshipAccessRequest.java | 87 +++++++++++++ .../authorize/simple/AtlasSimpleAuthorizer.java | 81 +++++++++++- .../simple/AtlasSimpleAuthzPolicy.java | 130 +++++++++++++++++-- .../resources/atlas-simple-authz-policy.json | 34 ++++- .../resources/atlas-simple-authz-policy.json | 12 ++ distro/src/conf/atlas-simple-authz-policy.json | 32 ++++- .../graph/v2/AtlasRelationshipStoreV2.java | 25 +++- 13 files changed, 498 insertions(+), 72 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasAccessRequest.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAccessRequest.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAccessRequest.java index 4ae9510..8cdd676 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAccessRequest.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAccessRequest.java @@ -17,10 +17,17 @@ */ package org.apache.atlas.authorize; +import org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.type.AtlasClassificationType; +import org.apache.atlas.type.AtlasEntityType; +import org.apache.atlas.type.AtlasTypeRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.Set; public class AtlasAccessRequest { @@ -78,6 +85,68 @@ public class AtlasAccessRequest { this.clientIPAddress = clientIPAddress; } + public Set<String> getEntityTypeAndAllSuperTypes(String entityType, AtlasTypeRegistry typeRegistry) { + final Set<String> ret; + + if (entityType == null) { + ret = Collections.emptySet(); + } else if (typeRegistry == null) { + ret = Collections.singleton(entityType); + } else { + AtlasEntityType entType = typeRegistry.getEntityTypeByName(entityType); + + ret = entType != null ? entType.getTypeAndAllSuperTypes() : Collections.singleton(entityType); + } + + return ret; + } + + public Set<String> getClassificationTypeAndAllSuperTypes(String classificationName, AtlasTypeRegistry typeRegistry) { + final Set<String> ret; + + if (classificationName == null) { + ret = Collections.emptySet(); + } else if (typeRegistry == null) { + ret = Collections.singleton(classificationName); + } else { + AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classificationName); + + return classificationType != null ? classificationType.getTypeAndAllSuperTypes() : Collections.singleton(classificationName); + } + + return ret; + } + + public String getEntityId(AtlasEntityHeader entity) { + final String ret; + + if (entity == null) { + ret = null; + } else { + String qualifiedName = (String) entity.getAttribute("qualifiedName"); + + ret = qualifiedName; + } + + return ret; + } + + public Set<String> getClassificationNames(AtlasEntityHeader entity) { + final Set<String> ret; + + if (entity == null || entity.getClassifications() == null) { + ret = Collections.emptySet(); + } else { + ret = new HashSet<>(); + + for (AtlasClassification classify : entity.getClassifications()) { + ret.add(classify.getTypeName()); + } + } + + return ret; + } + @Override public String toString() { return "AtlasAccessRequest[action=" + action + ", accessTime=" + accessTime + ", user=" + user + http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java index a0d78eb..3f5bd24 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java @@ -62,6 +62,13 @@ public class AtlasAuthorizationUtils { } } + public static void verifyAccess(AtlasRelationshipAccessRequest request, Object... errorMsgParams) throws AtlasBaseException { + if (!isAccessAllowed(request)) { + String message = (errorMsgParams != null && errorMsgParams.length > 0) ? StringUtils.join(errorMsgParams) : ""; + throw new AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS, request.getUser(), message); + } + } + public static void scrubSearchResults(AtlasSearchResultScrubRequest request) throws AtlasBaseException { String userName = getCurrentUserName(); @@ -142,6 +149,27 @@ public class AtlasAuthorizationUtils { return ret; } + public static boolean isAccessAllowed(AtlasRelationshipAccessRequest request) { + boolean ret = false; + String userName = getCurrentUserName(); + + if (StringUtils.isNotEmpty(userName)) { + try { + AtlasAuthorizer authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer(); + + request.setUser(getCurrentUserName(), getCurrentUserGroups()); + request.setClientIPAddress(RequestContext.get().getClientIPAddress()); + ret = authorizer.isAccessAllowed(request); + } catch (AtlasAuthorizationException e) { + LOG.error("Unable to obtain AtlasAuthorizer", e); + } + } else { + ret = true; + } + + return ret; + } + public static String getRequestIpAddress(HttpServletRequest httpServletRequest) { String ret = ""; @@ -156,6 +184,8 @@ public class AtlasAuthorizationUtils { return ret; } + + public static String getCurrentUserName() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java index 563485e..95d69e6 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java @@ -48,8 +48,6 @@ public interface AtlasAuthorizer { */ boolean isAccessAllowed(AtlasEntityAccessRequest request) throws AtlasAuthorizationException; - - /** * authorize operations on a type * @param request @@ -58,6 +56,16 @@ public interface AtlasAuthorizer { */ boolean isAccessAllowed(AtlasTypeAccessRequest request) throws AtlasAuthorizationException; + /** + * authorize relationship type + * @param request + * @return + * @throws AtlasAuthorizationException + */ + default + boolean isAccessAllowed(AtlasRelationshipAccessRequest request) throws AtlasAuthorizationException { + return true; + } /** * scrub search-results to handle entities for which the user doesn't have access http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java ---------------------------------------------------------------------- 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 e79b97c..d87c830 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasEntityAccessRequest.java @@ -19,13 +19,9 @@ package org.apache.atlas.authorize; import org.apache.atlas.model.instance.AtlasClassification; import org.apache.atlas.model.instance.AtlasEntityHeader; -import org.apache.atlas.type.AtlasClassificationType; -import org.apache.atlas.type.AtlasEntityType; import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.commons.lang.StringUtils; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; public class AtlasEntityAccessRequest extends AtlasAccessRequest { @@ -68,21 +64,12 @@ public class AtlasEntityAccessRequest extends AtlasAccessRequest { public AtlasEntityAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, AtlasEntityHeader entity, AtlasClassification classification, String attributeName, String userName, Set<String> userGroups) { super(action, userName, userGroups); - this.entity = entity; - this.entityId = entity != null ? (String) entity.getAttribute("qualifiedName") : null; - this.classification = classification; - this.attributeName = attributeName; - this.typeRegistry = typeRegistry; - - if (entity == null || entity.getClassifications() == null) { - this.entityClassifications = Collections.emptySet(); - } else { - this.entityClassifications = new HashSet<>(); - - for (AtlasClassification classify : entity.getClassifications()) { - this.entityClassifications.add(classify.getTypeName()); - } - } + this.entity = entity; + this.entityId = super.getEntityId(entity); + this.classification = classification; + this.attributeName = attributeName; + this.typeRegistry = typeRegistry; + this.entityClassifications = super.getClassificationNames(entity); } public AtlasEntityHeader getEntity() { @@ -110,29 +97,11 @@ public class AtlasEntityAccessRequest extends AtlasAccessRequest { } public Set<String> getEntityTypeAndAllSuperTypes() { - final Set<String> ret; - - if (entity == null) { - ret = Collections.emptySet(); - } else if (typeRegistry == null) { - ret = Collections.singleton(entity.getTypeName()); - } else { - AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entity.getTypeName()); - - ret = entityType != null ? entityType.getTypeAndAllSuperTypes() : Collections.singleton(entity.getTypeName()); - } - - return ret; + return super.getEntityTypeAndAllSuperTypes(entity == null ? null : entity.getTypeName(), typeRegistry); } public Set<String> getClassificationTypeAndAllSuperTypes(String classificationName) { - if (typeRegistry != null && classificationName != null) { - AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classificationName); - - return classificationType == null ? Collections.emptySet() : classificationType.getTypeAndAllSuperTypes(); - } - - return Collections.emptySet(); + return super.getClassificationTypeAndAllSuperTypes(classificationName, typeRegistry); } @Override http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java index 9f8f7ac..a371049 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasNoneAuthorizer.java @@ -45,6 +45,11 @@ public class AtlasNoneAuthorizer implements AtlasAuthorizer { return true; } + @Override + public boolean isAccessAllowed(AtlasRelationshipAccessRequest request) throws AtlasAuthorizationException { + return true; + } + public void scrubSearchResults(AtlasSearchResultScrubRequest request) throws AtlasAuthorizationException { } http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java ---------------------------------------------------------------------- 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 3cb7f65..59c596d 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java @@ -32,7 +32,11 @@ public enum AtlasPrivilege { ENTITY_REMOVE_CLASSIFICATION("entity-remove-classification"), ADMIN_EXPORT("admin-export"), - ADMIN_IMPORT("admin-import"); + ADMIN_IMPORT("admin-import"), + + RELATIONSHIP_ADD("add-relationship"), + RELATIONSHIP_UPDATE("update-relationship"), + RELATIONSHIP_REMOVE("remove-relationship"); private final String type; http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/AtlasRelationshipAccessRequest.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasRelationshipAccessRequest.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasRelationshipAccessRequest.java new file mode 100644 index 0000000..87e9b59 --- /dev/null +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasRelationshipAccessRequest.java @@ -0,0 +1,87 @@ +/** + * 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.atlas.authorize; + +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.type.AtlasTypeRegistry; + +import java.util.Date; +import java.util.Set; + +public class AtlasRelationshipAccessRequest extends AtlasAccessRequest { + private final AtlasTypeRegistry typeRegistry; + private final String relationshipType ; + private final AtlasEntityHeader end1Entity; + private final AtlasEntityHeader end2Entity; + + + public AtlasRelationshipAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, String relationshipType, AtlasEntityHeader end1Entity, AtlasEntityHeader end2Entity) { + this(typeRegistry, action, relationshipType, end1Entity, end2Entity, null, null, null,null); + } + + public AtlasRelationshipAccessRequest(AtlasTypeRegistry typeRegistry, AtlasPrivilege action, String relationshipType, AtlasEntityHeader end1Entity, AtlasEntityHeader end2Entity, String user, Set<String> userGroups, Date accessTime, String clientIPAddress) { + super(action, user, userGroups, accessTime, clientIPAddress); + + this.typeRegistry = typeRegistry; + this.relationshipType = relationshipType; + this.end1Entity = end1Entity; + this.end2Entity = end2Entity; + } + + public AtlasEntityHeader getEnd1Entity() { + return end1Entity; + } + + public AtlasEntityHeader getEnd2Entity() { + return end2Entity; + } + + public String getRelationshipType() { + return relationshipType; + } + + + public Set<String> getEnd1EntityTypeAndAllSuperTypes() { + return super.getEntityTypeAndAllSuperTypes(end1Entity == null ? null : end1Entity.getTypeName(), typeRegistry); + } + + public Set<String> getEnd1EntityClassifications() { + return super.getClassificationNames(end1Entity); + } + + public String getEnd1EntityId() { + return super.getEntityId(end1Entity); + } + + public Set<String> getEnd2EntityTypeAndAllSuperTypes() { + return super.getEntityTypeAndAllSuperTypes(end2Entity == null ? null : end2Entity.getTypeName(), typeRegistry); + } + + public Set<String> getEnd2EntityClassifications() { + return super.getClassificationNames(end2Entity); + } + + public String getEnd2EntityId() { + return super.getEntityId(end2Entity); + } + + public Set<String> getClassificationTypeAndAllSuperTypes(String classificationName) { + return super.getClassificationTypeAndAllSuperTypes(classificationName, typeRegistry); + } +} http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java ---------------------------------------------------------------------- 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 47c44cc..e210958 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 @@ -27,13 +27,7 @@ import java.util.Set; import org.apache.atlas.ApplicationProperties; import org.apache.atlas.AtlasException; -import org.apache.atlas.authorize.AtlasAdminAccessRequest; -import org.apache.atlas.authorize.AtlasAuthorizer; -import org.apache.atlas.authorize.AtlasAuthorizationException; -import org.apache.atlas.authorize.AtlasEntityAccessRequest; -import org.apache.atlas.authorize.AtlasPrivilege; -import org.apache.atlas.authorize.AtlasSearchResultScrubRequest; -import org.apache.atlas.authorize.AtlasTypeAccessRequest; +import org.apache.atlas.authorize.*; import org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.*; import org.apache.atlas.model.discovery.AtlasSearchResult; import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult; @@ -164,6 +158,66 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { } @Override + public boolean isAccessAllowed(AtlasRelationshipAccessRequest request) throws AtlasAuthorizationException { + final Set<String> roles = getRoles(request.getUser(), request.getUserGroups()); + final String relationShipType = request.getRelationshipType(); + final Set<String> end1EntityTypeAndSuperTypes = request.getEnd1EntityTypeAndAllSuperTypes(); + final Set<String> end1Classifications = new HashSet<>(request.getEnd1EntityClassifications()); + final String end1EntityId = request.getEnd1EntityId(); + final Set<String> end2EntityTypeAndSuperTypes = request.getEnd2EntityTypeAndAllSuperTypes(); + final Set<String> end2Classifications = new HashSet<>(request.getEnd2EntityClassifications()); + final String end2EntityId = request.getEnd2EntityId(); + final String action = request.getAction() != null ? request.getAction().getType() : null; + + boolean hasEnd1EntityAccess = false; + boolean hasEnd2EntityAccess = false; + + for (String role : roles) { + final List<AtlasRelationshipPermission> permissions = getRelationshipPermissionsForRole(role); + + if (permissions == null) { + continue; + } + + for (AtlasRelationshipPermission permission : permissions) { + if (isMatch(relationShipType, permission.getRelationshipTypes()) && isMatch(action, permission.getPrivileges())) { + //End1 permission check + if (!hasEnd1EntityAccess) { + if (isMatchAny(end1EntityTypeAndSuperTypes, permission.getEnd1EntityType()) && isMatch(end1EntityId, permission.getEnd1EntityId())) { + for (Iterator<String> iter = end1Classifications.iterator(); iter.hasNext();) { + String entityClassification = iter.next(); + + if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getEnd1EntityClassification())) { + iter.remove(); + } + } + + hasEnd1EntityAccess = CollectionUtils.isEmpty(end1Classifications); + } + } + + //End2 permission chech + if (!hasEnd2EntityAccess) { + if (isMatchAny(end2EntityTypeAndSuperTypes, permission.getEnd2EntityType()) && isMatch(end2EntityId, permission.getEnd2EntityId())) { + for (Iterator<String> iter = end2Classifications.iterator(); iter.hasNext();) { + String entityClassification = iter.next(); + + if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getEnd2EntityClassification())) { + iter.remove(); + } + } + + hasEnd2EntityAccess = CollectionUtils.isEmpty(end2Classifications); + } + } + } + } + } + + return hasEnd1EntityAccess && hasEnd2EntityAccess; + } + + @Override public boolean isAccessAllowed(AtlasEntityAccessRequest request) throws AtlasAuthorizationException { if (LOG.isDebugEnabled()) { LOG.debug("==> SimpleAtlasAuthorizer.isAccessAllowed({})", request); @@ -324,6 +378,19 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { return ret; } + + private List<AtlasRelationshipPermission> getRelationshipPermissionsForRole(String roleName) { + List<AtlasRelationshipPermission> ret = null; + + if (authzPolicy != null && roleName != null) { + AtlasAuthzRole role = authzPolicy.getRoles().get(roleName); + + ret = role != null ? role.getRelationshipPermissions() : null; + } + + return ret; + } + private boolean isMatch(String value, List<String> patterns) { boolean ret = false; http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthzPolicy.java ---------------------------------------------------------------------- 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 e2a8b7f..485d4e8 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 @@ -76,17 +76,19 @@ public class AtlasSimpleAuthzPolicy implements Serializable { public static class AtlasAuthzRole implements Serializable { private static final long serialVersionUID = 1L; - private List<AtlasAdminPermission> adminPermissions; - private List<AtlasEntityPermission> entityPermissions; - private List<AtlasTypePermission> typePermissions; + private List<AtlasAdminPermission> adminPermissions; + private List<AtlasTypePermission> typePermissions; + private List<AtlasEntityPermission> entityPermissions; + private List<AtlasRelationshipPermission> relationshipPermissions; public AtlasAuthzRole() { } - public AtlasAuthzRole(List<AtlasAdminPermission> adminPermissions, List<AtlasEntityPermission> entityPermissions, List<AtlasTypePermission> typePermissions) { - this.adminPermissions = adminPermissions; - this.entityPermissions = entityPermissions; - this.typePermissions = typePermissions; + public AtlasAuthzRole(List<AtlasAdminPermission> adminPermissions, List<AtlasTypePermission> typePermissions, List<AtlasEntityPermission> entityPermissions, List<AtlasRelationshipPermission> relationshipPermissions) { + this.adminPermissions = adminPermissions; + this.typePermissions = typePermissions; + this.entityPermissions = entityPermissions; + this.relationshipPermissions = relationshipPermissions; } public List<AtlasAdminPermission> getAdminPermissions() { @@ -97,6 +99,14 @@ public class AtlasSimpleAuthzPolicy implements Serializable { this.adminPermissions = adminPermissions; } + public List<AtlasTypePermission> getTypePermissions() { + return typePermissions; + } + + public void setTypePermissions(List<AtlasTypePermission> typePermissions) { + this.typePermissions = typePermissions; + } + public List<AtlasEntityPermission> getEntityPermissions() { return entityPermissions; } @@ -105,13 +115,14 @@ public class AtlasSimpleAuthzPolicy implements Serializable { this.entityPermissions = entityPermissions; } - public List<AtlasTypePermission> getTypePermissions() { - return typePermissions; + public List<AtlasRelationshipPermission> getRelationshipPermissions() { + return relationshipPermissions; } - public void setTypePermissions(List<AtlasTypePermission> typePermissions) { - this.typePermissions = typePermissions; + public void setRelationshipPermissions(List<AtlasRelationshipPermission> relationshipPermissions) { + this.relationshipPermissions = relationshipPermissions; } + } @JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE) @@ -252,4 +263,101 @@ public class AtlasSimpleAuthzPolicy implements Serializable { } } + + @JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE) + @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) + @JsonIgnoreProperties(ignoreUnknown=true) + @XmlRootElement + @XmlAccessorType(XmlAccessType.PROPERTY) + public static class AtlasRelationshipPermission implements Serializable { + private static final long serialVersionUID = 1L; + + private List<String> privileges; // name of AtlasPrivilege enum, wildcards supported + private List<String> relationshipTypes; // name of relationship-type, wildcards supported + private List<String> end1EntityType; // name of end1 entity-type, wildcards supported + private List<String> end1EntityId; // value of end1 entity-unique attribute, wildcards supported + private List<String> end1EntityClassification; // name of end1 classification-type, wildcards supported + private List<String> end2EntityType; // name of end2 entity-type, wildcards supported + private List<String> end2EntityId; // value of end2 entity-unique attribute, wildcards supported + private List<String> end2EntityClassification; // name of end2 classification-type, wildcards supported + + + public AtlasRelationshipPermission() { + } + + public AtlasRelationshipPermission(List<String> privileges, List<String> relationshipTypes, List<String> end1Entitytype, List<String> end1EntityId, List<String> end1EntityClassification, List<String> end2EntityType, List<String> end2EntityId, List<String> end2EntityClassification) { + this.privileges = privileges; + this.relationshipTypes = relationshipTypes; + this.end1EntityType = end1Entitytype; + this.end1EntityId = end1EntityId; + this.end1EntityClassification = end1EntityClassification; + this.end2EntityType = end2EntityType; + this.end2EntityId = end2EntityId; + this.end2EntityClassification = end2EntityClassification; + } + + public List<String> getPrivileges() { + return privileges; + } + + public void setPrivileges(List<String> privileges) { + this.privileges = privileges; + } + + public List<String> getRelationshipTypes() { + return relationshipTypes; + } + + public void setRelationshipTypes(List<String> relationshipTypes) { + this.relationshipTypes = relationshipTypes; + } + + public List<String> getEnd1EntityType() { + return end1EntityType; + } + + public void setEnd1EntityType(List<String> end1EntityType) { + this.end1EntityType = end1EntityType; + } + + public List<String> getEnd1EntityId() { + return end1EntityId; + } + + public void setEnd1EntityId(List<String> end1EntityId) { + this.end1EntityId = end1EntityId; + } + + public List<String> getEnd1EntityClassification() { + return end1EntityClassification; + } + + public void setEnd1EntityClassification(List<String> end1EntityClassification) { + this.end1EntityClassification = end1EntityClassification; + } + + public List<String> getEnd2EntityType() { + return end2EntityType; + } + + public void setEnd2EntityType(List<String> end2EntityType) { + this.end2EntityType = end2EntityType; + } + + public List<String> getEnd2EntityId() { + return end2EntityId; + } + + public void setEnd2EntityId(List<String> end2EntityId) { + this.end2EntityId = end2EntityId; + } + + public List<String> getEnd2EntityClassification() { + return end2EntityClassification; + } + + public void setEnd2EntityClassification(List<String> end2EntityClassification) { + this.end2EntityClassification = end2EntityClassification; + } + } } http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/main/resources/atlas-simple-authz-policy.json ---------------------------------------------------------------------- diff --git a/authorization/src/main/resources/atlas-simple-authz-policy.json b/authorization/src/main/resources/atlas-simple-authz-policy.json index 457b8e8..0a5f0fa 100644 --- a/authorization/src/main/resources/atlas-simple-authz-policy.json +++ b/authorization/src/main/resources/atlas-simple-authz-policy.json @@ -6,7 +6,13 @@ "privileges": [ ".*" ] } ], - + "typePermissions": [ + { + "privileges": [ ".*" ], + "typeCategories": [ ".*" ], + "typeNames": [ ".*" ] + } + ], "entityPermissions": [ { "privileges": [ ".*" ], @@ -15,12 +21,16 @@ "classifications": [ ".*" ] } ], - - "typePermissions": [ + "relationshipPermissions": [ { - "privileges": [ ".*" ], - "typeCategories": [ ".*" ], - "typeNames": [ ".*" ] + "privileges": [ ".*" ], + "relationshipTypes": [ ".*" ], + "end1EntityType": [ ".*" ], + "end1EntityId": [ ".*" ], + "end1EntityClassification": [ ".*" ], + "end2EntityType": [ ".*" ], + "end2EntityId": [ ".*" ], + "end2EntityClassification": [ ".*" ] } ] }, @@ -44,6 +54,18 @@ "entityIds": [ ".*" ], "classifications": [ ".*" ] } + ], + "relationshipPermissions": [ + { + "privileges": [ "add-relationship", "update-relationship", "remove-relationship" ], + "relationshipTypes": [ ".*" ], + "end1EntityType": [ ".*" ], + "end1EntityId": [ ".*" ], + "end1EntityClassification": [ ".*" ], + "end2EntityType": [ ".*" ], + "end2EntityId": [ ".*" ], + "end2EntityClassification": [ ".*" ] + } ] } }, http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/authorization/src/test/resources/atlas-simple-authz-policy.json ---------------------------------------------------------------------- diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json b/authorization/src/test/resources/atlas-simple-authz-policy.json index 457b8e8..5743de1 100644 --- a/authorization/src/test/resources/atlas-simple-authz-policy.json +++ b/authorization/src/test/resources/atlas-simple-authz-policy.json @@ -22,6 +22,18 @@ "typeCategories": [ ".*" ], "typeNames": [ ".*" ] } + ], + "relationshipPermissions": [ + { + "privileges": [ ".*" ], + "relationshipTypes": [ ".*" ], + "endOneEntityType": [ ".*" ], + "endOneEntityId": [ ".*" ], + "endOneEntityClassification": [ ".*" ], + "endTwoEntityType": [ ".*" ], + "endTwoEntityId": [ ".*" ], + "endTwoEntityClassification": [ ".*" ] + } ] }, http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/distro/src/conf/atlas-simple-authz-policy.json ---------------------------------------------------------------------- diff --git a/distro/src/conf/atlas-simple-authz-policy.json b/distro/src/conf/atlas-simple-authz-policy.json index 457b8e8..5ca7084 100644 --- a/distro/src/conf/atlas-simple-authz-policy.json +++ b/distro/src/conf/atlas-simple-authz-policy.json @@ -6,7 +6,13 @@ "privileges": [ ".*" ] } ], - + "typePermissions": [ + { + "privileges": [ ".*" ], + "typeCategories": [ ".*" ], + "typeNames": [ ".*" ] + } + ], "entityPermissions": [ { "privileges": [ ".*" ], @@ -15,12 +21,16 @@ "classifications": [ ".*" ] } ], - - "typePermissions": [ + "relationshipPermissions": [ { "privileges": [ ".*" ], - "typeCategories": [ ".*" ], - "typeNames": [ ".*" ] + "relationshipTypes": [ ".*" ], + "endOneEntityType": [ ".*" ], + "endOneEntityId": [ ".*" ], + "endOneEntityClassification": [ ".*" ], + "endTwoEntityType": [ ".*" ], + "endTwoEntityId": [ ".*" ], + "endTwoEntityClassification": [ ".*" ] } ] }, @@ -44,6 +54,18 @@ "entityIds": [ ".*" ], "classifications": [ ".*" ] } + ], + "relationshipPermissions": [ + { + "privileges": [ "add-relationship", "update-relationship", "remove-relationship" ], + "relationshipTypes": [ ".*" ], + "end1EntityType": [ ".*" ], + "end1EntityId": [ ".*" ], + "end1EntityClassification": [ ".*" ], + "end2EntityType": [ ".*" ], + "end2EntityId": [ ".*" ], + "end2EntityClassification": [ ".*" ] + } ] } }, http://git-wip-us.apache.org/repos/asf/atlas/blob/f2a0dc2c/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2.java index eb1079c..af97625 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2.java @@ -20,10 +20,14 @@ package org.apache.atlas.repository.store.graph.v2; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.annotation.GraphTransaction; +import org.apache.atlas.authorize.AtlasAuthorizationUtils; +import org.apache.atlas.authorize.AtlasPrivilege; +import org.apache.atlas.authorize.AtlasRelationshipAccessRequest; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.instance.AtlasClassification; import org.apache.atlas.model.instance.AtlasEntity.Status; +import org.apache.atlas.model.instance.AtlasEntityHeader; import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasRelationship; import org.apache.atlas.model.instance.AtlasRelationship.AtlasRelationshipWithExtInfo; @@ -183,7 +187,6 @@ public class AtlasRelationshipStoreV2 implements AtlasRelationshipStore { } } - validateRelationship(end1Vertex, end2Vertex, edgeType, relationship.getAttributes()); AtlasRelationship ret = updateRelationship(edge, relationship); @@ -251,6 +254,7 @@ public class AtlasRelationshipStoreV2 implements AtlasRelationshipStore { AtlasEdge edge = graphHelper.getEdgeForGUID(guid); + if (edge == null) { throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIP_GUID_NOT_FOUND, guid); } @@ -259,6 +263,13 @@ public class AtlasRelationshipStoreV2 implements AtlasRelationshipStore { throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIP_ALREADY_DELETED, guid); } + String relationShipType = GraphHelper.getTypeName(edge); + AtlasEntityHeader end1Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(edge.getOutVertex()); + AtlasEntityHeader end2Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(edge.getInVertex()); + + AtlasAuthorizationUtils.verifyAccess(new AtlasRelationshipAccessRequest(typeRegistry,AtlasPrivilege.RELATIONSHIP_REMOVE, relationShipType, end1Entity, end2Entity )); + + deleteHandler.deleteRelationships(Collections.singleton(edge), forceDelete); // notify entities for added/removed classification propagation @@ -320,7 +331,13 @@ public class AtlasRelationshipStoreV2 implements AtlasRelationshipStore { try { ret = getRelationshipEdge(end1Vertex, end2Vertex, relationship.getTypeName()); + if (ret == null) { + AtlasEntityHeader end1Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(end1Vertex); + AtlasEntityHeader end2Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(end2Vertex); + + AtlasAuthorizationUtils.verifyAccess(new AtlasRelationshipAccessRequest(typeRegistry, AtlasPrivilege.RELATIONSHIP_ADD, relationship.getTypeName(), end1Entity , end2Entity )); + ret = createRelationshipEdge(end1Vertex, end2Vertex, relationship); AtlasRelationshipType relationType = typeRegistry.getRelationshipTypeByName(relationship.getTypeName()); @@ -347,6 +364,12 @@ public class AtlasRelationshipStoreV2 implements AtlasRelationshipStore { private AtlasRelationship updateRelationship(AtlasEdge relationshipEdge, AtlasRelationship relationship) throws AtlasBaseException { AtlasRelationshipType relationType = typeRegistry.getRelationshipTypeByName(relationship.getTypeName()); + AtlasVertex end1Vertex = relationshipEdge.getOutVertex(); + AtlasVertex end2Vertex = relationshipEdge.getInVertex(); + AtlasEntityHeader end1Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(end1Vertex); + AtlasEntityHeader end2Entity = entityRetriever.toAtlasEntityHeaderWithClassifications(end2Vertex); + + AtlasAuthorizationUtils.verifyAccess(new AtlasRelationshipAccessRequest(typeRegistry, AtlasPrivilege.RELATIONSHIP_UPDATE, relationship.getTypeName(), end1Entity, end2Entity)); updateTagPropagations(relationshipEdge, relationship);