Repository: sentry Updated Branches: refs/heads/master af8ea0ac1 -> 7ac2b05e5
SENTRY-2226: Support Hive operation ALTER TABLE EXCHANGE. (Na Li, reviewed by Sergio Pena, Kalyan Kumar Kalvagadda) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/7ac2b05e Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/7ac2b05e Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/7ac2b05e Branch: refs/heads/master Commit: 7ac2b05e5681e902dc01fc0d4cc21ac9eb13ae43 Parents: af8ea0a Author: lina.li <[email protected]> Authored: Fri May 11 11:17:09 2018 -0500 Committer: lina.li <[email protected]> Committed: Fri May 11 11:17:09 2018 -0500 ---------------------------------------------------------------------- .../hive/authz/HiveAuthzPrivilegesMap.java | 12 ++ .../TestDbColumnLevelMetaDataOps.java | 124 +++++++++++++++++++ 2 files changed, 136 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/7ac2b05e/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java index ffa193f..4f932ea 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/HiveAuthzPrivilegesMap.java @@ -112,6 +112,16 @@ public class HiveAuthzPrivilegesMap { setOperationType(HiveOperationType.DDL). build(); + // input required privilege from Hive: SELECT on column level and DELETE on table level + // output required privilege from Hive: INSERT on table level + // Sentry makes it more restrictive, and requires ALL at input, INSERT and ALTER at output + HiveAuthzPrivileges alterTableExchangePrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder(). + addInputObjectPriviledge(AuthorizableType.Table, EnumSet.of(DBModelAction.ALL)). + addOutputObjectPriviledge(AuthorizableType.Table, EnumSet.of(DBModelAction.INSERT, DBModelAction.ALTER)). + setOperationScope(HiveOperationScope.TABLE). + setOperationType(HiveOperationType.DDL). + build(); + HiveAuthzPrivileges alterPartPrivilege = new HiveAuthzPrivileges.AuthzPrivilegeBuilder(). addInputObjectPriviledge(AuthorizableType.Table, EnumSet.of(DBModelAction.ALTER)). setOperationScope(HiveOperationScope.TABLE). @@ -240,6 +250,8 @@ public class HiveAuthzPrivilegesMap { hiveAuthzStmtPrivMap.put(HiveOperation.ALTERTABLE_ADDCOLS, alterTablePrivilege); hiveAuthzStmtPrivMap.put(HiveOperation.ALTERTABLE_REPLACECOLS, alterTablePrivilege); hiveAuthzStmtPrivMap.put(HiveOperation.ALTERTABLE_PARTCOLTYPE, alterPartPrivilege); + hiveAuthzStmtPrivMap.put(HiveOperation.ALTERTABLE_EXCHANGEPARTITION, alterTableExchangePrivilege); + hiveAuthzStmtPrivMap.put(HiveOperation.ALTERTABLE_BUCKETNUM, alterPartPrivilege); hiveAuthzStmtPrivMap.put(HiveOperation.ALTERPARTITION_BUCKETNUM, alterPartPrivilege); http://git-wip-us.apache.org/repos/asf/sentry/blob/7ac2b05e/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbColumnLevelMetaDataOps.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbColumnLevelMetaDataOps.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbColumnLevelMetaDataOps.java index 3735179..c065f7f 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbColumnLevelMetaDataOps.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/dbprovider/TestDbColumnLevelMetaDataOps.java @@ -371,4 +371,128 @@ public class TestDbColumnLevelMetaDataOps extends AbstractTestWithStaticConfigur String query = "SHOW TABLE EXTENDED IN " + TEST_COL_METADATA_OPS_DB + " LIKE " + TEST_COL_METADATA_OPS_TB; validateSemanticException(query, USER1_1); } + + /** + * User cannot exchange partition of tables without any privilege on input table and output table + * @throws Exception + */ + @Test + public void testAlterTableExchangeNoPrivilege() throws Exception { + final String PAR_ROLE_NAME = "config1_user_role"; + final String PAR_GROUP_NAME = USERGROUP1; + final String PAR_DB_NAME = "config1_test_database1"; + final String PAR_INPUT_TABLE_NAME = "aliens"; + final String PAR_OUTPUT_TABLE_NAME = "movie_stars"; + + establishSession(ADMIN1); + statement.execute("DROP DATABASE IF EXISTS " + PAR_DB_NAME + " CASCADE"); + statement.execute("CREATE DATABASE " + PAR_DB_NAME); + statement.execute("CREATE ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ROLE " + PAR_ROLE_NAME + " TO GROUP " + PAR_GROUP_NAME); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='earth', diet='milk shakes')"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='trapis-4', diet='sentient lifeforms with cheese')"); + + String query = "ALTER TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " EXCHANGE PARTITION (home_planet='earth', diet='milk shakes') WITH TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME; + validateSemanticException(query, USER1_1); + } + + /** + * User cannot exchange partition of tables without input required privilege + * @throws Exception + */ + @Test + public void testAlterTableExchangeNoPrivilegeOnInput() throws Exception { + final String PAR_ROLE_NAME = "config1_user_role"; + final String PAR_GROUP_NAME = USERGROUP1; + final String PAR_DB_NAME = "config1_test_database2"; + final String PAR_INPUT_TABLE_NAME = "aliens"; + final String PAR_OUTPUT_TABLE_NAME = "movie_stars"; + + establishSession(ADMIN1); + statement.execute("DROP DATABASE IF EXISTS " + PAR_DB_NAME + " CASCADE"); + statement.execute("CREATE DATABASE " + PAR_DB_NAME); + statement.execute("CREATE ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ROLE " + PAR_ROLE_NAME + " TO GROUP " + PAR_GROUP_NAME); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='earth', diet='milk shakes')"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='trapis-4', diet='sentient lifeforms with cheese')"); + + // grant propert privilege to output table + statement.execute("GRANT INSERT ON TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ALTER ON TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + + // move a partition from a source table to target table and alter each table's metadata. + // ALTER TABLE <dest_table> EXCHANGE PARTITION (<[partial] partition spec>) WITH TABLE <src_table> + String query = "ALTER TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " EXCHANGE PARTITION (home_planet='earth', diet='milk shakes') WITH TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME; + validateSemanticException(query, USER1_1); + } + + /** + * User cannot exchange partition of tables without output required privilege + * @throws Exception + */ + @Test + public void testAlterTableExchangeNoPrivilegeOnOutput() throws Exception { + final String PAR_ROLE_NAME = "config1_user_role"; + final String PAR_GROUP_NAME = USERGROUP1; + final String PAR_DB_NAME = "config1_test_database3"; + final String PAR_INPUT_TABLE_NAME = "aliens"; + final String PAR_OUTPUT_TABLE_NAME = "movie_stars"; + + establishSession(ADMIN1); + statement.execute("DROP DATABASE IF EXISTS " + PAR_DB_NAME + " CASCADE"); + statement.execute("CREATE DATABASE " + PAR_DB_NAME); + statement.execute("CREATE ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ROLE " + PAR_ROLE_NAME + " TO GROUP " + PAR_GROUP_NAME); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='earth', diet='milk shakes')"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='trapis-4', diet='sentient lifeforms with cheese')"); + + // grant propert privilege to input table + statement.execute("GRANT ALL ON TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + + // move a partition from a source table to target table and alter each table's metadata. + // ALTER TABLE <dest_table> EXCHANGE PARTITION (<[partial] partition spec>) WITH TABLE <src_table> + String query = "ALTER TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " EXCHANGE PARTITION (home_planet='earth', diet='milk shakes') WITH TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME; + validateSemanticException(query, USER1_1); + } + + /** + * User can exchange partition of tables with both input and output required privileges + * @throws Exception + */ + @Test + public void testAlterTableExchangeWithPrivilege() throws Exception { + final String PAR_ROLE_NAME = "config1_user_role"; + final String PAR_GROUP_NAME = USERGROUP1; + final String PAR_DB_NAME = "config1_test_database4"; + final String PAR_INPUT_TABLE_NAME = "aliens"; + final String PAR_OUTPUT_TABLE_NAME = "movie_stars"; + + establishSession(ADMIN1); + statement.execute("DROP DATABASE IF EXISTS " + PAR_DB_NAME + " CASCADE"); + statement.execute("CREATE DATABASE " + PAR_DB_NAME); + statement.execute("CREATE ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ROLE " + PAR_ROLE_NAME + " TO GROUP " + PAR_GROUP_NAME); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("CREATE TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " (name string) PARTITIONED BY (home_planet string, diet string)"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='earth', diet='milk shakes')"); + statement.execute("ALTER TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " ADD PARTITION (home_planet='trapis-4', diet='sentient lifeforms with cheese')"); + + // grant propert privilege to input table + statement.execute("GRANT ALL ON TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + // grant propert privilege to output table + statement.execute("GRANT INSERT ON TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + statement.execute("GRANT ALTER ON TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " TO ROLE " + PAR_ROLE_NAME); + + // move a partition from a source table to target table and alter each table's metadata. + // ALTER TABLE <dest_table> EXCHANGE PARTITION (<[partial] partition spec>) WITH TABLE <src_table> + String query = "ALTER TABLE " + PAR_DB_NAME + "." + PAR_OUTPUT_TABLE_NAME + " EXCHANGE PARTITION (home_planet='earth', diet='milk shakes') WITH TABLE " + PAR_DB_NAME + "." + PAR_INPUT_TABLE_NAME; + establishSession(USER1_1); + statement.execute(query); + } }
