sentry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s..@apache.org
Subject [07/13] sentry git commit: SENTRY-514: Enable e2e tests for authorization V2 (Dapeng Sun, reviewed by Anne Yu)
Date Wed, 30 Mar 2016 01:52:03 GMT
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());
+  }
+}


Mime
View raw message