diff --git a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLAuthorizationUtils.java b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLAuthorizationUtils.java index 95da54a..beb45f5 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLAuthorizationUtils.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/plugin/sqlstd/SQLAuthorizationUtils.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -43,6 +45,7 @@ import org.apache.hadoop.hive.metastore.api.HiveObjectType; import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.hive.metastore.api.PrincipalPrivilegeSet; +import org.apache.hadoop.hive.metastore.api.PrincipalType; import org.apache.hadoop.hive.metastore.api.PrivilegeBag; import org.apache.hadoop.hive.metastore.api.PrivilegeGrantInfo; import org.apache.hadoop.hive.metastore.api.Table; @@ -61,6 +64,7 @@ private static final String[] SUPPORTED_PRIVS = { "INSERT", "UPDATE", "DELETE", "SELECT" }; private static final Set SUPPORTED_PRIVS_SET = new HashSet( Arrays.asList(SUPPORTED_PRIVS)); + public static final Log LOG = LogFactory.getLog(SQLAuthorizationUtils.class); /** * Create thrift privileges bag @@ -197,7 +201,7 @@ static RequiredPrivileges getPrivilegesFromMetaStore(IMetaStoreClient metastoreC RequiredPrivileges privs = getRequiredPrivsFromThrift(thrifPrivs); // add owner privilege if user is owner of the object - if (isOwner(metastoreClient, userName, hivePrivObject)) { + if (isOwner(metastoreClient, userName, curRoles, hivePrivObject)) { privs.addPrivilege(SQLPrivTypeGrant.OWNER_PRIV); } if (isAdmin) { @@ -239,42 +243,56 @@ private static void filterPrivsByCurrentRoles(PrincipalPrivilegeSet thriftPrivs, * * @param metastoreClient * @param userName - * user + * current user + * @param curRoles + * current roles for userName * @param hivePrivObject * given object * @return true if user is owner * @throws HiveAuthzPluginException */ private static boolean isOwner(IMetaStoreClient metastoreClient, String userName, - HivePrivilegeObject hivePrivObject) throws HiveAuthzPluginException { - //for now, check only table & db + List curRoles, HivePrivilegeObject hivePrivObject) throws HiveAuthzPluginException { + // for now, check only table & db switch (hivePrivObject.getType()) { - case TABLE_OR_VIEW : { + case TABLE_OR_VIEW: { Table thriftTableObj = null; try { - thriftTableObj = metastoreClient.getTable(hivePrivObject.getDbname(), hivePrivObject.getTableViewURI()); + thriftTableObj = metastoreClient.getTable(hivePrivObject.getDbname(), + hivePrivObject.getTableViewURI()); } catch (Exception e) { throwGetObjErr(e, hivePrivObject); } return userName.equals(thriftTableObj.getOwner()); } - case DATABASE: { - if (MetaStoreUtils.DEFAULT_DATABASE_NAME.equalsIgnoreCase(hivePrivObject.getDbname())){ - return true; - } - Database db = null; - try { - db = metastoreClient.getDatabase(hivePrivObject.getDbname()); - } catch (Exception e) { - throwGetObjErr(e, hivePrivObject); - } - return userName.equals(db.getOwnerName()); + case DATABASE: { + if (MetaStoreUtils.DEFAULT_DATABASE_NAME.equalsIgnoreCase(hivePrivObject.getDbname())) { + return true; + } + Database db = null; + try { + db = metastoreClient.getDatabase(hivePrivObject.getDbname()); + } catch (Exception e) { + throwGetObjErr(e, hivePrivObject); } - case DFS_URI: - case LOCAL_URI: - case PARTITION: - default: + // a db owner can be a user or a role + if(db.getOwnerType() == PrincipalType.USER){ + return userName.equals(db.getOwnerName()); + } else if(db.getOwnerType() == PrincipalType.ROLE){ + // check if any of the roles of this user is an owner + return curRoles.contains(db.getOwnerName()); + } else { + // looks like owner is an unsupported type + LOG.warn("Owner of database " + db.getName() + " is of unsupported type " + + db.getOwnerType()); return false; + } + } + case DFS_URI: + case LOCAL_URI: + case PARTITION: + default: + return false; } } diff --git a/ql/src/test/queries/clientpositive/authorization_owner_actions_db.q b/ql/src/test/queries/clientpositive/authorization_owner_actions_db.q new file mode 100644 index 0000000..b87199d --- /dev/null +++ b/ql/src/test/queries/clientpositive/authorization_owner_actions_db.q @@ -0,0 +1,21 @@ +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; + +set role admin; +-- create role, db, make role the owner of db +create role testrole; +grant role testrole to user hrt_1; +create database testdb; +alter database testdb set owner role testrole; +desc database testdb; + +-- actions that require user to be db owner +-- create table +use testdb; +create table foobar (foo string, bar string); + +-- drop db +drop database testdb cascade; diff --git a/ql/src/test/results/clientpositive/authorization_owner_actions_db.q.out b/ql/src/test/results/clientpositive/authorization_owner_actions_db.q.out new file mode 100644 index 0000000..f0b2146 --- /dev/null +++ b/ql/src/test/results/clientpositive/authorization_owner_actions_db.q.out @@ -0,0 +1,55 @@ +PREHOOK: query: set role admin +PREHOOK: type: SHOW_ROLES +POSTHOOK: query: set role admin +POSTHOOK: type: SHOW_ROLES +#### A masked pattern was here #### +create role testrole +PREHOOK: type: CREATEROLE +#### A masked pattern was here #### +create role testrole +POSTHOOK: type: CREATEROLE +PREHOOK: query: grant role testrole to user hrt_1 +PREHOOK: type: GRANT_ROLE +POSTHOOK: query: grant role testrole to user hrt_1 +POSTHOOK: type: GRANT_ROLE +PREHOOK: query: create database testdb +PREHOOK: type: CREATEDATABASE +POSTHOOK: query: create database testdb +POSTHOOK: type: CREATEDATABASE +#### A masked pattern was here #### +PREHOOK: type: ALTERDATABASE_OWNER +PREHOOK: Output: database:testdb +#### A masked pattern was here #### +POSTHOOK: type: ALTERDATABASE_OWNER +POSTHOOK: Output: database:testdb +PREHOOK: query: desc database testdb +PREHOOK: type: DESCDATABASE +POSTHOOK: query: desc database testdb +POSTHOOK: type: DESCDATABASE +#### A masked pattern was here #### +-- create table +use testdb +PREHOOK: type: SWITCHDATABASE +#### A masked pattern was here #### +-- create table +use testdb +POSTHOOK: type: SWITCHDATABASE +PREHOOK: query: create table foobar (foo string, bar string) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:testdb +POSTHOOK: query: create table foobar (foo string, bar string) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:testdb +POSTHOOK: Output: testdb@foobar +PREHOOK: query: -- drop db +drop database testdb cascade +PREHOOK: type: DROPDATABASE +PREHOOK: Input: database:testdb +PREHOOK: Output: database:testdb +PREHOOK: Output: testdb@foobar +POSTHOOK: query: -- drop db +drop database testdb cascade +POSTHOOK: type: DROPDATABASE +POSTHOOK: Input: database:testdb +POSTHOOK: Output: database:testdb +POSTHOOK: Output: testdb@foobar