This is an automated email from the ASF dual-hosted git repository. nixon pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/atlas.git
commit ea66c181ba0d592ce2aff998ed84e4afd30a3d41 Author: nixonrodrigues <ni...@apache.org> AuthorDate: Tue Feb 16 15:56:45 2021 +0530 ATLAS-4158 : Atlas authorization for Add/Update/Remove classification on entities. --- .../authorize/simple/AtlasSimpleAuthorizer.java | 48 ++-- .../authorize/simple/AtlasSimpleAuthzPolicy.java | 50 ++-- .../main/resources/atlas-simple-authz-policy.json | 42 ++-- .../simple/AtlasSimpleAuthorizerTest.java | 260 ++++++++++++++++++--- .../test/resources/atlas-simple-authz-policy.json | 92 +++++++- distro/src/conf/atlas-simple-authz-policy.json | 38 +-- 6 files changed, 407 insertions(+), 123 deletions(-) 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 5636438..7b99e97 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 @@ -42,6 +42,9 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_ADD_CLASSIFICATION; +import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_REMOVE_CLASSIFICATION; +import static org.apache.atlas.authorize.AtlasPrivilege.ENTITY_UPDATE_CLASSIFICATION; import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_CREATE; import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_DELETE; import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_READ; @@ -53,6 +56,12 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { private final static String WILDCARD_ASTERISK = "*"; + private final static Set<AtlasPrivilege> CLASSIFICATION_PRIVILEGES = new HashSet<AtlasPrivilege>() {{ + add(ENTITY_ADD_CLASSIFICATION); + add(ENTITY_REMOVE_CLASSIFICATION); + add(ENTITY_UPDATE_CLASSIFICATION); + }}; + private AtlasSimpleAuthzPolicy authzPolicy; @@ -233,43 +242,38 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { LOG.debug("==> SimpleAtlasAuthorizer.isAccessAllowed({})", request); } + boolean ret = false; final String action = request.getAction() != null ? request.getAction().getType() : null; final Set<String> entityTypes = request.getEntityTypeAndAllSuperTypes(); final String entityId = request.getEntityId(); - final String classification = request.getClassification() != null ? request.getClassification().getTypeName() : null; final String attribute = request.getAttributeName(); final Set<String> entClsToAuthz = new HashSet<>(request.getEntityClassifications()); final Set<String> roles = getRoles(request.getUser(), request.getUserGroups()); - boolean hasEntityAccess = false; - boolean hasClassificationsAccess = false; for (String role : roles) { List<AtlasEntityPermission> permissions = getEntityPermissionsForRole(role); if (permissions != null) { for (AtlasEntityPermission permission : permissions) { - // match entity-type/entity-id/label/business-metadata/attribute - if (isMatchAny(entityTypes, permission.getEntityTypes()) && isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes()) - && isLabelMatch(request, permission) && isBusinessMetadataMatch(request, permission)) { - // match permission/classification - if (!hasEntityAccess) { - if (isMatch(action, permission.getPrivileges()) && isMatch(classification, permission.getClassifications())) { - hasEntityAccess = true; - } - } - - // match entity-classifications - for (Iterator<String> iter = entClsToAuthz.iterator(); iter.hasNext();) { + if (isMatch(action, permission.getPrivileges()) && isMatchAny(entityTypes, permission.getEntityTypes()) && + isMatch(entityId, permission.getEntityIds()) && isMatch(attribute, permission.getAttributes()) && + isLabelMatch(request, permission) && isBusinessMetadataMatch(request, permission) && isClassificationMatch(request, permission)) { + + // 1. entity could have multiple classifications + // 2. access for these classifications could be granted by multiple AtlasEntityPermission entries + // 3. classifications allowed by the current permission will be removed from entClsToAuthz + // 4. request will be allowed once entClsToAuthz is empty i.e. user has permission for all classifications + for (Iterator<String> iter = entClsToAuthz.iterator(); iter.hasNext(); ) { String entityClassification = iter.next(); - if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getClassifications())) { + if (isMatchAny(request.getClassificationTypeAndAllSuperTypes(entityClassification), permission.getEntityClassifications())) { iter.remove(); } } - hasClassificationsAccess = CollectionUtils.isEmpty(entClsToAuthz); + ret = CollectionUtils.isEmpty(entClsToAuthz); - if (hasEntityAccess && hasClassificationsAccess) { + if (ret) { break; } } @@ -277,11 +281,9 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { } } - boolean ret = hasEntityAccess && hasClassificationsAccess; - if (LOG.isDebugEnabled()) { if (!ret) { - LOG.debug("hasEntityAccess={}; hasClassificationsAccess={}, classificationsWithNoAccess={}", hasEntityAccess, hasClassificationsAccess, entClsToAuthz); + LOG.debug("isAccessAllowed={}; classificationsWithNoAccess={}", ret, entClsToAuthz); } LOG.debug("<== SimpleAtlasAuthorizer.isAccessAllowed({}): {}", request, ret); @@ -490,6 +492,10 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { return AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA.equals(request.getAction()) ? isMatch(request.getBusinessMetadata(), permission.getBusinessMetadata()) : true; } + private boolean isClassificationMatch(AtlasEntityAccessRequest request, AtlasEntityPermission permission) { + return (CLASSIFICATION_PRIVILEGES.contains(request.getAction()) && request.getClassification() != null) ? isMatch(request.getClassification().getTypeName(), permission.getClassifications()) : true; + } + private void filterTypes(AtlasAccessRequest request, List<? extends AtlasBaseTypeDef> typeDefs)throws AtlasAuthorizationException { if (typeDefs != null) { for (ListIterator<? extends AtlasBaseTypeDef> iter = typeDefs.listIterator(); iter.hasNext();) { 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 d191128..ee13233 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 @@ -205,29 +205,31 @@ public class AtlasSimpleAuthzPolicy implements Serializable { public static class AtlasEntityPermission implements Serializable { private static final long serialVersionUID = 1L; - private List<String> privileges; // name of AtlasPrivilege enum, wildcards supported - 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> businessMetadata; // name of business-metadata, wildcards supported - private List<String> attributes; // name of entity-attribute, wildcards supported + private List<String> privileges; // name of AtlasPrivilege enum, wildcards supported + private List<String> entityTypes; // name of entity-type, wildcards supported + private List<String> entityIds; // value of entity-unique attribute, wildcards supported + private List<String> entityClassifications; // name of entity classification-type, wildcards supported + private List<String> labels; // labels, wildcards supported + private List<String> businessMetadata; // name of business-metadata, wildcards supported + private List<String> attributes; // name of entity-attribute, wildcards supported + private List<String> classifications; // name of classification-type, 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); + this(privileges, entityTypes, entityIds, classifications, attributes, null, null, null); } - public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> classifications, List<String> labels, List<String> businessMetadata, List<String> attributes) { - this.privileges = privileges; - this.entityTypes = entityTypes; - this.entityIds = entityIds; - this.classifications = classifications; - this.labels = labels; - this.businessMetadata = businessMetadata; - this.attributes = attributes; + public AtlasEntityPermission(List<String> privileges, List<String> entityTypes, List<String> entityIds, List<String> entityClassifications, List<String> labels, List<String> businessMetadata, List<String> attributes, List<String> classifications) { + this.privileges = privileges; + this.entityTypes = entityTypes; + this.entityIds = entityIds; + this.entityClassifications = entityClassifications; + this.labels = labels; + this.businessMetadata = businessMetadata; + this.attributes = attributes; + this.classifications = classifications; } public List<String> getPrivileges() { @@ -254,12 +256,12 @@ public class AtlasSimpleAuthzPolicy implements Serializable { this.entityIds = entityIds; } - public List<String> getClassifications() { - return classifications; + public List<String> getEntityClassifications() { + return entityClassifications; } - public void setClassifications(List<String> classifications) { - this.classifications = classifications; + public void setEntityClassifications(List<String> entityClassifications) { + this.entityClassifications = entityClassifications; } public List<String> getLabels() { @@ -285,6 +287,14 @@ public class AtlasSimpleAuthzPolicy implements Serializable { public void setAttributes(List<String> attributes) { this.attributes = attributes; } + + public List<String> getClassifications() { + return classifications; + } + + public void setClassifications(List<String> classifications) { + this.classifications = classifications; + } } diff --git a/authorization/src/main/resources/atlas-simple-authz-policy.json b/authorization/src/main/resources/atlas-simple-authz-policy.json index 6b20012..bd9d5ed 100644 --- a/authorization/src/main/resources/atlas-simple-authz-policy.json +++ b/authorization/src/main/resources/atlas-simple-authz-policy.json @@ -15,12 +15,14 @@ ], "entityPermissions": [ { - "privileges": [ ".*" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ], - "labels": [ ".*" ], - "namespaces": [ ".*" ] + "privileges": [ ".*" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] } ], "relationshipPermissions": [ @@ -40,12 +42,14 @@ "DATA_SCIENTIST": { "entityPermissions": [ { - "privileges": [ "entity-read", "entity-read-classification" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ], - "labels": [ ".*" ], - "businessMetadata": [ ".*" ] + "privileges": [ "entity-read", "entity-read-classification" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] } ] }, @@ -53,12 +57,14 @@ "DATA_STEWARD": { "entityPermissions": [ { - "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-business-metadata" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ], - "labels": [ ".*" ], - "businessMetadata": [ ".*" ] + "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-business-metadata" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] } ], "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 7083b82..8d38ebe 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 @@ -17,6 +17,8 @@ package org.apache.atlas.authorize.simple; import org.apache.atlas.authorize.*; +import org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasEntityHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterClass; @@ -24,14 +26,48 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.AssertJUnit; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; 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 static final String USER_ADMIN = "admin"; + private static final String USER_DATA_SCIENTIST = "dataScientist"; + private static final String USER_DATA_STEWARD = "dataSteward"; + private static final String USER_DATA_STEWARD_EX = "dataStewardEx"; + private static final String USER_FINANCE = "finance"; + private static final String USER_FINANCE_PII = "financePII"; + private static final String USER_IN_ADMIN_GROUP = "admin-group-user"; + private static final String USER_IN_UNKNOWN_GROUP = "unknown-group-user"; + + private static final Map<String, Set<String>> USER_GROUPS = new HashMap<String, Set<String>>() {{ + put(USER_ADMIN, Collections.singleton("ROLE_ADMIN")); + put(USER_DATA_STEWARD, Collections.emptySet()); + put(USER_DATA_SCIENTIST, Collections.emptySet()); + put(USER_DATA_STEWARD_EX, Collections.singleton("DATA_STEWARD_EX")); + put(USER_FINANCE, Collections.singleton("FINANCE")); + put(USER_FINANCE_PII, Collections.singleton("FINANCE_PII")); + put(USER_IN_ADMIN_GROUP, Collections.singleton("ROLE_ADMIN")); + put(USER_IN_UNKNOWN_GROUP, Collections.singleton("UNKNOWN_GROUP")); + }}; + + private static final List<AtlasPrivilege> ENTITY_PRIVILEGES = Arrays.asList(AtlasPrivilege.ENTITY_CREATE, + AtlasPrivilege.ENTITY_UPDATE, + AtlasPrivilege.ENTITY_READ, + AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, + AtlasPrivilege.ENTITY_UPDATE_CLASSIFICATION, + AtlasPrivilege.ENTITY_REMOVE_CLASSIFICATION, + AtlasPrivilege.ENTITY_READ_CLASSIFICATION, + AtlasPrivilege.ENTITY_ADD_LABEL, + AtlasPrivilege.ENTITY_REMOVE_LABEL, + AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA); + + private static final List<AtlasPrivilege> LABEL_PRIVILEGES = Arrays.asList(AtlasPrivilege.ENTITY_ADD_LABEL, AtlasPrivilege.ENTITY_REMOVE_LABEL); private String originalConf; private AtlasAuthorizer authorizer; @@ -59,15 +95,34 @@ public class AtlasSimpleAuthorizerTest { } @Test(enabled = true) - public void testAccessAllowedForUserAndGroup() { + public void testAllAllowedForAdminUser() { try { - AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE); + for (AtlasPrivilege privilege : AtlasPrivilege.values()) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege); + + setUser(request, USER_ADMIN); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals(privilege.name() + " should have been allowed for user " + USER_DATA_SCIENTIST, true, isAccessAllowed); + } + } catch (Exception e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testAddPIIForStewardExUser() { + try { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null , AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, null, new AtlasClassification("PII")); - request.setUser("admin", Collections.singleton("ROLE_ADMIN")); + setUser(request, USER_DATA_STEWARD_EX); boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals(true, isAccessAllowed); + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed to add PII", true, isAccessAllowed); } catch (Exception e) { LOG.error("Exception in AtlasSimpleAuthorizerTest", e); @@ -76,16 +131,20 @@ public class AtlasSimpleAuthorizerTest { } @Test(enabled = true) - public void testAccessAllowedForGroup() { + public void testAddClassificationOnEntityWithClassificationForStewardExUser() { try { - AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE); - request.setUser("nonmappeduser", Collections.singleton("ROLE_ADMIN")); + AtlasEntityHeader entityHeader = new AtlasEntityHeader(); + entityHeader.setClassifications(Arrays.asList(new AtlasClassification("PII_1"), new AtlasClassification("PII_2"))); + + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, entityHeader, new AtlasClassification("PII")); + + setUser(request, USER_DATA_STEWARD_EX); boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals(true, isAccessAllowed); - } catch (AtlasAuthorizationException e) { + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed to add PII", true, isAccessAllowed); + } catch (Exception e) { LOG.error("Exception in AtlasSimpleAuthorizerTest", e); AssertJUnit.fail(); @@ -93,16 +152,20 @@ public class AtlasSimpleAuthorizerTest { } @Test(enabled = true) - public void testAccessNotAllowedForUserAndGroup() { + public void testAddClassificationOnEntityWithClassificationForStewardExUserShouldFail() { try { - AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE); - request.setUser("nonmappeduser", Collections.singleton("GROUP-NOT-IN-POLICYFILE")); + AtlasEntityHeader entityHeader = new AtlasEntityHeader(); + entityHeader.setClassifications(Arrays.asList(new AtlasClassification("TAG1"), new AtlasClassification("TAG2"))); + + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, entityHeader, new AtlasClassification("PII")); + + setUser(request, USER_DATA_STEWARD_EX); boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals(false, isAccessAllowed); - } catch (AtlasAuthorizationException e) { + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have not been allowed to add PII on entity with TAG1,TAG2 classification ", false, isAccessAllowed); + } catch (Exception e) { LOG.error("Exception in AtlasSimpleAuthorizerTest", e); AssertJUnit.fail(); @@ -110,38 +173,149 @@ public class AtlasSimpleAuthorizerTest { } @Test(enabled = true) - public void testLabels() { + public void testAddPIIForStewardUser() { + try { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null , AtlasPrivilege.ENTITY_ADD_CLASSIFICATION, null, new AtlasClassification("PII")); + + setUser(request, USER_DATA_STEWARD); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should not have been allowed to add PII", false, isAccessAllowed); + } catch (Exception e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testFinancePIIEntityAccessForFinancePIIUser() { + try { + AtlasEntityHeader entity = new AtlasEntityHeader() {{ + setClassifications(Arrays.asList(new AtlasClassification("FINANCE"), new AtlasClassification("PII"))); + }}; + + for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("PII")); + + setUser(request, USER_FINANCE_PII); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_FINANCE_PII + " should have been allowed " + privilege + " on entity with FINANCE & PII", true, isAccessAllowed); + } + } catch (Exception e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testFinancePIIEntityAccessForFinanceUser() { + try { + AtlasEntityHeader entity = new AtlasEntityHeader() {{ + setClassifications(Arrays.asList(new AtlasClassification("FINANCE"), new AtlasClassification("PII"))); + }}; + + for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("PII")); + + setUser(request, USER_FINANCE); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + USER_FINANCE + " should not have been allowed " + privilege + " on entity with FINANCE & PII", false, isAccessAllowed); + } + } catch (Exception e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testFinanceEntityAccess() { + try { + AtlasEntityHeader entity = new AtlasEntityHeader() {{ + setClassifications(Arrays.asList(new AtlasClassification("FINANCE"))); + }}; + + for (String userName : Arrays.asList(USER_FINANCE_PII, USER_FINANCE)) { + for (AtlasPrivilege privilege : ENTITY_PRIVILEGES) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege, entity, new AtlasClassification("FINANCE")); + + setUser(request, userName); + + boolean isAccessAllowed = authorizer.isAccessAllowed(request); + + AssertJUnit.assertEquals("user " + userName + " should have been allowed " + privilege + " on entity with FINANCE", true, isAccessAllowed); + } + } + } catch (Exception e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + + AssertJUnit.fail(); + } + } + + @Test(enabled = true) + public void testAccessForUserInAdminGroup() { try { - AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_ADD_LABEL); + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE); - request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + setUser(request, USER_IN_ADMIN_GROUP); boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to add label", false, isAccessAllowed); + AssertJUnit.assertEquals("user " + USER_IN_ADMIN_GROUP + " should have been allowed " + AtlasPrivilege.ENTITY_UPDATE, true, isAccessAllowed); + } catch (AtlasAuthorizationException e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + AssertJUnit.fail(); + } + } - request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + @Test(enabled = true) + public void testAccessForUserInUnknownGroup() { + try { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE); + + setUser(request, USER_IN_UNKNOWN_GROUP); - isAccessAllowed = authorizer.isAccessAllowed(request); + boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to add label", true, isAccessAllowed); + AssertJUnit.assertEquals("user " + USER_IN_UNKNOWN_GROUP + " should not have been allowed " + AtlasPrivilege.ENTITY_UPDATE, false, isAccessAllowed); + } catch (AtlasAuthorizationException e) { + LOG.error("Exception in AtlasSimpleAuthorizerTest", e); + AssertJUnit.fail(); + } + } - request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_REMOVE_LABEL); + @Test(enabled = true) + public void testLabels() { + try { + for (AtlasPrivilege privilege : LABEL_PRIVILEGES) { + for (String userName : Arrays.asList(USER_DATA_SCIENTIST, USER_DATA_STEWARD)) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege); - request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + setUser(request, userName); - isAccessAllowed = authorizer.isAccessAllowed(request); + boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to remove label", false, isAccessAllowed); + AssertJUnit.assertEquals("user " + userName + " should not have been allowed " + privilege, false, isAccessAllowed); + } + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, privilege); - request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + setUser(request, USER_DATA_STEWARD_EX); - isAccessAllowed = authorizer.isAccessAllowed(request); + boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to remove label", true, isAccessAllowed); + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed " + privilege, true, isAccessAllowed); + } } catch (AtlasAuthorizationException e) { LOG.error("Exception in AtlasSimpleAuthorizerTest", e); @@ -152,23 +326,33 @@ public class AtlasSimpleAuthorizerTest { @Test(enabled = true) public void testBusinessMetadata() { try { - AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA); + for (String userName : Arrays.asList(USER_DATA_SCIENTIST, USER_DATA_STEWARD)) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA); - request.setUser(USER_DATA_SCIENTIST, Collections.emptySet()); + setUser(request, userName); - boolean isAccessAllowed = authorizer.isAccessAllowed(request); + boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_SCIENTIST + " shouldn't be allowed to update business-metadata", false, isAccessAllowed); + AssertJUnit.assertEquals("user " + userName + " should not have been allowed " + AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA, false, isAccessAllowed); + } - request.setUser(USER_DATA_STEWARD, Collections.emptySet()); + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA); + + setUser(request, USER_DATA_STEWARD_EX); - isAccessAllowed = authorizer.isAccessAllowed(request); + boolean isAccessAllowed = authorizer.isAccessAllowed(request); - AssertJUnit.assertEquals("user " + USER_DATA_STEWARD + " should be allowed to update business-metadata", true, isAccessAllowed); + AssertJUnit.assertEquals("user " + USER_DATA_STEWARD_EX + " should have been allowed " + AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA, true, isAccessAllowed); } catch (AtlasAuthorizationException e) { LOG.error("Exception in AtlasSimpleAuthorizerTest", e); AssertJUnit.fail(); } } + + private void setUser(AtlasAccessRequest request, String userName) { + Set<String> userGroups = USER_GROUPS.get(userName); + + request.setUser(userName, userGroups != null ? userGroups : Collections.emptySet()); + } } diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json b/authorization/src/test/resources/atlas-simple-authz-policy.json index 9db6505..cada904 100644 --- a/authorization/src/test/resources/atlas-simple-authz-policy.json +++ b/authorization/src/test/resources/atlas-simple-authz-policy.json @@ -9,10 +9,11 @@ "entityPermissions": [ { - "privileges": [ ".*" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "privileges": [ ".*" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "classifications": [ ".*" ], + "entityClassifications": [ ".*" ] } ], @@ -53,12 +54,77 @@ "DATA_STEWARD": { "entityPermissions": [ { - "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-business-metadata" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ], - "labels": [ ".*" ], - "businessMetadata": [ ".*" ] + "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-business-metadata" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] + } + ] + }, + + "FINANCE": { + "entityPermissions": [ + { + "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ "FINANCE" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ] + }, + { + "privileges": [ "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ "FINANCE" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ "FINANCE" ] + } + ] + }, + + "FINANCE_PII": { + "entityPermissions": [ + { + "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-label", "entity-remove-label", "entity-update-business-metadata" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ "FINANCE", "PII" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ] + }, + { + "privileges": [ "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ "FINANCE", "PII" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ "FINANCE", "PII" ] + } + ] + }, + + "DATA_STEWARD_EX": { + "entityPermissions": [ + { + "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-business-metadata" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ "PII.*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ "PII.*" ] } ] } @@ -75,6 +141,10 @@ "ROLE_ADMIN": [ "ROLE_ADMIN" ], "hadoop": [ "DATA_STEWARD" ], "DATA_STEWARD": [ "DATA_STEWARD" ], - "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ] + "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ], + "FINANCE": [ "FINANCE" ], + "FINANCE_PII": [ "FINANCE_PII" ], + "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ], + "DATA_STEWARD_EX": [ "DATA_STEWARD_EX" ] } } diff --git a/distro/src/conf/atlas-simple-authz-policy.json b/distro/src/conf/atlas-simple-authz-policy.json index 8a3ce60..a5761cc 100644 --- a/distro/src/conf/atlas-simple-authz-policy.json +++ b/distro/src/conf/atlas-simple-authz-policy.json @@ -15,13 +15,14 @@ ], "entityPermissions": [ { - "privileges": [ ".*" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ], - "labels" : [ ".*" ], - "businessMetadata" : [ ".*" ], - "attributes" :[ ".*" ] + "privileges": [ ".*" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] } ], "relationshipPermissions": [ @@ -41,10 +42,13 @@ "DATA_SCIENTIST": { "entityPermissions": [ { - "privileges": [ "entity-read", "entity-read-classification" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "privileges": [ "entity-read", "entity-read-classification" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ] } ] }, @@ -52,10 +56,14 @@ "DATA_STEWARD": { "entityPermissions": [ { - "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], - "entityTypes": [ ".*" ], - "entityIds": [ ".*" ], - "classifications": [ ".*" ] + "privileges": [ "entity-read", "entity-create", "entity-update", "entity-read-classification", "entity-add-classification", "entity-update-classification", "entity-remove-classification" ], + "entityTypes": [ ".*" ], + "entityIds": [ ".*" ], + "entityClassifications": [ ".*" ], + "labels": [ ".*" ], + "businessMetadata": [ ".*" ], + "attributes": [ ".*" ], + "classifications": [ ".*" ] } ], "relationshipPermissions": [