Repository: atlas
Updated Branches:
  refs/heads/master d5ecfee50 -> da967ea8b


ATLAS-2809: updated authorization model to authorize add/update/remove of 
relationships

Signed-off-by: Madhan Neethiraj <mad...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/da967ea8
Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/da967ea8
Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/da967ea8

Branch: refs/heads/master
Commit: da967ea8be923102c3485a4cbf55c958f57e23fd
Parents: d5ecfee
Author: nixonrodrigues <ni...@apache.org>
Authored: Mon Jul 30 18:32:23 2018 +0530
Committer: Madhan Neethiraj <mad...@apache.org>
Committed: Sat Aug 4 11:58:07 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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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/da967ea8/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 c1aca45..c8adcf1 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);
 

Reply via email to