You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sd...@apache.org on 2016/03/30 03:52:03 UTC
[07/13] sentry git commit: SENTRY-514: Enable e2e tests for
authorization V2 (Dapeng Sun, reviewed by Anne Yu)
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCrossDbOps.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCrossDbOps.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCrossDbOps.java
new file mode 100644
index 0000000..b123dcd
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCrossDbOps.java
@@ -0,0 +1,669 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/* Tests privileges at table scope with cross database access */
+
+public class TestCrossDbOps extends AbstractTestWithStaticConfiguration {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(TestCrossDbOps.class);
+
+ private File dataFile;
+ private PolicyFile policyFile;
+ private String loadData;
+
+ @BeforeClass
+ public static void setupTestStaticConfiguration() throws Exception{
+ LOGGER.info("TestCrossDbOps setupTestStaticConfiguration");
+ policyOnHdfs = true;
+ AbstractTestWithStaticConfiguration.setupTestStaticConfiguration();
+
+ }
+
+ @Before
+ public void setup() throws Exception {
+ LOGGER.info("TestCrossDbOps setup");
+ policyFile = super.setupPolicy();
+ super.setup();
+ File dataDir = context.getDataDir();
+ // copy data file to test dir
+ dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+ FileOutputStream to = new FileOutputStream(dataFile);
+ Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+ to.close();
+ loadData = "server=server1->uri=file://" + dataFile.getPath();
+ }
+
+ /*
+ * Admin creates DB_1, DB2, tables (tab_1 ) and (tab_2, tab_3) in DB_1 and
+ * DB_2 respectively. User user1 has select on DB_1.tab_1, insert on
+ * DB2.tab_2 User user2 has select on DB2.tab_3 Test show database and show
+ * tables for both user1 and user2
+ */
+ @Test
+ public void testShowDatabasesAndShowTables() throws Exception {
+ // admin create two databases
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("CREATE DATABASE " + DB1);
+ statement.execute("CREATE DATABASE " + DB2);
+ statement.execute("USE " + DB1);
+ statement.execute("CREATE TABLE TAB1(id int)");
+ statement.executeQuery("SHOW TABLES");
+ statement.execute("USE " + DB2);
+ statement.execute("CREATE TABLE TAB2(id int)");
+ statement.execute("CREATE TABLE TAB3(id int)");
+
+ // load policy file and grant role with privileges
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1", "server=server1->db=" + DB1 + "->table=tab1->action=select")
+ .addPermissionsToRole("select_tab3", "server=server1->db=" + DB2 + "->table=tab3->action=select")
+ .addPermissionsToRole("insert_tab2", "server=server1->db=" + DB2 + "->table=tab2->action=insert")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ // show grant to validate roles and privileges
+ if(useSentryService) {
+ PrivilegeResultSet pRset = new PrivilegeResultSet(statement, "SHOW GRANT ROLE select_tab1 ON DATABASE " + DB1);
+ LOGGER.info("SHOW GRANT ROLE select_tab1 ON DATABASE " + DB1 + " : " + pRset.toString());
+ pRset.verifyResultSetColumn("database", DB1);
+ pRset.verifyResultSetColumn("table", "tab1");
+
+ pRset = new PrivilegeResultSet(statement, "SHOW GRANT ROLE insert_tab2 ON DATABASE " + DB2);
+ LOGGER.info("SHOW GRANT ROLE insert_tab2 ON DATABASE " + DB2 + " : " + pRset.toString());
+ pRset.verifyResultSetColumn("database", DB2);
+ pRset.verifyResultSetColumn("table", "tab2");
+
+ pRset = new PrivilegeResultSet(statement, "SHOW GRANT ROLE select_tab3 ON DATABASE " + DB2);
+ LOGGER.info("SHOW GRANT ROLE select_tab3 ON DATABASE " + DB2 + " : " + pRset.toString());
+ pRset.verifyResultSetColumn("database", DB2);
+ pRset.verifyResultSetColumn("table", "tab3");
+ }
+
+ // test show databases
+ // show databases shouldn't filter any of the dbs from the resultset
+ Connection conn = context.createConnection(USER1_1);
+ Statement stmt = context.createStatement(conn);
+ PrivilegeResultSet pRset = new PrivilegeResultSet(stmt, "SHOW DATABASES");
+ LOGGER.info("found databases :" + pRset.toString());
+ pRset.verifyResultSetColumn("database_name", DB1);
+ pRset.verifyResultSetColumn("database_name", DB2);
+
+ // test show tables
+ stmt.execute("USE " + DB1);
+ pRset = new PrivilegeResultSet(stmt, "SHOW TABLES");
+ LOGGER.info("found tables :" + pRset.toString());
+ pRset.verifyResultSetColumn("tab_name", "tab1");
+
+ stmt.execute("USE " + DB2);
+ pRset = new PrivilegeResultSet(stmt, "SHOW TABLES");
+ LOGGER.info("found tables :" + pRset.toString());
+ pRset.verifyResultSetColumn("tab_name", "tab2");
+
+ try {
+ stmt.close();
+ conn.close();
+ } catch (Exception ex) {
+ // nothing to do
+ }
+
+ // test show databases and show tables for user2_1
+ conn = context.createConnection(USER2_1);
+ stmt = context.createStatement(conn);
+
+ pRset = new PrivilegeResultSet(stmt, "SHOW DATABASES");
+ pRset.verifyResultSetColumn("database_name", DB2);
+
+ // test show tables
+ stmt.execute("USE " + DB2);
+ pRset = new PrivilegeResultSet(stmt, "SHOW TABLES");
+ pRset.verifyResultSetColumn("tab_name", "tab3");
+
+ try {
+ stmt.execute("USE " + DB1);
+ Assert.fail("Expected SQL exception");
+ } catch (SQLException e) {
+ context.verifyAuthzException(e);
+ }
+
+ context.close();
+ }
+
+ /*
+ * Admin creates DB_1, DB2, tables (tab_1 ) and (tab_2, tab_3) in DB_1 and
+ * DB_2 respectively. User user1 has select on DB_1.tab_1, insert on
+ * DB2.tab_2 User user2 has select on DB2.tab_3 Test show database and show
+ * tables for both user1 and user2
+ */
+ @Test
+ public void testJDBCGetSchemasAndGetTables() throws Exception {
+ // admin create two databases
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("CREATE DATABASE " + DB1);
+ statement.execute("CREATE DATABASE " + DB2);
+ statement.execute("USE " + DB1);
+ statement.execute("CREATE TABLE TAB1(id int)");
+ statement.executeQuery("SHOW TABLES");
+ statement.execute("USE " + DB2);
+ statement.execute("CREATE TABLE TAB2(id int)");
+ statement.execute("CREATE TABLE TAB3(id int)");
+
+ // edit policy file
+ policyFile.addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1", "server=server1->db=" + DB1 + "->table=tab1->action=select")
+ .addPermissionsToRole("select_tab3", "server=server1->db=" + DB2 + "->table=tab3->action=select")
+ .addPermissionsToRole("insert_tab2", "server=server1->db=" + DB2 + "->table=tab2->action=insert")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ // test show databases
+ // show databases shouldn't filter any of the dbs from the resultset
+ Connection conn = context.createConnection(USER1_1);
+ Statement stmt = context.createStatement(conn);
+ // test direct JDBC metadata API
+ ResultSet res = stmt.executeQuery("SHOW DATABASES");
+ res = conn.getMetaData().getSchemas();
+ ResultSetMetaData resMeta = res.getMetaData();
+ assertEquals(2, resMeta.getColumnCount());
+ assertEquals("TABLE_SCHEM", resMeta.getColumnName(1));
+ assertEquals("TABLE_CATALOG", resMeta.getColumnName(2));
+
+ List<String> expectedResult = new ArrayList<String>();
+ List<String> returnedResult = new ArrayList<String>();
+
+ expectedResult.add(DB1);
+ expectedResult.add(DB2);
+ expectedResult.add("default");
+ while (res.next()) {
+ returnedResult.add(res.getString(1).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getTables(null, DB1, "tab%", null);
+ expectedResult.add("tab1");
+ while (res.next()) {
+ returnedResult.add(res.getString(3).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getTables(null, DB2, "tab%", null);
+ expectedResult.add("tab2");
+ while (res.next()) {
+ returnedResult.add(res.getString(3).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ res = conn.getMetaData().getTables(null, "DB%", "tab%", null);
+ expectedResult.add("tab2");
+ expectedResult.add("tab1");
+ while (res.next()) {
+ returnedResult.add(res.getString(3).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ //test show columns
+ res = conn.getMetaData().getColumns(null, "DB%", "tab%","i%" );
+ expectedResult.add("id");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ conn.close();
+
+ // test show databases and show tables for user2
+ conn = context.createConnection(USER2_1);
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getSchemas();
+ resMeta = res.getMetaData();
+ assertEquals(2, resMeta.getColumnCount());
+ assertEquals("TABLE_SCHEM", resMeta.getColumnName(1));
+ assertEquals("TABLE_CATALOG", resMeta.getColumnName(2));
+
+ expectedResult.add(DB2);
+ expectedResult.add("default");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(1).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ // test JDBC direct API
+ res = conn.getMetaData().getTables(null, "DB%", "tab%", null);
+ expectedResult.add("tab3");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(3).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+
+ //test show columns
+ res = conn.getMetaData().getColumns(null, "DB%", "tab%","i%" );
+ expectedResult.add("id");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ //test show columns
+ res = conn.getMetaData().getColumns(null, DB1, "tab%","i%" );
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4).trim());
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ returnedResult.clear();
+ expectedResult.clear();
+ res.close();
+
+ context.close();
+ }
+
+ /**
+ * 2.8 admin user create two database, DB_1, DB_2 admin grant all to USER1_1,
+ * USER1_2 on DB_1, admin grant all to user1's group, user2's group on DB_2
+ * positive test case: user1, user2 has ALL privilege on both DB_1 and DB_2
+ * negative test case: user1, user2 don't have ALL privilege on SERVER
+ */
+ @Test
+ public void testDbPrivileges() throws Exception {
+ createDb(ADMIN1, DB1, DB2);
+
+ // edit policy file
+ policyFile.addRolesToGroup(USERGROUP1, "db1_all,db2_all, load_data")
+ .addPermissionsToRole("db1_all", "server=server1->db=" + DB1)
+ .addPermissionsToRole("db2_all", "server=server1->db=" + DB2)
+ .addPermissionsToRole("load_data", "server=server1->URI=file://" + dataFile.getPath())
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ for (String user : new String[]{USER1_1, USER1_2}) {
+ for (String dbName : new String[]{DB1, DB2}) {
+ Connection userConn = context.createConnection(user);
+ String tabName = user + "_tab1";
+ Statement userStmt = context.createStatement(userConn);
+ // Positive case: test user1 and user2 has permissions to access
+ // db1 and
+ // db2
+ userStmt.execute("Use " + dbName);
+ userStmt
+ .execute("create table " + dbName + "." + tabName + " (id int)");
+ userStmt.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+ + "' INTO TABLE " + tabName);
+ userStmt.execute("select * from " + dbName + "." + tabName);
+ context.close();
+ }
+ }
+ }
+
+ /**
+ * Test Case 2.11 admin user create a new database DB_1 and grant ALL to
+ * himself on DB_1 should work
+ */
+ @Test
+ public void testAdminDbPrivileges() throws Exception {
+ createDb(ADMIN1, DB1);
+
+ policyFile
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection adminCon = context.createConnection(ADMIN1);
+ Statement adminStmt = context.createStatement(adminCon);
+ String tabName = DB1 + "." + "admin_tab1";
+ adminStmt.execute("create table " + tabName + "(c1 string)");
+ adminStmt.execute("load data local inpath '" + dataFile.getPath() + "' into table "
+ + tabName);
+ assertTrue(adminStmt.executeQuery("select * from " + tabName).next());
+ adminStmt.close();
+ adminCon.close();
+ }
+
+ /**
+ * Test Case 2.14 admin user create a new database DB_1 create TABLE_1 in DB_1
+ * admin user grant INSERT to user1's group on TABLE_1 negative test case:
+ * user1 try to do following on TABLE_1 will fail: --explain --analyze
+ * --describe --describe function --show columns --show table status --show
+ * table properties --show create table --show partitions --show indexes
+ * --select * from TABLE_1.
+ */
+ @Test
+ public void testNegativeUserPrivileges() throws Exception {
+ Connection adminCon = context.createConnection(ADMIN1);
+ Statement adminStmt = context.createStatement(adminCon);
+ adminStmt.execute("use default");
+ adminStmt.execute("CREATE DATABASE " + DB1);
+ adminStmt.execute("create table " + DB1 + ".table_1 (id int)");
+ adminStmt.execute("create table " + DB1 + ".table_2 (id int)");
+ adminStmt.close();
+ adminCon.close();
+
+ // edit policy file
+ policyFile.addRolesToGroup(USERGROUP1, "db1_tab1_insert", "db1_tab2_all")
+ .addPermissionsToRole("db1_tab2_all", "server=server1->db=" + DB1 + "->table=table_2")
+ .addPermissionsToRole("db1_tab1_insert", "server=server1->db=" + DB1 + "->table=table_1->action=insert")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection userConn = context.createConnection(USER1_1);
+ Statement userStmt = context.createStatement(userConn);
+ context.assertAuthzException(userStmt, "select * from " + DB1 + ".table_1");
+ userConn.close();
+ userStmt.close();
+ }
+
+ /**
+ * Test Case 2.16 admin user create a new database DB_1 create TABLE_1 and
+ * TABLE_2 (same schema) in DB_1 admin user grant SELECT, INSERT to user1's
+ * group on TABLE_2 negative test case: user1 try to do following on TABLE_1
+ * will fail: --insert overwrite TABLE_2 select * from TABLE_1
+ */
+ @Test
+ public void testNegativeUserDMLPrivileges() throws Exception {
+ createDb(ADMIN1, DB1);
+ Connection adminCon = context.createConnection(ADMIN1);
+ Statement adminStmt = context.createStatement(adminCon);
+ adminStmt.execute("create table " + DB1 + ".table_1 (id int)");
+ adminStmt.execute("create table " + DB1 + ".table_2 (id int)");
+ adminStmt.close();
+ adminCon.close();
+
+ policyFile
+ .addPermissionsToRole("db1_tab2_all", "server=server1->db=" + DB1 + "->table=table_2")
+ .addRolesToGroup(USERGROUP1, "db1_tab2_all")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection userConn = context.createConnection(USER1_1);
+ Statement userStmt = context.createStatement(userConn);
+ context.assertAuthzException(userStmt, "insert overwrite table " + DB1
+ + ".table_2 select * from " + DB1 + ".table_1");
+ context.assertAuthzException(userStmt, "insert overwrite directory '" + dataDir.getPath()
+ + "' select * from " + DB1 + ".table_1");
+ userStmt.close();
+ userConn.close();
+ }
+
+ /**
+ * Test Case 2.17 Execution steps
+ * a) Admin user creates a new database DB_1,
+ * b) Admin user grants ALL on DB_1 to group GROUP_1
+ * c) User from GROUP_1 creates table TAB_1, TAB_2 in DB_1
+ * d) Admin user grants SELECT on TAB_1 to group GROUP_2
+ *
+ * 1) verify users from GROUP_2 have only SELECT privileges on TAB_1. They
+ * shouldn't be able to perform any operation other than those listed as
+ * requiring SELECT in the privilege model.
+ *
+ * 2) verify users from GROUP_2 can't perform queries involving join between
+ * TAB_1 and TAB_2.
+ *
+ * 3) verify users from GROUP_1 can't perform operations requiring ALL @
+ * SERVER scope. Refer to list
+ */
+ @Test
+ public void testNegUserPrivilegesAll() throws Exception {
+ // create dbs
+ Connection adminCon = context.createConnection(ADMIN1);
+ Statement adminStmt = context.createStatement(adminCon);
+ adminStmt.execute("use default");
+ adminStmt.execute("drop table if exists table_def");
+ adminStmt.execute("create table table_def (name string)");
+ adminStmt
+ .execute("load data local inpath '" + dataFile.getPath() + "' into table table_def");
+
+ adminStmt.execute("CREATE DATABASE " + DB1);
+ adminStmt.execute("use " + DB1);
+
+ adminStmt.execute("create table table_1 (name string)");
+ adminStmt
+ .execute("load data local inpath '" + dataFile.getPath() + "' into table table_1");
+ adminStmt.execute("create table table_2 (name string)");
+ adminStmt
+ .execute("load data local inpath '" + dataFile.getPath() + "' into table table_2");
+ adminStmt.execute("create view v1 AS select * from table_1");
+ adminStmt
+ .execute("create table table_part_1 (name string) PARTITIONED BY (year INT)");
+ adminStmt.execute("ALTER TABLE table_part_1 ADD PARTITION (year = 2012)");
+
+ adminStmt.close();
+ adminCon.close();
+
+ policyFile
+ .addRolesToGroup(USERGROUP1, "db1_all")
+ .addRolesToGroup(USERGROUP2, "db1_tab1_select")
+ .addPermissionsToRole("db1_all", "server=server1->db=" + DB1)
+ .addPermissionsToRole("db1_tab1_select", "server=server1->db=" + DB1 + "->table=table_1->action=select")
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection userConn = context.createConnection(USER2_1);
+ Statement userStmt = context.createStatement(userConn);
+
+ context.assertAuthzException(userStmt, "drop database " + DB1);
+
+ // Hive currently doesn't support cross db index DDL
+
+ context.assertAuthzException(userStmt, "CREATE TEMPORARY FUNCTION strip AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+ context.assertAuthzException(userStmt, "create table " + DB1
+ + ".c_tab_2 as select * from " + DB1 + ".table_2");
+ context.assertAuthzException(userStmt, "select * from " + DB1 + ".table_2");
+ context.assertAuthzException(userStmt, "ALTER DATABASE " + DB1
+ + " SET DBPROPERTIES ('foo' = 'bar')");
+ context.assertAuthzException(userStmt, "drop table " + DB1 + ".table_1");
+ context.assertAuthzException(userStmt, "DROP VIEW IF EXISTS " + DB1 + ".v1");
+ context.assertAuthzException(userStmt, "create table " + DB1 + ".table_5 (name string)");
+ context.assertAuthzException(userStmt, "ALTER TABLE " + DB1 + ".table_1 RENAME TO "
+ + DB1 + ".table_99");
+ context.assertAuthzException(userStmt, "insert overwrite table " + DB1
+ + ".table_2 select * from " + DB1 + ".table_1");
+ context.assertAuthzException(userStmt, "insert overwrite table " + DB1
+ + ".table_2 select * from " + "table_def");
+ context.assertAuthzException(userStmt, "ALTER TABLE " + DB1
+ + ".table_part_1 ADD IF NOT EXISTS PARTITION (year = 2012)");
+ context.assertAuthzException(userStmt, "ALTER TABLE " + DB1
+ + ".table_part_1 PARTITION (year = 2012) SET LOCATION '/etc'");
+ userStmt.close();
+ userConn.close();
+ }
+
+ /**
+ * Steps: 1. admin user create databases, DB_1 and DB_2, no table or other
+ * object in database
+ * 2. admin grant all to user1's group on DB_1 and DB_2
+ * positive test case:
+ * a)user1 has the privilege to create table, load data,
+ * drop table, create view, insert more data on both databases
+ * b) user1 can switch between DB_1 and DB_2 without exception
+ * negative test case:
+ * c) user1 cannot drop database
+ */
+ @Test
+ public void testSandboxOpt9() throws Exception {
+ createDb(ADMIN1, DB1, DB2);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, ALL_DB1, ALL_DB2, loadData)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection connection = context.createConnection(USER1_1);
+ Statement statement = context.createStatement(connection);
+
+ // a
+ statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + TBL1);
+ statement.execute("create table " + DB1 + "." + TBL1
+ + " (under_col int comment 'the under column', value string)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + DB1 + "." + TBL1);
+ statement.execute("DROP VIEW IF EXISTS " + DB1 + "." + VIEW1);
+ statement.execute("CREATE VIEW " + DB1 + "." + VIEW1
+ + " (value) AS SELECT value from " + DB1 + "." + TBL1
+ + " LIMIT 10");
+ statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + TBL1);
+ statement.execute("CREATE TABLE " + DB2 + "." + TBL1
+ + " AS SELECT value from " + DB1 + "." + TBL1
+ + " LIMIT 10");
+
+ // b
+ statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + TBL2);
+ statement.execute("create table " + DB2 + "." + TBL2
+ + " (under_col int comment 'the under column', value string)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + DB2 + "." + TBL2);
+ statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + TBL3);
+ statement.execute("create table " + DB2 + "." + TBL3
+ + " (under_col int comment 'the under column', value string)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + DB2 + "." + TBL3);
+
+ policyFile.removePermissionsFromRole(GROUP1_ROLE, ALL_DB2);
+ writePolicyFile(policyFile);
+ // create db1.view1 as select from db2.tbl2
+ statement.execute("DROP VIEW IF EXISTS " + DB1 + "." + VIEW2);
+ context.assertAuthzException(statement, "CREATE VIEW " + DB1 + "." + VIEW2 +
+ " (value) AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+ // create db1.tbl2 as select from db2.tbl2
+ statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + TBL2);
+ context.assertAuthzException(statement, "CREATE TABLE " + DB1 + "." + TBL2 +
+ " AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Steps: 1. admin user create databases, DB_1 and DB_2, no table or other
+ * object in database positive test case:
+ * d) user1 has the privilege to create view on tables in DB_1 negative test case:
+ * e) user1 cannot create view in DB_1 that select from tables in DB_2
+ * with no select privilege 2.
+ * positive test case:
+ * f) user1 has the privilege to create view to select from DB_1.tb_1
+ * and DB_2.tb_2 negative test case:
+ * g) user1 cannot create view to select from DB_1.tb_1 and DB_2.tb_3
+ */
+ @Test
+ public void testCrossDbViewOperations() throws Exception {
+ // admin create two databases
+ createDb(ADMIN1, DB1, DB2);
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement
+ .execute("CREATE TABLE " + DB1 + "." + TBL1 + "(id int)");
+ statement
+ .execute("CREATE TABLE " + DB2 + "." + TBL1 + "(id int)");
+ statement
+ .execute("CREATE TABLE " + DB2 + "." + TBL2 + "(id int)");
+ context.close();
+
+ // edit policy file
+ policyFile
+ .addRolesToGroup(USERGROUP1, "all_db1", "load_data", "select_tb2")
+ .addPermissionsToRole("all_db1", "server=server1->db=" + DB1)
+ .addPermissionsToRole("all_db2", "server=server1->db=" + DB2)
+ .addPermissionsToRole("select_tb2", "server=server1->db=" + DB2 + "->table=tb_1->action=select")
+ .addPermissionsToRole("load_data", "server=server1->URI=file://" + dataFile.getPath())
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+
+ // d
+ statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + TBL1);
+ statement.execute("create table " + DB1 + "." + TBL1
+ + " (under_col int comment 'the under column', value string)");
+
+ // e
+ statement.execute("DROP VIEW IF EXISTS " + DB1 + "." + VIEW1);
+ context.assertAuthzException(statement, "CREATE VIEW " + DB1 + "." + VIEW1
+ + " (value) AS SELECT value from " + DB2 + "." + TBL2
+ + " LIMIT 10");
+ // f
+ statement.execute("DROP VIEW IF EXISTS " + DB1 + "." + VIEW2);
+ statement.execute("CREATE VIEW " + DB1 + "." + VIEW2
+ + " (value) AS SELECT value from " + DB1 + "." + TBL1
+ + " LIMIT 10");
+
+ // g
+ statement.execute("DROP VIEW IF EXISTS " + DB1 + "." + VIEW3);
+ context.assertAuthzException(statement, "CREATE VIEW " + DB1 + "." + VIEW3
+ + " (value) AS SELECT value from " + DB2 + "." + TBL2
+ + " LIMIT 10");
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCustomSerdePrivileges.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCustomSerdePrivileges.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCustomSerdePrivileges.java
new file mode 100644
index 0000000..2851ed6
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestCustomSerdePrivileges.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import com.google.common.collect.Maps;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.security.CodeSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map;
+
+public class TestCustomSerdePrivileges extends AbstractTestWithHiveServer {
+ private static Context context;
+ private static Map<String, String> properties;
+ private PolicyFile policyFile;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ properties = Maps.newHashMap();
+
+ // Start the Hive Server without buildin Serde, such as
+ // "org.apache.hadoop.hive.serde2.OpenCSVSerde". Instead,
+ // used a bogus class name for testing.
+ properties.put(HiveAuthzConf.HIVE_SENTRY_SERDE_WHITELIST, "org.example.com");
+ properties.put(HiveAuthzConf.HIVE_SENTRY_SERDE_URI_PRIVILIEGES_ENABLED, "true");
+ properties.put(HiveConf.ConfVars.METASTORE_AUTO_CREATE_ALL.varname, "true");
+ context = createContext(properties);
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ if(context != null) {
+ context.close();
+ }
+ }
+
+ @Before
+ public void setupPolicyFile() throws Exception {
+ policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP);
+ }
+
+ /**
+ * User with db level access and Uri privileges on the Serde Jar should be able
+ * to create tables with Serde.
+ * User with db level access but without Uri privileges on the Serde Jar will fail
+ * on creating tables with Serde.
+ */
+ @Test
+ public void testSerdePrivilegesWithoutBuildinJar() throws Exception {
+ String db = "db1";
+ String tableName1 = "tab1";
+
+ String serdeClassName = "org.apache.hadoop.hive.serde2.OpenCSVSerde";
+ CodeSource serdeSrc = Class.forName(serdeClassName).getProtectionDomain().getCodeSource();
+ String serdeLocation = serdeSrc.getLocation().getPath();
+
+ policyFile
+ .addRolesToGroup(USERGROUP1, "db1_all")
+ .addRolesToGroup(USERGROUP2, "db1_all", "SERDE_JAR")
+ .addPermissionsToRole("db1_all", "server=server1->db=" + db)
+ .addPermissionsToRole("db1_tab1", "server=server1->db=" + db + "->table=" + tableName1)
+ .addPermissionsToRole("SERDE_JAR", "server=server1->uri=file://" + serdeLocation)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ policyFile.write(context.getPolicyFile());
+
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("DROP DATABASE IF EXISTS " + db + " CASCADE");
+ statement.execute("CREATE DATABASE " + db);
+ context.close();
+
+ // User1 does not have the URI privileges to use the Serde Jar.
+ // The table creation will fail.
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + db);
+ try {
+ statement.execute("create table " + db + "." + tableName1 + " (a string, b string) " +
+ "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' " + " STORED AS TEXTFILE");
+ Assert.fail("Expect create table with Serde to fail");
+ } catch (SQLException e) {
+ context.verifyAuthzException(e);
+ }
+ context.close();
+
+ // User2 has the URI privileges to use the Serde Jar.
+ // The table creation will succeed.
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + db);
+ statement.execute("create table " + db + "." + tableName1 + " (a string, b string) ROW FORMAT" +
+ " SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' " + " STORED AS TEXTFILE");
+ context.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestEndToEnd.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestEndToEnd.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestEndToEnd.java
new file mode 100644
index 0000000..23577c2
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestEndToEnd.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.Statement;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+public class TestEndToEnd extends AbstractTestWithStaticConfiguration {
+ private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+ private File dataFile;
+ private PolicyFile policyFile;
+
+
+ @Before
+ public void setup() throws Exception {
+ dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+ FileOutputStream to = new FileOutputStream(dataFile);
+ Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+ to.close();
+ policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP);
+
+ }
+
+ /**
+ * Steps:
+ * 1. admin create a new experimental database
+ * 2. admin create a new production database, create table, load data
+ * 3. admin grant privilege all@'experimental database' to usergroup1
+ * 4. user create table, load data in experimental DB
+ * 5. user create view based on table in experimental DB
+ * 6. admin create table (same name) in production DB
+ * 7. admin grant read@productionDB.table to group
+ * admin grant select@productionDB.table to group
+ * 8. user load data from experimental table to production table
+ */
+ @Test
+ public void testEndToEnd1() throws Exception {
+ policyFile
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+ String tableName1 = "tb_1";
+ String tableName2 = "tb_2";
+ String viewName1 = "view_1";
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ // 1
+ statement.execute("DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+ statement.execute("CREATE DATABASE " + DB1);
+ // 2
+ statement.execute("DROP DATABASE IF EXISTS " + DB2 + " CASCADE");
+ statement.execute("CREATE DATABASE " + DB2);
+ statement.execute("USE " + DB2);
+ statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + tableName2);
+ statement.execute("create table " + DB2 + "." + tableName2
+ + " (under_col int comment 'the under column', value string)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + tableName2);
+ statement.close();
+ connection.close();
+
+ // 3
+ policyFile
+ .addRolesToGroup(USERGROUP1, "all_db1", "data_uri", "select_tb1", "insert_tb1")
+ .addPermissionsToRole("all_db1", "server=server1->db=" + DB1)
+ .addPermissionsToRole("select_tb1", "server=server1->db=" + DB2 + "->table=tb_1->action=select")
+ .addPermissionsToRole("insert_tb2", "server=server1->db=" + DB2 + "->table=tb_2->action=insert")
+ .addPermissionsToRole("insert_tb1", "server=server1->db=" + DB2 + "->table=tb_2->action=insert")
+ .addPermissionsToRole("data_uri", "server=server1->uri=file://" + dataDir.getPath());
+ writePolicyFile(policyFile);
+
+ // 4
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + tableName1);
+ statement.execute("create table " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column', value string)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + tableName1);
+ // 5
+ statement.execute("CREATE VIEW " + viewName1 + " (value) AS SELECT value from " + tableName1 + " LIMIT 10");
+ statement.close();
+ connection.close();
+
+ // 7
+ connection = context.createConnection(ADMIN1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + DB2);
+ statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + tableName1);
+ statement.execute("create table " + DB1 + "." + tableName1
+ + " (under_col int comment 'the under column', value string)");
+ statement.close();
+ connection.close();
+
+ // 8
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + DB2);
+ statement.execute("INSERT OVERWRITE TABLE " +
+ DB2 + "." + tableName2 + " SELECT * FROM " + DB1
+ + "." + tableName1);
+ statement.close();
+ connection.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestExportImportPrivileges.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestExportImportPrivileges.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestExportImportPrivileges.java
new file mode 100644
index 0000000..5242bb1
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestExportImportPrivileges.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sentry.tests.e2e.hive;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.Statement;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestExportImportPrivileges extends AbstractTestWithStaticConfiguration {
+ private static final Logger LOGGER = LoggerFactory.
+ getLogger(TestExportImportPrivileges.class);
+ private File dataFile;
+ private PolicyFile policyFile;
+
+ @BeforeClass
+ public static void setupTestStaticConfiguration () throws Exception {
+ LOGGER.info("TestExportImportPrivileges setupTestStaticConfiguration");
+ AbstractTestWithStaticConfiguration.setupTestStaticConfiguration();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ LOGGER.info("TestExportImportPrivileges setup");
+ policyFile = super.setupPolicy();
+ super.setup();
+ dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+ FileOutputStream to = new FileOutputStream(dataFile);
+ Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+ to.close();
+ }
+
+ @Test
+ public void testInsertToDirPrivileges() throws Exception {
+ Connection connection = null;
+ Statement statement = null;
+ String dumpDir = dfs.getBaseDir() + "/hive_data_dump";
+
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+
+ policyFile
+ .addRolesToGroup(USERGROUP1, "db1_read", "db1_write", "data_dump")
+ .addRolesToGroup(USERGROUP2, "db1_read", "db1_write")
+ .addPermissionsToRole("db1_write", "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=INSERT")
+ .addPermissionsToRole("db1_read", "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=SELECT")
+ .addPermissionsToRole("data_dump", "server=server1->URI=" + dumpDir);
+ writePolicyFile(policyFile);
+
+ // Negative test, user2 doesn't have access to write to dir
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ context.assertAuthzException(statement, "INSERT OVERWRITE DIRECTORY '" + dumpDir + "' SELECT * FROM " + TBL1);
+ statement.close();
+ connection.close();
+
+ // Negative test, user2 doesn't have access to dir that's similar to scratch dir
+ String scratchLikeDir = context.getProperty(HiveConf.ConfVars.SCRATCHDIR.varname) + "_foo";
+ dfs.assertCreateDir(scratchLikeDir);
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ context.assertAuthzException(statement, "INSERT OVERWRITE DIRECTORY '" + scratchLikeDir + "/bar' SELECT * FROM " + TBL1);
+ statement.close();
+ connection.close();
+
+ // positive test, user1 has access to write to dir
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ assertTrue(statement.executeQuery("SELECT * FROM " + TBL1).next());
+ statement.execute("INSERT OVERWRITE DIRECTORY '" + dumpDir + "' SELECT * FROM " + TBL1);
+ }
+
+ @Test
+ public void testExportImportPrivileges() throws Exception {
+ Connection connection = null;
+ Statement statement = null;
+ String exportDir = dfs.getBaseDir() + "/hive_export1";
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+
+ policyFile
+ .addRolesToGroup(USERGROUP1, "tab1_read", "tab1_write", "db1_all", "data_read", "data_export")
+ .addRolesToGroup(USERGROUP2, "tab1_write", "tab1_read")
+ .addRolesToGroup(USERGROUP3, "col1_read")
+ .addPermissionsToRole("tab1_write", "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=INSERT")
+ .addPermissionsToRole("tab1_read", "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=SELECT")
+ .addPermissionsToRole("col1_read", "server=server1->db=" + DB1 + "->table=" + TBL1 + "->column=under_col->action=SELECT")
+ .addPermissionsToRole("db1_all", "server=server1->db=" + DB1)
+ .addPermissionsToRole("data_read", "server=server1->URI=file://" + dataFile.getPath())
+ .addPermissionsToRole("data_export", "server=server1->URI=" + exportDir);
+ writePolicyFile(policyFile);
+
+ // Negative test, user2 doesn't have access to the file being loaded
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ context.assertAuthzException(statement, "EXPORT TABLE " + TBL1 + " TO '" + exportDir + "'");
+ statement.close();
+ connection.close();
+
+ // Positive test, user1 have access to the target directory
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ statement.execute("EXPORT TABLE " + TBL1 + " TO '" + exportDir + "'");
+ statement.close();
+ connection.close();
+
+ // Negative test, user2 doesn't have access to the directory loading from
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ context.assertAuthzException(statement, "IMPORT TABLE " + TBL2 + " FROM '" + exportDir + "'");
+ statement.close();
+ connection.close();
+
+ // Positive test, user1 have access to the target directory
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ statement.execute("IMPORT TABLE " + TBL2 + " FROM '" + exportDir + "'");
+ statement.close();
+ connection.close();
+
+ // Positive test, user3 have access to the target directory
+ connection = context.createConnection(USER3_1);
+ statement = context.createStatement(connection);
+ statement.execute("use " + DB1);
+ statement.execute("SELECT under_col FROM " + TBL1);
+ statement.close();
+ connection.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestJDBCInterface.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestJDBCInterface.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestJDBCInterface.java
new file mode 100644
index 0000000..bc5c08b
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestJDBCInterface.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestJDBCInterface extends AbstractTestWithStaticConfiguration {
+ private static final Logger LOGGER = LoggerFactory.
+ getLogger(TestJDBCInterface.class);
+ private static PolicyFile policyFile;
+
+ @BeforeClass
+ public static void setupTestStaticConfiguration() throws Exception {
+ LOGGER.info("TestJDBCInterface setupTestStaticConfiguration");
+ policyOnHdfs = true;
+ AbstractTestWithStaticConfiguration.setupTestStaticConfiguration();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ LOGGER.info("TestJDBCInterface setup");
+ policyFile = super.setupPolicy();
+ super.setup();
+ }
+
+ /*
+ * Admin creates DB_1, DB2, tables (tab_1 ) and (tab_2, tab_3) in DB_1 and
+ * DB_2 respectively. User user1 has select on DB_1.tab_1, insert on
+ * DB2.tab_2 User user2 has select on DB2.tab_3 Test show database and show
+ * tables for both user1 and user2
+ */
+ @Test
+ public void testJDBCGetSchemasAndGetTables() throws Exception {
+ // admin create two databases
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+ statement.execute("DROP DATABASE IF EXISTS DB_2 CASCADE");
+ statement.execute("DROP DATABASE IF EXISTS DB1 CASCADE");
+ statement.execute("DROP DATABASE IF EXISTS DB2 CASCADE");
+
+ statement.execute("CREATE DATABASE " + DB1);
+ statement.execute("CREATE DATABASE " + DB2);
+ statement.execute("USE " + DB1);
+ statement.execute("CREATE TABLE TAB1(id int)");
+ statement.executeQuery("SHOW TABLES");
+ statement.execute("USE " + DB2);
+ statement.execute("CREATE TABLE TAB2(id int)");
+ statement.execute("CREATE TABLE TAB3(id int)");
+
+ // edit policy file
+ policyFile
+ .addRolesToGroup(USERGROUP1, "select_tab1", "insert_tab2")
+ .addRolesToGroup(USERGROUP2, "select_tab3")
+ .addPermissionsToRole("select_tab1",
+ "server=server1->db=" + DB1 + "->table=tab1->action=select")
+ .addPermissionsToRole("select_tab3",
+ "server=server1->db=" + DB2 + "->table=tab3->action=select")
+ .addPermissionsToRole("insert_tab2",
+ "server=server1->db=" + DB2 + "->table=tab2->action=insert");
+ writePolicyFile(policyFile);
+
+ // test show databases
+ // show databases shouldn't filter any of the dbs from the resultset
+ Connection conn = context.createConnection(USER1_1);
+ List<String> expectedResult = new ArrayList<String>();
+ List<String> returnedResult = new ArrayList<String>();
+
+ // test direct JDBC metadata API
+ ResultSet res = conn.getMetaData().getSchemas();
+ ResultSetMetaData resMeta = res.getMetaData();
+ assertEquals(2, resMeta.getColumnCount());
+ assertEquals("TABLE_SCHEM", resMeta.getColumnName(1));
+ assertEquals("TABLE_CATALOG", resMeta.getColumnName(2));
+
+ expectedResult.add(DB1);
+ expectedResult.add(DB2);
+ expectedResult.add("default");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(1));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getTables(null, DB1, "tab%", null);
+ expectedResult.add("tab1");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(3));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getTables(null, DB2, "tab%", null);
+ expectedResult.add("tab2");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(3));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ res = conn.getMetaData().getTables(null, "DB%", "tab%", null);
+ expectedResult.add("tab2");
+ expectedResult.add("tab1");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(3));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test show columns
+ res = conn.getMetaData().getColumns(null, "DB%", "tab%", "i%");
+ expectedResult.add("id");
+ expectedResult.add("id");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ conn.close();
+
+ // test show databases and show tables for user2
+ conn = context.createConnection(USER2_1);
+
+ // test direct JDBC metadata API
+ res = conn.getMetaData().getSchemas();
+ resMeta = res.getMetaData();
+ assertEquals(2, resMeta.getColumnCount());
+ assertEquals("TABLE_SCHEM", resMeta.getColumnName(1));
+ assertEquals("TABLE_CATALOG", resMeta.getColumnName(2));
+
+ expectedResult.add(DB2);
+ expectedResult.add("default");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(1));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test JDBC direct API
+ res = conn.getMetaData().getTables(null, "DB%", "tab%", null);
+ expectedResult.add("tab3");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(3));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test show columns
+ res = conn.getMetaData().getColumns(null, "DB%", "tab%", "i%");
+ expectedResult.add("id");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4));
+ }
+ validateReturnedResult(expectedResult, returnedResult);
+ expectedResult.clear();
+ returnedResult.clear();
+ res.close();
+
+ // test show columns
+ res = conn.getMetaData().getColumns(null, DB1, "tab%", "i%");
+
+ while (res.next()) {
+ returnedResult.add(res.getString(4));
+ }
+ assertTrue("returned result shouldn't contain any value, actually returned result = " + returnedResult.toString(),
+ returnedResult.isEmpty());
+ res.close();
+
+ context.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java
new file mode 100644
index 0000000..0e403d8
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestLockPrivileges.java
@@ -0,0 +1,214 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestLockPrivileges extends AbstractTestWithStaticConfiguration {
+ private PolicyFile policyFile;
+ final String tableName = "tb1";
+
+ static Map<String, String> privileges = new HashMap<String, String>();
+ static {
+ privileges.put("all_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=all");
+ privileges.put("select_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=select");
+ privileges.put("insert_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=insert");
+ privileges.put("alter_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=alter");
+ privileges.put("lock_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=lock");
+
+ privileges.put("all_db1", "server=server1->db=" + DB1 + "->action=all");
+ privileges.put("select_db1", "server=server1->db=" + DB1 + "->action=select");
+ privileges.put("insert_db1", "server=server1->db=" + DB1 + "->action=insert");
+ privileges.put("alter_db1", "server=server1->db=" + DB1 + "->action=alter");
+ privileges.put("lock_db1", "server=server1->db=" + DB1 + "->action=lock");
+ }
+
+ @BeforeClass
+ public static void setHiveConcurrency() throws Exception {
+ enableHiveConcurrency = true;
+ setupTestStaticConfiguration();
+ }
+
+ private void adminCreate(String db, String table) throws Exception {
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("DROP DATABASE IF EXISTS " + db + " CASCADE");
+ statement.execute("CREATE DATABASE " + db);
+ if (table != null) {
+ statement.execute("CREATE table " + db + "." + table + " (a string)");
+ }
+ statement.close();
+ connection.close();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP).setUserGroupMapping(
+ StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+ }
+
+ @Test
+ public void testLockDatabase() throws Exception {
+ String partialErrorMsgForNoPrivilege = "No valid privileges";
+ String assertErrorException = "The exception is not the same as the expectation.";
+ String assertExceptionThrown = "SQLException will be thrown.";
+
+ adminCreate(DB1, null);
+ policyFile.addPermissionsToRole("lock_db1", privileges.get("lock_db1"))
+ .addRolesToGroup(USERGROUP1, "lock_db1")
+ .addPermissionsToRole("insert_db1", privileges.get("insert_db1"))
+ .addRolesToGroup(USERGROUP2, "insert_db1")
+ .addPermissionsToRole("select_db1", privileges.get("select_db1"))
+ .addRolesToGroup(USERGROUP2, "select_db1")
+ .addPermissionsToRole("alter_db1", privileges.get("alter_db1"))
+ .addRolesToGroup(USERGROUP2, "alter_db1")
+ .addPermissionsToRole("all_db1", privileges.get("all_db1"))
+ .addRolesToGroup(USERGROUP3, "all_db1");
+ writePolicyFile(policyFile);
+
+ // user1 has lock privilege only
+ Connection connection = context.createConnection(USER1_1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ statement.execute("LOCK DATABASE db_1 SHARED");
+ try {
+ statement.execute("UNLOCK DATABASE db_1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is successful.
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1);
+ }
+
+ // user2 has privileges with insert, select, alter, but has no lock privilege
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ try {
+ statement.execute("LOCK DATABASE db_1 SHARED");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is failed, the error message include "No valid privileges"
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0);
+ }
+ try {
+ statement.execute("UNLOCK DATABASE db_1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is failed, the error message include "No valid privileges"
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0);
+ }
+
+ // user3 has All privilege
+ connection = context.createConnection(USER3_1);
+ statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ statement.execute("LOCK DATABASE db_1 SHARED");
+ try {
+ statement.execute("UNLOCK DATABASE db_1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is successful.
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1);
+ }
+ statement.close();
+ connection.close();
+ }
+
+ @Test
+ public void testLockTable() throws Exception {
+ String partialErrorMsgForNoPrivilege = "No valid privileges";
+ String assertErrorException = "The exception is not the same as the expectation.";
+ String assertExceptionThrown = "SQLException will be thrown.";
+
+ adminCreate(DB1, tableName);
+ policyFile.addPermissionsToRole("lock_db1_tb1", privileges.get("lock_db1_tb1"))
+ .addRolesToGroup(USERGROUP1, "lock_db1_tb1")
+ .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1"))
+ .addRolesToGroup(USERGROUP2, "insert_db1_tb1")
+ .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1"))
+ .addRolesToGroup(USERGROUP2, "select_db1_tb1")
+ .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1"))
+ .addRolesToGroup(USERGROUP2, "alter_db1_tb1")
+ .addPermissionsToRole("all_db1_tb1", privileges.get("all_db1_tb1"))
+ .addRolesToGroup(USERGROUP3, "all_db1_tb1");
+ writePolicyFile(policyFile);
+
+ // user1 has lock privilege only
+ Connection connection = context.createConnection(USER1_1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ statement.execute("LOCK TABLE tb1 SHARED");
+ try {
+ statement.execute("UNLOCK TABLE tb1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is successful.
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1);
+ }
+
+ // user2 has privileges with insert, select, alter, but has no lock privilege
+ connection = context.createConnection(USER2_1);
+ statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ try {
+ statement.execute("LOCK TABLE tb1 SHARED");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is failed, the error message include "No valid privileges"
+ assertTrue(assertErrorException,
+ se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0);
+ }
+ try {
+ statement.execute("UNLOCK TABLE tb1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is failed, the error message include "No valid privileges"
+ assertTrue(assertErrorException,
+ se.getMessage().indexOf(partialErrorMsgForNoPrivilege) > 0);
+ }
+
+ // user3 has All privilege
+ connection = context.createConnection(USER3_1);
+ statement = context.createStatement(connection);
+ statement.execute("Use " + DB1);
+ statement.execute("LOCK TABLE tb1 SHARED");
+ try {
+ statement.execute("UNLOCK TABLE tb1");
+ fail(assertExceptionThrown);
+ } catch (SQLException se) {
+ // Authorization is successful.
+ assertTrue(assertErrorException, se.getMessage().indexOf(partialErrorMsgForNoPrivilege) == -1);
+ }
+ statement.close();
+ connection.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataObjectRetrieval.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataObjectRetrieval.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataObjectRetrieval.java
new file mode 100644
index 0000000..3c23dc4
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataObjectRetrieval.java
@@ -0,0 +1,501 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.sentry.tests.e2e.hive;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestMetadataObjectRetrieval extends AbstractTestWithStaticConfiguration {
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(TestMetadataObjectRetrieval.class);
+ private PolicyFile policyFile;
+ private File dataFile;
+
+ @BeforeClass
+ public static void setupTestStaticConfiguration () throws Exception {
+ LOGGER.info("TestMetadataObjectRetrieval setupTestStaticConfiguration");
+ AbstractTestWithStaticConfiguration.setupTestStaticConfiguration();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ LOGGER.info("TestMetadataObjectRetrieval setup");
+ policyFile = super.setupPolicy();
+ super.setup();
+ dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+ FileOutputStream to = new FileOutputStream(dataFile);
+ Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+ to.close();
+ }
+
+ /**
+ * Method called to run positive tests:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * The table is assumed to have two columns under_col int and value string.
+ */
+ private void positiveDescribeShowTests(String user, String db, String table) throws Exception {
+ Connection connection = context.createConnection(user);
+ Statement statement = context.createStatement(connection);
+ statement.execute("USE " + db);
+ ResultSet rs = statement.executeQuery("DESCRIBE " + table);
+ assertTrue(rs.next());
+
+ assertTrue("describe table fail", rs.getString(1).trim().equals("under_col"));
+ assertTrue("describe table fail", rs.getString(2).trim().equals("int"));
+ assertTrue(rs.next());
+ assertTrue("describe table fail", rs.getString(1).trim().equals("value"));
+ assertTrue("describe table fail", rs.getString(2).trim().equals("string"));
+
+ rs = statement.executeQuery("DESCRIBE " + table + " under_col");
+ assertTrue(rs.next());
+ assertTrue("describe table fail", rs.getString(1).trim().equals("under_col"));
+ assertTrue("describe table fail", rs.getString(2).trim().equals("int"));
+
+ rs = statement.executeQuery("DESCRIBE " + table + " value");
+ assertTrue(rs.next());
+ assertTrue("describe table fail", rs.getString(1).trim().equals("value"));
+ assertTrue("describe table fail", rs.getString(2).trim().equals("string"));
+
+ rs = statement.executeQuery("DESCRIBE EXTENDED " + table);
+ assertTrue(rs.next());
+ assertTrue(rs.getString(1), rs.getString(1).contains("under_col"));
+ assertTrue(rs.getString(2), rs.getString(2).contains("int"));
+ assertTrue(rs.next());
+ assertTrue(rs.getString(1), rs.getString(1).contains("value"));
+ assertTrue(rs.getString(2), rs.getString(2).contains("string"));
+ assertTrue(rs.next());
+
+ rs = statement.executeQuery("DESCRIBE FORMATTED " + table);
+ // Skip the header
+ assertTrue(rs.next());
+ assertTrue(rs.next());
+ assertTrue(rs.next());
+ assertTrue(rs.getString(1), rs.getString(1).contains("under_col"));
+ assertTrue(rs.getString(2), rs.getString(2).contains("int"));
+ assertTrue(rs.next());
+ assertTrue(rs.getString(1), rs.getString(1).contains("value"));
+ assertTrue(rs.getString(2), rs.getString(2).contains("string"));
+ assertTrue(rs.next());
+
+ rs = statement.executeQuery("SHOW COLUMNS FROM " + table);
+ assertTrue(rs.next());
+ assertTrue("show columns from fail", rs.getString(1).trim().equals("under_col"));
+ assertTrue(rs.next());
+ assertTrue("show columns from fail", rs.getString(1).trim().equals("value"));
+
+ rs = statement.executeQuery("SHOW CREATE TABLE " + table);
+ assertTrue("SHOW CREATE TABLE fail", rs.next());
+
+ rs = statement.executeQuery("SHOW TBLPROPERTIES " + table);
+ assertTrue("SHOW TBLPROPERTIES fail", rs.next());
+
+ statement.close();
+ connection.close();
+ }
+ /**
+ * Method called to run negative tests:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * The table is assumed to have two columns under_col int and value string.
+ */
+ private void negativeDescribeShowTests(String user, String db, String table) throws Exception {
+ Connection connection = context.createConnection(user);
+ Statement statement = context.createStatement(connection);
+ statement.execute("USE " + db);
+ context.assertAuthzException(statement, "DESCRIBE " + table + " under_col");
+ context.assertAuthzException(statement, "DESCRIBE " + table + " value");
+ context.assertAuthzException(statement, "DESCRIBE FORMATTED " + table);
+ context.assertAuthzException(statement, "DESCRIBE EXTENDED " + table);
+ context.assertAuthzException(statement, "SHOW COLUMNS FROM " + table);
+ context.assertAuthzException(statement, "SHOW CREATE TABLE " + table);
+ context.assertAuthzException(statement, "SHOW TBLPROPERTIES " + table);
+ statement.close();
+ connection.close();
+ }
+
+
+ /**
+ * Tests to ensure a user with all on server,
+ * insert|select on table can view metadata while
+ * a user with all on a different table cannot
+ * view the metadata.
+
+ * Test both positive and negative of:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * Positive tests are run with:
+ * all@server
+ * select@table
+ * insert@table
+ * Negative tests are run three times:
+ * none
+ * insert@different table
+ */
+ @Test
+ public void testAllOnServerSelectInsertNegativeNoneAllOnDifferentTable()
+ throws Exception {
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ createTable(ADMIN1, DB1, dataFile, TBL2);
+ positiveDescribeShowTests(ADMIN1, DB1, TBL1);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + TBL2)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ negativeDescribeShowTests(USER1_1, DB1, TBL1);
+
+ policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ positiveDescribeShowTests(USER1_1, DB1, TBL1);
+
+ policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1);
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ positiveDescribeShowTests(USER1_1, DB1, TBL1);
+ }
+
+ /**
+ * Tests to ensure that a user is able to view metadata
+ * with all on db
+ *
+ * Test positive:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * Positive tests are run twice:
+ * all@server
+ * all@db
+ */
+ @Test
+ public void testAllOnServerAndAllOnDb() throws Exception {
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ positiveDescribeShowTests(ADMIN1, DB1, TBL1);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ positiveDescribeShowTests(USER1_1, DB1, TBL1);
+ }
+
+ /**
+ * Test to ensure that all on view do not result in
+ * metadata privileges on the underlying table
+ *
+ * Test both positive and negative of:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * Positive tests are run with all@server
+ * Negative tests are run three times:
+ * none
+ * all@view
+ */
+ @Test
+ public void testAllOnServerNegativeAllOnView() throws Exception {
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ statement.execute("DROP VIEW IF EXISTS " + VIEW1);
+ statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10");
+ positiveDescribeShowTests(ADMIN1, DB1, TBL1);
+ statement.close();
+ connection.close();
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + VIEW1)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ negativeDescribeShowTests(USER1_1, DB1, TBL1);
+ }
+
+ /**
+ * Tests to ensure that a user is able to view metadata
+ * with all on table
+ *
+ * Test positive:
+ * describe table
+ * describe table column
+ * show columns from table
+ * show create table table
+ * show tblproperties table
+ *
+ * Positive tests are run twice:
+ * all@server
+ * all@table
+ */
+ @Test
+ public void testAllOnServerAndAllOnTable() throws Exception {
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ positiveDescribeShowTests(ADMIN1, DB1, TBL1);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + TBL1)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ positiveDescribeShowTests(USER1_1, DB1, TBL1);
+ }
+
+
+ /**
+ * Tests that admin and all@db can describe database
+ * and describe database extended. Also tests that a user
+ * with no privileges on a db cannot describe database.
+ */
+ @Test
+ public void testDescribeDatabasesWithAllOnServerAndAllOnDb()
+ throws Exception {
+ dropDb(ADMIN1, DB1, DB2);
+ createDb(ADMIN1, DB1, DB2);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ createTable(ADMIN1, DB2, dataFile, TBL1);
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next());
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE EXTENDED " + DB1).next());
+ statement.close();
+ connection.close();
+
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next());
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE EXTENDED " + DB1).next());
+ context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE EXTENDED " + DB2);
+
+ policyFile.addPermissionsToRole(GROUP1_ROLE, INSERT_DB2_TBL1);
+ writePolicyFile(policyFile);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE EXTENDED " + DB2);
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Tests that a user without db level privileges cannot describe default
+ */
+ @Test
+ public void testDescribeDefaultDatabase() throws Exception {
+ createDb(ADMIN1, DB1, DB2);
+ createTable(ADMIN1, "default", dataFile, TBL1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE default").next());
+ statement.execute("USE " + DB1);
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE default").next());
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next());
+ assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB2).next());
+ statement.close();
+ connection.close();
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=default->table=" + TBL1 + "->action=select",
+ "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=select")
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE default");
+ context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB1);
+ statement.execute("USE " + DB1);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB1);
+ context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2);
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Tests that users without privileges cannot execute show indexes
+ * and that users with all on table can execute show indexes
+ */
+ @Test
+ public void testShowIndexes1() throws Exception {
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+ createTable(ADMIN1, DB1, dataFile, TBL2);
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ statement.execute("DROP INDEX IF EXISTS " + INDEX1 + " ON " + TBL1);
+ statement
+ .execute("CREATE INDEX "
+ + INDEX1
+ + " ON TABLE "
+ + TBL1
+ + "(value) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH DEFERRED REBUILD");
+ statement.execute("DROP VIEW IF EXISTS " + VIEW1);
+ statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10");
+ statement.close();
+ connection.close();
+
+ // grant privilege to table2 to allow use db1
+ policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL2)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ context.assertAuthzException(statement, "SHOW INDEX ON " + TBL1);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_VIEW1);
+ writePolicyFile(policyFile);
+ context.assertAuthzException(statement, "SHOW INDEX ON " + TBL1);
+
+ policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_VIEW1)
+ .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ verifyIndex(statement, DB1, TBL1, INDEX1);
+
+ policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1)
+ .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ verifyIndex(statement, DB1, TBL1, INDEX1);
+ statement.close();
+ connection.close();
+ }
+
+ private void verifyIndex(Statement statement, String dbName, String table, String index) throws Exception {
+ ResultSet rs = statement.executeQuery("SHOW INDEX ON " + table);
+ assertTrue(rs.next());
+ assertEquals(index, rs.getString(1).trim());
+ assertEquals(table, rs.getString(2).trim());
+ assertEquals("value", rs.getString(3).trim());
+ assertEquals(dbName + "__" + table + "_" + index + "__",
+ rs.getString(4).trim());
+ assertEquals("compact", rs.getString(5).trim());
+ }
+
+ /**
+ * Tests that users without privileges cannot execute show partitions
+ * and that users with select on table can execute show partitions
+ */
+ @Test
+ public void testShowPartitions1() throws Exception {
+ createDb(ADMIN1, DB1);
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ statement.execute("DROP TABLE IF EXISTS " + TBL2);
+ statement.execute("create table " + TBL2
+ + " (under_col int, value string) PARTITIONED BY (dt INT)");
+ statement.execute("DROP TABLE IF EXISTS " + TBL1);
+ statement.execute("create table " + TBL1
+ + " (under_col int, value string) PARTITIONED BY (dt INT)");
+ statement.execute("load data local inpath '" + dataFile.getPath()
+ + "' into table " + TBL1 + " PARTITION (dt=3)");
+ statement.execute("DROP VIEW IF EXISTS " + VIEW1);
+ statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10");
+ statement.close();
+ connection.close();
+
+ // grant privilege to table2 to allow use db1
+ policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL2)
+ .addRolesToGroup(USERGROUP1, GROUP1_ROLE)
+ .setUserGroupMapping(StaticUserGroup.getStaticMapping());
+ writePolicyFile(policyFile);
+
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ statement.execute("USE " + DB1);
+ context.assertAuthzException(statement, "SHOW PARTITIONS " + TBL1);
+
+ policyFile
+ .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_VIEW1);
+ writePolicyFile(policyFile);
+ context.assertAuthzException(statement, "SHOW PARTITIONS " + TBL1);
+
+ policyFile
+ .removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_VIEW1)
+ .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ verifyParition(statement, TBL1);
+
+ policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1)
+ .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1);
+ writePolicyFile(policyFile);
+ verifyParition(statement, TBL1);
+ statement.close();
+ connection.close();
+ }
+
+ private void verifyParition(Statement statement, String table) throws Exception {
+ ResultSet rs = statement.executeQuery("SHOW PARTITIONS " + table);
+ assertTrue(rs.next());
+ assertEquals("dt=3", rs.getString(1).trim());
+ }
+}