diff --git a/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java b/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java index 0070185..d60cb1b 100644 --- a/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java +++ b/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java @@ -39,7 +39,6 @@ import java.util.concurrent.locks.ReentrantLock; import javax.jdo.JDODataStoreException; -import javax.jdo.JDOEnhanceException; import javax.jdo.JDOHelper; import javax.jdo.JDOObjectNotFoundException; import javax.jdo.PersistenceManager; @@ -49,7 +48,6 @@ import javax.jdo.datastore.DataStoreCache; import javax.jdo.identity.IntIdentity; -import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.RecognitionException; import org.apache.commons.logging.Log; @@ -62,14 +60,10 @@ import org.apache.hadoop.hive.common.classification.InterfaceStability; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; -import org.apache.hadoop.hive.metastore.api.BinaryColumnStatsData; -import org.apache.hadoop.hive.metastore.api.BooleanColumnStatsData; import org.apache.hadoop.hive.metastore.api.ColumnStatistics; -import org.apache.hadoop.hive.metastore.api.ColumnStatisticsData; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsDesc; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj; import org.apache.hadoop.hive.metastore.api.Database; -import org.apache.hadoop.hive.metastore.api.DoubleColumnStatsData; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.metastore.api.Function; import org.apache.hadoop.hive.metastore.api.FunctionType; @@ -80,7 +74,6 @@ import org.apache.hadoop.hive.metastore.api.InvalidInputException; import org.apache.hadoop.hive.metastore.api.InvalidObjectException; import org.apache.hadoop.hive.metastore.api.InvalidPartitionException; -import org.apache.hadoop.hive.metastore.api.LongColumnStatsData; import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.hive.metastore.api.NoSuchObjectException; import org.apache.hadoop.hive.metastore.api.Order; @@ -96,7 +89,6 @@ import org.apache.hadoop.hive.metastore.api.SerDeInfo; import org.apache.hadoop.hive.metastore.api.SkewedInfo; import org.apache.hadoop.hive.metastore.api.StorageDescriptor; -import org.apache.hadoop.hive.metastore.api.StringColumnStatsData; import org.apache.hadoop.hive.metastore.api.Table; import org.apache.hadoop.hive.metastore.api.Type; import org.apache.hadoop.hive.metastore.api.UnknownDBException; @@ -140,8 +132,6 @@ import org.apache.thrift.TException; import org.datanucleus.store.rdbms.exceptions.MissingTableException; -import org.antlr.runtime.Token; - import com.google.common.collect.Lists; @@ -3164,7 +3154,13 @@ public boolean removeRole(String roleName) throws MetaException, return success; } - private List listRoles(String userName, + /** + * Get all the roles in the role hierarchy that this user and groupNames belongs to + * @param userName + * @param groupNames + * @return + */ + private Set listAllRolesInHierarchy(String userName, List groupNames) { List ret = new ArrayList(); if(userName != null) { @@ -3175,7 +3171,29 @@ public boolean removeRole(String roleName) throws MetaException, ret.addAll(listRoles(groupName, PrincipalType.GROUP)); } } - return ret; + // get names of these roles and its ancestors + Set roleNames = new HashSet(); + getAllRoleAncestors(roleNames, ret); + return roleNames; + } + + /** + * Add role names of parentRoles and its parents to processedRoles + * + * @param processedRoleNames + * @param parentRoles + */ + private void getAllRoleAncestors(Set processedRoleNames, List parentRoles) { + for (MRoleMap parentRole : parentRoles) { + String parentRoleName = parentRole.getRole().getRoleName(); + if (!processedRoleNames.contains(parentRoleName)) { + // unprocessed role: get its parents, add it to processed, and call this + // function recursively + List nextParentRoles = listRoles(parentRoleName, PrincipalType.ROLE); + processedRoleNames.add(parentRoleName); + getAllRoleAncestors(processedRoleNames, nextParentRoles); + } + } } @SuppressWarnings("unchecked") @@ -3383,13 +3401,12 @@ public PrincipalPrivilegeSet getDBPrivilegeSet(String dbName, } ret.setGroupPrivileges(dbGroupPriv); } - List roles = listRoles(userName, groupNames); - if (roles != null && roles.size() > 0) { + Set roleNames = listAllRolesInHierarchy(userName, groupNames); + if (roleNames != null && roleNames.size() > 0) { Map> dbRolePriv = new HashMap>(); - for (MRoleMap role : roles) { - String name = role.getRole().getRoleName(); + for (String roleName : roleNames) { dbRolePriv - .put(name, getDBPrivilege(dbName, name, PrincipalType.ROLE)); + .put(roleName, getDBPrivilege(dbName, roleName, PrincipalType.ROLE)); } ret.setRolePrivileges(dbRolePriv); } @@ -3427,11 +3444,10 @@ public PrincipalPrivilegeSet getPartitionPrivilegeSet(String dbName, } ret.setGroupPrivileges(partGroupPriv); } - List roles = listRoles(userName, groupNames); - if (roles != null && roles.size() > 0) { + Set roleNames = listAllRolesInHierarchy(userName, groupNames); + if (roleNames != null && roleNames.size() > 0) { Map> partRolePriv = new HashMap>(); - for (MRoleMap role : roles) { - String roleName = role.getRole().getRoleName(); + for (String roleName : roleNames) { partRolePriv.put(roleName, getPartitionPrivilege(dbName, tableName, partition, roleName, PrincipalType.ROLE)); } @@ -3471,11 +3487,10 @@ public PrincipalPrivilegeSet getTablePrivilegeSet(String dbName, } ret.setGroupPrivileges(tableGroupPriv); } - List roles = listRoles(userName, groupNames); - if (roles != null && roles.size() > 0) { + Set roleNames = listAllRolesInHierarchy(userName, groupNames); + if (roleNames != null && roleNames.size() > 0) { Map> tableRolePriv = new HashMap>(); - for (MRoleMap role : roles) { - String roleName = role.getRole().getRoleName(); + for (String roleName : roleNames) { tableRolePriv.put(roleName, getTablePrivilege(dbName, tableName, roleName, PrincipalType.ROLE)); } @@ -3517,11 +3532,10 @@ public PrincipalPrivilegeSet getColumnPrivilegeSet(String dbName, } ret.setGroupPrivileges(columnGroupPriv); } - List roles = listRoles(userName, groupNames); - if (roles != null && roles.size() > 0) { + Set roleNames = listAllRolesInHierarchy(userName, groupNames); + if (roleNames != null && roleNames.size() > 0) { Map> columnRolePriv = new HashMap>(); - for (MRoleMap role : roles) { - String roleName = role.getRole().getRoleName(); + for (String roleName : roleNames) { columnRolePriv.put(roleName, getColumnPrivilege(dbName, tableName, columnName, partitionName, roleName, PrincipalType.ROLE)); } @@ -6444,6 +6458,7 @@ private MFunction convertToMFunction(Function func) throws InvalidObjectExceptio return mresourceUriList; } + @Override public void createFunction(Function func) throws InvalidObjectException, MetaException { boolean committed = false; try { @@ -6458,6 +6473,7 @@ public void createFunction(Function func) throws InvalidObjectException, MetaExc } } + @Override public void alterFunction(String dbName, String funcName, Function newFunction) throws InvalidObjectException, MetaException { boolean success = false; @@ -6492,6 +6508,7 @@ public void alterFunction(String dbName, String funcName, Function newFunction) } } + @Override public void dropFunction(String dbName, String funcName) throws MetaException, NoSuchObjectException, InvalidObjectException, InvalidInputException { boolean success = false; @@ -6532,6 +6549,7 @@ private MFunction getMFunction(String db, String function) { return mfunc; } + @Override public Function getFunction(String dbName, String funcName) throws MetaException { boolean commited = false; Function func = null; @@ -6547,6 +6565,7 @@ public Function getFunction(String dbName, String funcName) throws MetaException return func; } + @Override public List getFunctions(String dbName, String pattern) throws MetaException { boolean commited = false; diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLStdHiveAccessController.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLStdHiveAccessController.java index cb1c4e4..e446f71 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLStdHiveAccessController.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLStdHiveAccessController.java @@ -18,8 +18,10 @@ package org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.hadoop.classification.InterfaceAudience.Private; @@ -47,6 +49,7 @@ import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject; import org.apache.hadoop.hive.ql.security.authorization.plugin.HivePrivilegeObject.HivePrivilegeObjectType; import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveRole; +import org.apache.thrift.TException; /** * Implements functionality of access control statements for sql standard based @@ -92,20 +95,46 @@ private void initUserRoles() throws HiveAuthzPluginException { private List getRolesFromMS() throws HiveAuthzPluginException { List roles; try { - roles = metastoreClientFactory.getHiveMetastoreClient(). - list_roles(currentUserName, PrincipalType.USER); + roles = metastoreClientFactory.getHiveMetastoreClient().list_roles(currentUserName, + PrincipalType.USER); + Map name2Rolesmap = new HashMap(); + getAllRoleAncestors(name2Rolesmap, roles); List currentRoles = new ArrayList(roles.size()); - for (Role role : roles) { + for (HiveRole role : name2Rolesmap.values()) { if (!HiveMetaStore.ADMIN.equalsIgnoreCase(role.getRoleName())) { - currentRoles.add(new HiveRole(role)); + currentRoles.add(role); } else { - this.adminRole = new HiveRole(role); + this.adminRole = role; } } return currentRoles; } catch (Exception e) { - throw new HiveAuthzPluginException("Failed to retrieve roles for "+ - currentUserName + ": " + e.getMessage(), e); + throw new HiveAuthzPluginException("Failed to retrieve roles for " + currentUserName + ": " + + e.getMessage(), e); + } + } + + /** + * Add role names of parentRoles and its parents to processedRolesMap + * + * @param processedRolesMap + * @param parentRoles + * @throws TException + * @throws HiveAuthzPluginException + * @throws MetaException + */ + private void getAllRoleAncestors(Map processedRolesMap, List parentRoles) + throws MetaException, HiveAuthzPluginException, TException { + for (Role parentRole : parentRoles) { + String parentRoleName = parentRole.getRoleName(); + if (processedRolesMap.get(parentRoleName) == null) { + // unprocessed role: get its parents, add it to processed, and call this + // function recursively + List nextParentRoles = metastoreClientFactory.getHiveMetastoreClient().list_roles( + parentRoleName, PrincipalType.ROLE); + processedRolesMap.put(parentRoleName, new HiveRole(parentRole)); + getAllRoleAncestors(processedRolesMap, nextParentRoles); + } } } diff --git a/ql/src/test/queries/clientnegative/authorization_rolehierarchy_privs.q b/ql/src/test/queries/clientnegative/authorization_rolehierarchy_privs.q new file mode 100644 index 0000000..496141a --- /dev/null +++ b/ql/src/test/queries/clientnegative/authorization_rolehierarchy_privs.q @@ -0,0 +1,74 @@ +set hive.users.in.admin.role=hive_admin_user; +set hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory; +set hive.security.authenticator.manager=org.apache.hadoop.hive.ql.security.SessionStateConfigUserAuthenticator; +set hive.security.authorization.enabled=true; + +set user.name=hive_admin_user; +show current roles; +set role ADMIN; + +---------- +-- create the following user, role mapping +-- user1 -> role1 -> role2 -> role3 +---------- + +create role role1; +grant role1 to user user1; + +create role role2; +grant role2 to role role1; + +create role role3; +grant role3 to role role2; + + +create table t1(i int); +grant select on t1 to role role3; + +set user.name=user1; +show current roles; +select * from t1; + +set user.name=hive_admin_user; +show current roles; +grant select on t1 to role role2; + + +set user.name=user1; +show current roles; +select * from t1; + +set user.name=hive_admin_user; +set role ADMIN; +show current roles; +revoke select on table t1 from role role2; + + +create role role4; +grant role4 to user user1; +grant role3 to role role4;; + +set user.name=user1; +show current roles; +select * from t1; + +set user.name=hive_admin_user; +show current roles; +set role ADMIN; + +-- Revoke role3 from hierarchy one at a time and check permissions +-- after revoking from both, select should fail +revoke role3 from role role2; + +set user.name=user1; +show current roles; +select * from t1; + +set user.name=hive_admin_user; +show current roles; +set role ADMIN; +revoke role3 from role role4; + +set user.name=user1; +show current roles; +select * from t1; diff --git a/ql/src/test/results/clientnegative/authorization_rolehierarchy_privs.q.out b/ql/src/test/results/clientnegative/authorization_rolehierarchy_privs.q.out new file mode 100644 index 0000000..53db1e9 --- /dev/null +++ b/ql/src/test/results/clientnegative/authorization_rolehierarchy_privs.q.out @@ -0,0 +1,209 @@ +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC + +PREHOOK: query: set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: ---------- +-- create the following user, role mapping +-- user1 -> role1 -> role2 -> role3 +---------- + +create role role1 +PREHOOK: type: CREATEROLE +POSTHOOK: query: ---------- +-- create the following user, role mapping +-- user1 -> role1 -> role2 -> role3 +---------- + +create role role1 +POSTHOOK: type: CREATEROLE +PREHOOK: query: grant role1 to user user1 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role1 to user user1 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: create role role2 +PREHOOK: type: CREATEROLE +POSTHOOK: query: create role role2 +POSTHOOK: type: CREATEROLE +PREHOOK: query: grant role2 to role role1 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role2 to role role1 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: create role role3 +PREHOOK: type: CREATEROLE +POSTHOOK: query: create role role3 +POSTHOOK: type: CREATEROLE +PREHOOK: query: grant role3 to role role2 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role3 to role role2 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: create table t1(i int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +POSTHOOK: query: create table t1(i int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@t1 +PREHOOK: query: grant select on t1 to role role3 +PREHOOK: type: GRANT_PRIVILEGE +PREHOOK: Output: default@t1 +POSTHOOK: query: grant select on t1 to role role3 +POSTHOOK: type: GRANT_PRIVILEGE +POSTHOOK: Output: default@t1 +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC +role3 +role2 +role1 + +PREHOOK: query: select * from t1 +PREHOOK: type: QUERY +PREHOOK: Input: default@t1 +#### A masked pattern was here #### +POSTHOOK: query: select * from t1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@t1 +#### A masked pattern was here #### +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC + +PREHOOK: query: grant select on t1 to role role2 +PREHOOK: type: GRANT_PRIVILEGE +PREHOOK: Output: default@t1 +POSTHOOK: query: grant select on t1 to role role2 +POSTHOOK: type: GRANT_PRIVILEGE +POSTHOOK: Output: default@t1 +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC +role3 +role2 +role1 + +PREHOOK: query: select * from t1 +PREHOOK: type: QUERY +PREHOOK: Input: default@t1 +#### A masked pattern was here #### +POSTHOOK: query: select * from t1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@t1 +#### A masked pattern was here #### +PREHOOK: query: set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +ADMIN + +PREHOOK: query: revoke select on table t1 from role role2 +PREHOOK: type: REVOKE_PRIVILEGE +PREHOOK: Output: default@t1 +POSTHOOK: query: revoke select on table t1 from role role2 +POSTHOOK: type: REVOKE_PRIVILEGE +POSTHOOK: Output: default@t1 +PREHOOK: query: create role role4 +PREHOOK: type: CREATEROLE +POSTHOOK: query: create role role4 +POSTHOOK: type: CREATEROLE +PREHOOK: query: grant role4 to user user1 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role4 to user user1 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: grant role3 to role role4 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role3 to role role4 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +role4 +PUBLIC +role3 +role2 +role1 + +PREHOOK: query: select * from t1 +PREHOOK: type: QUERY +PREHOOK: Input: default@t1 +#### A masked pattern was here #### +POSTHOOK: query: select * from t1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@t1 +#### A masked pattern was here #### +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC + +PREHOOK: query: set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: -- Revoke role3 from hierarchy one at a time and check permissions +-- after revoking from both, select should fail +revoke role3 from role role2 +PREHOOK: type: REVOKE_ROLE +POSTHOOK: query: -- Revoke role3 from hierarchy one at a time and check permissions +-- after revoking from both, select should fail +revoke role3 from role role2 +POSTHOOK: type: REVOKE_ROLE +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +role4 +role3 +PUBLIC +role2 +role1 + +PREHOOK: query: select * from t1 +PREHOOK: type: QUERY +PREHOOK: Input: default@t1 +#### A masked pattern was here #### +POSTHOOK: query: select * from t1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@t1 +#### A masked pattern was here #### +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +PUBLIC + +PREHOOK: query: set role ADMIN +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: set role ADMIN +POSTHOOK: type: SHOW_ROLES +PREHOOK: query: revoke role3 from role role4 +PREHOOK: type: REVOKE_ROLE +POSTHOOK: query: revoke role3 from role role4 +POSTHOOK: type: REVOKE_ROLE +PREHOOK: query: show current roles +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: show current roles +POSTHOOK: type: SHOW_ROLES +role4 +PUBLIC +role2 +role1 + +FAILED: HiveAccessControlException Permission denied. Principal [name=user1, type=USER] does not have following privileges on Object [type=TABLE_OR_VIEW, name=default.t1] : [SELECT]