You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by ka...@apache.org on 2018/05/17 17:03:06 UTC
sentry git commit: SENTRY-2174: Sentry authorization provider should
now generate ACL for users. (Kalyan Kumar kalvagadda,
reviewed-by Na Li and Sergio Pena)
Repository: sentry
Updated Branches:
refs/heads/master 48422f4cc -> 266857472
SENTRY-2174: Sentry authorization provider should now generate ACL for users. (Kalyan Kumar kalvagadda, reviewed-by Na Li and Sergio Pena)
Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/26685747
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/26685747
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/26685747
Branch: refs/heads/master
Commit: 266857472e49bccb02a70328a3d1f45eb01863a4
Parents: 48422f4
Author: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Authored: Thu May 17 12:01:15 2018 -0500
Committer: Kalyan Kumar Kalvagadda <kk...@cloudera.com>
Committed: Thu May 17 12:01:15 2018 -0500
----------------------------------------------------------------------
.../apache/sentry/hdfs/SentryPermissions.java | 164 ++++++++++++++++---
.../sentry/hdfs/TestSentryPermissions.java | 118 +++++++++++++
2 files changed, 260 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/sentry/blob/26685747/sentry-hdfs/sentry-hdfs-namenode-plugin/src/main/java/org/apache/sentry/hdfs/SentryPermissions.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-namenode-plugin/src/main/java/org/apache/sentry/hdfs/SentryPermissions.java b/sentry-hdfs/sentry-hdfs-namenode-plugin/src/main/java/org/apache/sentry/hdfs/SentryPermissions.java
index a88d8e2..c162ec1 100644
--- a/sentry-hdfs/sentry-hdfs-namenode-plugin/src/main/java/org/apache/sentry/hdfs/SentryPermissions.java
+++ b/sentry-hdfs/sentry-hdfs-namenode-plugin/src/main/java/org/apache/sentry/hdfs/SentryPermissions.java
@@ -25,6 +25,8 @@ import org.apache.hadoop.fs.permission.AclEntryType;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntity;
import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntityType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class SentryPermissions implements AuthzPermissions {
@@ -85,12 +87,89 @@ public class SentryPermissions implements AuthzPermissions {
}
}
+ /**
+ * Defines HDFS ACL entity to which ACL's are assigned.
+ */
+ public static class HdfsAclEntity {
+ private final AclEntryType type;
+ private final String value;
+
+ private HdfsAclEntity(AclEntryType type, String value) throws IllegalArgumentException {
+ if(type == AclEntryType.USER || type == AclEntryType.GROUP) {
+ this.type = type;
+ this.value = value;
+ } else {
+ throw new IllegalArgumentException("Invalid AclEntryType");
+ }
+ }
+ public static HdfsAclEntity constructAclEntityForUser(String user) {
+ return new HdfsAclEntity(AclEntryType.USER, user);
+ }
+
+ public static HdfsAclEntity constructAclEntityForGroup(String group) {
+ return new HdfsAclEntity(AclEntryType.GROUP, group);
+ }
+
+ public AclEntryType getType() {
+ return type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ HdfsAclEntity other = (HdfsAclEntity) obj;
+ if (type == null) {
+ if (other.type != null) {
+ return false;
+ }
+ } else if (!type.equals(other.type)) {
+ return false;
+ }
+
+ if (value == null) {
+ if (other.value != null) {
+ return false;
+ }
+ } else if (!value.equals(other.value)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+
+ return result;
+ }
+ }
+
// Comparison of authorizable object should be case insensitive.
private final Map<String, PrivilegeInfo> privileges = new TreeMap<String, PrivilegeInfo>(String.CASE_INSENSITIVE_ORDER);
private Map<String, Set<String>> authzObjChildren = new TreeMap<String, Set<String>>(String.CASE_INSENSITIVE_ORDER);
// RoleInfo should be case insensitive.
private final Map<String, RoleInfo> roles = new TreeMap<String, RoleInfo>(String.CASE_INSENSITIVE_ORDER);
+ private static Logger LOG =
+ LoggerFactory.getLogger(SentryINodeAttributesProvider.class);
+
String getParentAuthzObject(String authzObject) {
if (authzObject != null) {
@@ -127,37 +206,56 @@ public class SentryPermissions implements AuthzPermissions {
}
}
- private Map<String, FsAction> getGroupPerms(String authzObj) {
- Map<String, FsAction> groupPerms;
+ /**
+ * Retrieves all the permissions granted to the object directly and inherited from
+ * the parents.
+ * @param authzObj Object name for which permissions are needed.
+ * @return Sentry Permissions
+ */
+ private Map<HdfsAclEntity, FsAction> getPerms(String authzObj) {
+ Map<HdfsAclEntity, FsAction> perms;
String parent = getParentAuthzObject(authzObj);
if (parent == null || parent.equals(authzObj)) {
- groupPerms = new HashMap<String, FsAction>();
+ perms = new HashMap<HdfsAclEntity, FsAction>();
} else {
- groupPerms = getGroupPerms(parent);
+ perms = getPerms(parent);
}
PrivilegeInfo privilegeInfo = privileges.get(authzObj);
if (privilegeInfo != null) {
for (Map.Entry<TPrivilegeEntity, FsAction> privs : privilegeInfo
.getAllPermissions().entrySet()) {
- if(privs.getKey().getType() == TPrivilegeEntityType.ROLE) {
- constructAclEntry(privs.getKey().getValue(), privs.getValue(), groupPerms);
- }
+ constructHdfsPermissions(privs.getKey(), privs.getValue(), perms);
}
}
- return groupPerms;
+ return perms;
}
+ /**
+ * Constructs HDFS ACL's based on the permissions granted to the object directly
+ * and inherited from the parents.
+ * @param authzObj Object name for which ACL are needed
+ * @return HDFS ACL's
+ */
@Override
public List<AclEntry> getAcls(String authzObj) {
- Map<String, FsAction> groupPerms = getGroupPerms(authzObj);
+ Map<HdfsAclEntity, FsAction> permissions = getPerms(authzObj);
+
List<AclEntry> retList = new LinkedList<AclEntry>();
- for (Map.Entry<String, FsAction> groupPerm : groupPerms.entrySet()) {
+ for (Map.Entry<HdfsAclEntity, FsAction> permission : permissions.entrySet()) {
AclEntry.Builder builder = new AclEntry.Builder();
- builder.setName(groupPerm.getKey());
- builder.setType(AclEntryType.GROUP);
+ if(permission.getKey().getType() == AclEntryType.GROUP) {
+ builder.setName(permission.getKey().getValue());
+ builder.setType(AclEntryType.GROUP);
+ } else if (permission.getKey().getType() == AclEntryType.USER){
+ builder.setName(permission.getKey().getValue());
+ builder.setType(AclEntryType.USER);
+ } else {
+ LOG.warn("Permissions for Invalid AclEntryType: %s", permission.getKey().getType());
+ continue;
+ }
builder.setScope(AclEntryScope.ACCESS);
- FsAction action = groupPerm.getValue();
+ FsAction action = permission.getValue();
if (action == FsAction.READ || action == FsAction.WRITE
|| action == FsAction.READ_WRITE) {
action = action.or(FsAction.EXECUTE);
@@ -168,17 +266,39 @@ public class SentryPermissions implements AuthzPermissions {
return retList;
}
- private void constructAclEntry(String role, FsAction permission,
- Map<String, FsAction> groupPerms) {
- RoleInfo roleInfo = roles.get(role);
- if (roleInfo != null) {
- for (String group : roleInfo.groups) {
- FsAction fsAction = groupPerms.get(group);
- if (fsAction == null) {
- fsAction = FsAction.NONE;
+ /**
+ * Constructs HDFS Permissions entry based on the privileges granted.
+ * @param privilegeEntity Privilege Entity
+ * @param permission Permission granted
+ * @param perms
+ */
+ private void constructHdfsPermissions(TPrivilegeEntity privilegeEntity, FsAction permission,
+ Map<HdfsAclEntity, FsAction> perms) {
+ HdfsAclEntity aclEntry;
+ FsAction fsAction;
+ if(privilegeEntity.getType() == TPrivilegeEntityType.ROLE) {
+ RoleInfo roleInfo = roles.get(privilegeEntity.getValue());
+ if (roleInfo != null) {
+ for (String group : roleInfo.groups) {
+ aclEntry = HdfsAclEntity.constructAclEntityForGroup(group);
+ // fsAction is an aggregate of permissions granted to
+ // the group on the object and it's parents.
+ fsAction = perms.get(aclEntry);
+ if (fsAction == null) {
+ fsAction = FsAction.NONE;
+ }
+ perms.put(aclEntry, fsAction.or(permission));
}
- groupPerms.put(group, fsAction.or(permission));
}
+ } else if(privilegeEntity.getType() == TPrivilegeEntityType.USER) {
+ aclEntry = HdfsAclEntity.constructAclEntityForUser(privilegeEntity.getValue());
+ // fsAction is an aggregate of permissions granted to
+ // the user on the object and it's parents.
+ fsAction = perms.get(aclEntry);
+ if (fsAction == null) {
+ fsAction = FsAction.NONE;
+ }
+ perms.put(aclEntry, fsAction.or(permission));
}
}
http://git-wip-us.apache.org/repos/asf/sentry/blob/26685747/sentry-hdfs/sentry-hdfs-namenode-plugin/src/test/java/org/apache/sentry/hdfs/TestSentryPermissions.java
----------------------------------------------------------------------
diff --git a/sentry-hdfs/sentry-hdfs-namenode-plugin/src/test/java/org/apache/sentry/hdfs/TestSentryPermissions.java b/sentry-hdfs/sentry-hdfs-namenode-plugin/src/test/java/org/apache/sentry/hdfs/TestSentryPermissions.java
index dbce405..f0ca787 100644
--- a/sentry-hdfs/sentry-hdfs-namenode-plugin/src/test/java/org/apache/sentry/hdfs/TestSentryPermissions.java
+++ b/sentry-hdfs/sentry-hdfs-namenode-plugin/src/test/java/org/apache/sentry/hdfs/TestSentryPermissions.java
@@ -19,6 +19,13 @@
package org.apache.sentry.hdfs;
+import java.util.List;
+
+import org.apache.hadoop.fs.permission.AclEntryType;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntity;
+import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntityType;
+import org.apache.hadoop.fs.permission.AclEntry;
import org.junit.Assert;
import org.junit.Test;
@@ -37,4 +44,115 @@ public class TestSentryPermissions {
Assert.assertNotNull(perm.getRoleInfo("admin"));
Assert.assertNull(perm.getRoleInfo("doesNotExist"));
}
+
+ /**
+ * Adds group permissions and role info and check is the ACL are properly generated.
+ */
+ @Test
+ public void testSentryRolePermissions() {
+ String authorizable = "db1.tb1";
+ FsAction fsAction = FsAction.ALL;
+ SentryPermissions perms = new SentryPermissions();
+ SentryPermissions.RoleInfo roleInfo = new SentryPermissions.RoleInfo("role1");
+ roleInfo.addGroup("group1");
+ roleInfo.addGroup("group2");
+ TPrivilegeEntity roleEntity = new TPrivilegeEntity(TPrivilegeEntityType.ROLE, "role1");
+
+ perms.addRoleInfo(roleInfo);
+
+ SentryPermissions.PrivilegeInfo pInfo = new SentryPermissions.PrivilegeInfo(authorizable);
+ pInfo.setPermission(roleEntity, fsAction);
+
+ perms.addPrivilegeInfo(pInfo);
+
+ List<AclEntry> acls = perms.getAcls(authorizable);
+ Assert.assertEquals("Unexpected number of ACL entries received", 2, acls.size());
+ Assert.assertEquals("Unexpected permission", fsAction, acls.get(0).getPermission());
+ }
+
+ /**
+ * Adds user permissions and check is the ACL are properly generated.
+ */
+ @Test
+ public void testSentryUserPermissions() {
+ String authorizable = "db1.tb1";
+ FsAction fsAction = FsAction.ALL;
+ TPrivilegeEntity userEntity = new TPrivilegeEntity(TPrivilegeEntityType.USER, "user1");
+
+ SentryPermissions perms = new SentryPermissions();
+ SentryPermissions.PrivilegeInfo pInfo = new SentryPermissions.PrivilegeInfo(authorizable);
+ pInfo.setPermission(userEntity, fsAction);
+
+ perms.addPrivilegeInfo(pInfo);
+
+ List<AclEntry> acls = perms.getAcls(authorizable);
+ Assert.assertEquals("Unexpected number of ACL entries received", 1, acls.size());
+ Assert.assertEquals("Unexpected permission", fsAction, acls.get(0).getPermission());
+ }
+
+ /**
+ * Adds aggregated user permissions and check is the ACL are properly generated.
+ */
+ @Test
+ public void testSentryAggregatedUserPermissions() {
+ String authorizable = null;
+ // Add read permission for database
+ authorizable = "db1";
+ TPrivilegeEntity userEntity = new TPrivilegeEntity(TPrivilegeEntityType.USER, "user1");
+
+ SentryPermissions perms = new SentryPermissions();
+ SentryPermissions.PrivilegeInfo pInfo = new SentryPermissions.PrivilegeInfo(authorizable);
+ pInfo.setPermission(userEntity, FsAction.READ_EXECUTE);
+ perms.addPrivilegeInfo(pInfo);
+
+ // Add write permission for a particular table in the database.
+ authorizable = "db1.tb1";
+ pInfo = new SentryPermissions.PrivilegeInfo(authorizable);
+ pInfo.setPermission(userEntity, FsAction.WRITE_EXECUTE);
+ perms.addPrivilegeInfo(pInfo);
+
+ List<AclEntry> acls = perms.getAcls(authorizable);
+ Assert.assertEquals("Unexpected number of ACL entries received", 1, acls.size());
+ Assert.assertEquals("Unexpected permission", FsAction.ALL, acls.get(0).getPermission());
+ }
+
+ /**
+ * Adds user and group permissions and role info and check is the ACL are properly generated.
+ */
+ @Test
+ public void testSentryPermissions() {
+ String authorizable = "db1.tb1";
+ FsAction fsAction = FsAction.ALL;
+ SentryPermissions perms = new SentryPermissions();
+ SentryPermissions.RoleInfo roleInfo = new SentryPermissions.RoleInfo("role1");
+ roleInfo.addGroup("group1");
+ roleInfo.addGroup("group2");
+ TPrivilegeEntity roleEntity = new TPrivilegeEntity(TPrivilegeEntityType.ROLE, "role1");
+ TPrivilegeEntity userEntity = new TPrivilegeEntity(TPrivilegeEntityType.USER, "user1");
+
+ perms.addRoleInfo(roleInfo);
+
+ SentryPermissions.PrivilegeInfo pInfo = new SentryPermissions.PrivilegeInfo(authorizable);
+ pInfo.setPermission(roleEntity, fsAction);
+ pInfo.setPermission(userEntity, fsAction);
+
+ perms.addPrivilegeInfo(pInfo);
+
+ List<AclEntry> acls = perms.getAcls(authorizable);
+ Assert.assertEquals("Unexpected number of ACL entries received", 3, acls.size());
+ Assert.assertEquals("Unexpected permission", fsAction, acls.get(0).getPermission());
+
+ int userAclCount = 0;
+ int groupAclCount = 0;
+
+ for (AclEntry entry : acls) {
+ if(entry.getType() == AclEntryType.GROUP) {
+ groupAclCount++;
+ } else if (entry.getType() == AclEntryType.USER) {
+ userAclCount++;
+ }
+ }
+ Assert.assertEquals("Unexpected number of User ACL", 1, userAclCount);
+ Assert.assertEquals("Unexpected number of Group ACL", 2, groupAclCount);
+ }
}