You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sh...@apache.org on 2013/09/21 01:38:56 UTC

[7/9] SENTRY-16: Move sentry-tests to sentry-tests-hive package (Gregory Chanan via Shreepadma Venugopalan)

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/aef404c6/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
new file mode 100644
index 0000000..f7d701c
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtDatabaseScope.java
@@ -0,0 +1,464 @@
+/*
+ * 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.assertFalse;
+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.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf.AuthzConfVars;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+/* Tests privileges at table scope within a single database.
+ */
+
+public class TestPrivilegesAtDatabaseScope extends AbstractTestWithHiveServer {
+
+  private Context context;
+  private File dataFile;
+  private PolicyFile policyFile;
+
+  Map <String, String >testProperties;
+  private static final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+
+  @Before
+  public void setup() throws Exception {
+    testProperties = new HashMap<String, String>();
+    policyFile = PolicyFile.createAdminOnServer1("admin1");
+  }
+
+  @After
+  public void teardown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  /* Admin creates database DB_1
+   * Admin grants ALL to USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testAllPrivilege() throws Exception {
+    context = createContext(testProperties);
+
+    //copy data file to test dir
+    File dataDir = context.getDataDir();
+    File 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
+        .addRolesToGroup("user_group1", "all_db1", "load_data")
+        .addRolesToGroup("user_group2", "all_db2")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addPermissionsToRole("all_db2", "server=server1->db=DB_2")
+        .addPermissionsToRole("load_data", "server=server1->uri=file://" + dataFile.getPath())
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    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("CREATE DATABASE DB_1");
+    statement.execute("CREATE DATABASE DB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);  
+    // test user can create table
+    statement.execute("CREATE TABLE DB_1.TAB_1(A STRING)");
+    // test user can execute load
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE DB_1.TAB_1");
+    statement.execute("CREATE TABLE DB_1.TAB_2(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE DB_1.TAB_2");
+
+    // test user can switch db
+    statement.execute("USE DB_1");
+    //test user can create view
+    statement.execute("CREATE VIEW VIEW_1(A) AS SELECT A FROM TAB_1");
+
+    // test user can insert
+    statement.execute("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+    // test user can query table
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(A) FROM TAB_1");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 1000);
+
+    // test user can execute alter table rename
+    statement.execute("ALTER TABLE TAB_1 RENAME TO TAB_3");
+
+    // test user can execute create as select
+    statement.execute("CREATE TABLE TAB_4 AS SELECT * FROM TAB_2");
+
+    // test user can execute alter table rename cols
+    statement.execute("ALTER TABLE TAB_3 ADD COLUMNS (B INT)");
+
+    // test user can drop table
+    statement.execute("DROP TABLE TAB_3");
+
+    //negative test case: user can't drop another user's database
+    try {
+      statement.execute("DROP DATABASE DB_2 CASCADE");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    //negative test case: user can't switch into another user's database
+    try {
+      statement.execute("USE DB_2");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    //negative test case: user can't drop own database
+    try {
+      statement.execute("DROP DATABASE DB_1 CASCADE");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    //test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.execute("DROP DATABASE DB_2 CASCADE");
+    statement.close();
+    connection.close();
+    context.close();
+  }
+
+  /* Admin creates database DB_1, creates table TAB_1, loads data into it
+   * Admin grants ALL to USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testAllPrivilegeOnObjectOwnedByAdmin() throws Exception {
+    context = createContext(testProperties);
+
+    //copy data file to test dir
+    File dataDir = context.getDataDir();
+    File dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+    File externalTblDir = new File(dataDir, "exttab");
+    FileOutputStream to = new FileOutputStream(dataFile);
+    Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+    to.close();
+
+    policyFile
+        .addRolesToGroup("user_group1", "all_db1", "load_data", "exttab")
+        .addRolesToGroup("user_group2", "all_db2")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addPermissionsToRole("all_db2", "server=server1->db=DB_2")
+        .addPermissionsToRole("exttab", "server=server1->uri=file://" + dataDir.getPath())
+        .addPermissionsToRole("load_data", "server=server1->uri=file://" + dataFile.getPath())
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    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("CREATE DATABASE DB_1");
+    statement.execute("CREATE DATABASE DB_2");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE TAB_1");
+    statement.execute("CREATE TABLE PART_TAB_1(A STRING) partitioned by (B INT) STORED AS TEXTFILE");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE PART_TAB_1 PARTITION(B=1)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE PART_TAB_1 PARTITION(B=2)");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    // test user can switch db
+    statement.execute("USE DB_1");
+    // test user can execute load
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE TAB_1");
+    statement.execute("CREATE TABLE TAB_2(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE TAB_2");
+
+    //test user can create view
+    statement.execute("CREATE VIEW VIEW_1(A) AS SELECT A FROM TAB_1");
+
+    // test user can insert
+    statement.execute("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+    // test user can query table
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(A) FROM TAB_1");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 1500);
+
+    // test user can execute alter table rename
+    statement.execute("ALTER TABLE TAB_1 RENAME TO TAB_3");
+
+    // test user can drop table
+    statement.execute("DROP TABLE TAB_3");
+
+    //negative test case: user can't drop db
+    try {
+      statement.execute("DROP DATABASE DB_1 CASCADE");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    //negative test case: user can't create external tables
+    assertTrue("Unable to create directory for external table test" , externalTblDir.mkdir());
+    statement.execute("CREATE EXTERNAL TABLE EXT_TAB_1(A STRING) STORED AS TEXTFILE LOCATION 'file:"+
+                        externalTblDir.getAbsolutePath() + "'");
+
+    //negative test case: user can't execute alter table set location
+    try {
+      statement.execute("ALTER TABLE TAB_2 SET LOCATION 'hdfs://nn1.example.com/hive/warehouse'");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    connection = context.createConnection("user2", "password");
+    statement = context.createStatement(connection);
+    try {
+      statement.execute("CREATE EXTERNAL TABLE EXT_TAB_1(A STRING) STORED AS TEXTFILE LOCATION 'file:"+
+        externalTblDir.getAbsolutePath() + "'");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    //test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.execute("DROP DATABASE DB_2 CASCADE");
+    statement.close();
+    connection.close();
+    context.close();
+  }
+
+  /**
+   * Test privileges for 'use <db>'
+   * Admin should be able to run use <db> with server level access
+   * User with db level access should be able to run use <db>
+   * User with table level access should be able to run use <db>
+   * User with no access to that db objects, should NOT be able run use <db>
+   * @throws Exception
+   */
+  @Test
+  public void testUseDbPrivilege() throws Exception {
+    context = createContext(testProperties);
+
+    policyFile
+        .addRolesToGroup("user_group1", "all_db1")
+        .addRolesToGroup("user_group2", "select_db2")
+        .addRolesToGroup("user_group3", "all_db3")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addPermissionsToRole("select_db2", "server=server1->db=DB_2->table=tab_2->action=select")
+        .addPermissionsToRole("all_db3", "server=server1->db=DB_3")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .addGroupsToUser("user3", "user_group3")
+        .write(context.getPolicyFile());
+
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("use DB_1");
+    statement.execute("CREATE TABLE TAB_1(A STRING)");
+    statement.execute("DROP DATABASE IF EXISTS DB_2 CASCADE");
+    statement.execute("CREATE DATABASE DB_2");
+    statement.execute("use DB_1");
+    statement.execute("CREATE TABLE TAB_2(A STRING)");
+    context.close();
+
+    // user1 should be able to connect db_1
+    connection = context.createConnection("user1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use DB_1");
+    context.close();
+
+    // user2 should not be able to connect db_1
+    connection = context.createConnection("user2", "hive");
+    statement = context.createStatement(connection);
+    try {
+      statement.execute("use DB_1");
+      assertFalse("user2 shouldn't be able switch to db_1", true);
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    statement.execute("use DB_2");
+    context.close();
+
+    // user3 who is not listed in policy file should not be able to connect db_2
+    connection = context.createConnection("user3", "hive");
+    statement = context.createStatement(connection);
+    try {
+      statement.execute("use DB_2");
+      assertFalse("user3 shouldn't be able switch to db_2", true);
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    context.close();
+  }
+
+  /**
+   * Test access to default DB with out of box authz config
+   * All users should be able to switch to default, including the users that don't have any
+   * privilege on default db objects via policy file
+   * @throws Exception
+   */
+  @Test
+  public void testDefaultDbPrivilege() throws Exception {
+    context = createContext(testProperties);
+
+    policyFile
+        .addRolesToGroup("user_group1", "all_db1")
+        .addRolesToGroup("user_group2", "select_db2")
+        .addRolesToGroup("user_group3", "all_default")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addPermissionsToRole("select_db2", "server=server1->db=DB_2->table=tab_2->action=select")
+        .addPermissionsToRole("all_default", "server=server1->db=default")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .addGroupsToUser("user3", "user_group3")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user2", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user3", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+  }
+
+  /**
+   * Test access to default DB with explicit privilege requirement
+   * Admin should be able to run use default with server level access
+   * User with db level access should be able to run use default
+   * User with table level access should be able to run use default
+   * User with no access to default db objects, should NOT be able run use default
+   * @throws Exception
+   */
+  @Test
+  public void testDefaultDbRestrictivePrivilege() throws Exception {
+    testProperties.put(AuthzConfVars.AUTHZ_RESTRICT_DEFAULT_DB.getVar(), "true");
+    context = createContext(testProperties);
+
+    policyFile
+        .addRolesToGroup("user_group1", "all_default")
+        .addRolesToGroup("user_group2", "select_default")
+        .addRolesToGroup("user_group3", "all_db1")
+        .addPermissionsToRole("all_default", "server=server1->db=default")
+        .addPermissionsToRole("select_default", "server=server1->db=default->table=tab_2->action=select")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .addGroupsToUser("user3", "user_group3")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user2", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("use default");
+    context.close();
+
+    connection = context.createConnection("user3", "hive");
+    statement = context.createStatement(connection);
+    try {
+      // user3 doesn't have any implicit permission for default
+      statement.execute("use default");
+      assertFalse("user3 shouldn't be able switch to default", true);
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    context.close();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/aef404c6/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtFunctionScope.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtFunctionScope.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtFunctionScope.java
new file mode 100644
index 0000000..9bc0dcd
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtFunctionScope.java
@@ -0,0 +1,177 @@
+/*
+printf_test_3 * 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.assertFalse;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+public class TestPrivilegesAtFunctionScope extends AbstractTestWithStaticLocalFS {
+  private Context context;
+  private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+  private File dataDir;
+  private File dataFile;
+  private PolicyFile policyFile;
+
+  @Before
+  public void setup() throws Exception {
+    context = createContext();
+    dataDir = context.getDataDir();
+    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.createAdminOnServer1(ADMIN1);
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  /**
+   * admin should be able to create/drop temp functions
+   * user with db level access should be able to create/drop temp functions
+   * user with table level access should be able to create/drop temp functions
+   * user with no privilege should NOT be able to create/drop temp functions
+   */
+  @Test
+  public void testFuncPrivileges1() throws Exception {
+    String dbName1 = "db_1";
+    String tableName1 = "tb_1";
+
+    policyFile
+        .addRolesToGroup("group1", "db1_all", "UDF_JAR")
+        .addRolesToGroup("group2", "db1_tab1", "UDF_JAR")
+        .addRolesToGroup("group3", "db1_tab1")
+        .addPermissionsToRole("db1_all", "server=server1->db=" + dbName1)
+        .addPermissionsToRole("db1_tab1", "server=server1->db=" + dbName1 + "->table=" + tableName1)
+        .addPermissionsToRole("UDF_JAR", "server=server1->uri=file://${user.home}/.m2")
+        .addGroupsToUser("user1", "group1")
+        .addGroupsToUser("user2", "group2")
+        .addGroupsToUser("user3", "group3")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    statement.execute("DROP TABLE IF EXISTS " + dbName1 + "." + tableName1);
+    statement.execute("create table " + dbName1 + "." + tableName1
+        + " (under_col int comment 'the under column', value string)");
+    statement.execute("LOAD DATA INPATH '" + dataFile.getPath() + "' INTO TABLE "
+        + dbName1 + "." + tableName1);
+    statement.execute("DROP TEMPORARY FUNCTION IF EXISTS printf_test");
+    statement.execute("DROP TEMPORARY FUNCTION IF EXISTS printf_test_2");
+    context.close();
+
+    // user1 should be able create/drop temp functions
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    statement.execute(
+        "CREATE TEMPORARY FUNCTION printf_test AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+    statement.execute("DROP TEMPORARY FUNCTION printf_test");
+    context.close();
+
+    // user2 has select privilege on one of the tables in db2, should be able create/drop temp functions
+    connection = context.createConnection("user2", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    statement.execute(
+        "CREATE TEMPORARY FUNCTION printf_test_2 AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+    statement.execute("DROP TEMPORARY FUNCTION printf_test");
+    context.close();
+
+    // user3 shouldn't be able to create/drop temp functions since it doesn't have permission for jar
+    connection = context.createConnection("user3", "foo");
+    statement = context.createStatement(connection);
+    try {
+      statement.execute("USE " + dbName1);
+      statement.execute(
+      "CREATE TEMPORARY FUNCTION printf_test_bad AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+      assertFalse("CREATE TEMPORARY FUNCTION should fail for user3", true);
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    context.close();
+
+    // user4 (not part of any group ) shouldn't be able to create/drop temp functions
+    connection = context.createConnection("user4", "foo");
+    statement = context.createStatement(connection);
+    try {
+      statement.execute("USE default");
+      statement.execute(
+      "CREATE TEMPORARY FUNCTION printf_test_bad AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+      assertFalse("CREATE TEMPORARY FUNCTION should fail for user4", true);
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    context.close();
+
+  }
+
+  @Test
+  public void testUdfWhiteList () throws Exception {
+    String dbName1 = "db1";
+    String tableName1 = "tab1";
+
+    policyFile
+        .addRolesToGroup("group1", "db1_all", "UDF_JAR")
+        .addRolesToGroup("group2", "db1_tab1", "UDF_JAR")
+        .addRolesToGroup("group3", "db1_tab1")
+        .addPermissionsToRole("db1_all", "server=server1->db=" + dbName1)
+        .addPermissionsToRole("db1_tab1", "server=server1->db=" + dbName1 + "->table=" + tableName1)
+        .addPermissionsToRole("UDF_JAR", "server=server1->uri=file://${user.home}/.m2")
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "password");
+    Statement statement = connection.createStatement();
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    statement.execute("create table " + tableName1
+        + " (under_col int comment 'the under column', value string)");
+    statement.execute("LOAD DATA INPATH '" + dataFile.getPath() + "' INTO TABLE "
+        + dbName1 + "." + tableName1);
+    statement.execute("SELECT rand(), concat(value, '_foo') FROM " + tableName1);
+
+    context.assertAuthzException(statement,
+        "SELECT  reflect('java.net.URLDecoder', 'decode', 'http://www.apache.org', 'utf-8'), value FROM " + tableName1);
+    context.assertAuthzException(statement,
+        "SELECT  java_method('java.net.URLDecoder', 'decode', 'http://www.apache.org', 'utf-8'), value FROM " + tableName1);
+    statement.close();
+    connection.close();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/aef404c6/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
new file mode 100644
index 0000000..bf30abf
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestPrivilegesAtTableScope.java
@@ -0,0 +1,678 @@
+/*
+ * 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.*;
+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.SQLException;
+import java.sql.Statement;
+
+import junit.framework.Assert;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+/* Tests privileges at table scope within a single database.
+ */
+
+public class TestPrivilegesAtTableScope extends AbstractTestWithStaticLocalFS {
+
+  private Context context;
+  private PolicyFile policyFile;
+
+  private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+  private final String MULTI_TYPE_DATA_FILE_NAME = "emp.dat";
+
+  @Before
+  public void setup() throws Exception {
+    context = createContext();
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+  }
+
+  @After
+  public void teardown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, loads data into
+   * TAB_1, TAB_2 Admin grants SELECT on TAB_1, TAB_2, INSERT on TAB_1 to
+   * USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testInsertAndSelect() throws Exception {
+    File dataDir = context.getDataDir();
+    // copy data file to test dir
+    File 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
+        .addRolesToGroup("user_group", "select_tab1", "insert_tab1", "select_tab2")
+        .addPermissionsToRole("select_tab1", "server=server1->db=DB_1->table=TAB_1->action=select")
+        .addPermissionsToRole("insert_tab1", "server=server1->db=DB_1->table=TAB_1->action=insert")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE TABLE TAB_2(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can insert
+    statement.execute("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+    // test user can query table
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(A) FROM TAB_1");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 1000);
+
+    // negative test: test user can't drop
+    try {
+      statement.execute("DROP TABLE TAB_1");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    statement.close();
+    connection.close();
+
+    // connect as admin and drop tab_1
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    statement.execute("DROP TABLE TAB_1");
+    statement.close();
+    connection.close();
+
+    // negative test: connect as user1 and try to recreate tab_1
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    try {
+      statement.execute("CREATE TABLE TAB_1(A STRING)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, loads data into
+   * TAB_1, TAB_2. Admin grants INSERT on TAB_1, SELECT on TAB_2 to USER_GROUP
+   * of which user1 is a member.
+   */
+  @Test
+  public void testInsert() throws Exception {
+    File dataDir = context.getDataDir();
+    // copy data file to test dir
+    File 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
+        .addRolesToGroup("user_group", "insert_tab1", "select_tab2")
+        .addPermissionsToRole("insert_tab1", "server=server1->db=DB_1->table=TAB_1->action=insert")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1(A) AS SELECT A FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can execute insert on table
+    statement.executeQuery("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+
+    // negative test: user can't query table
+    try {
+      statement.executeQuery("SELECT COUNT(A) FROM TAB_1");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    // negative test: test user can't query view
+    try {
+      statement.executeQuery("SELECT COUNT(A) FROM VIEW_1");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    // negative test case: show tables shouldn't list VIEW_1
+    ResultSet resultSet = statement.executeQuery("SHOW TABLES");
+    while (resultSet.next()) {
+      String tableName = resultSet.getString(1);
+      assertNotNull("table name is null in result set", tableName);
+      assertFalse("Found VIEW_1 in the result set",
+          "VIEW_1".equalsIgnoreCase(tableName));
+    }
+
+    // negative test: test user can't create a new view
+    try {
+      statement.executeQuery("CREATE VIEW VIEW_2(A) AS SELECT A FROM TAB_1");
+      Assert.fail("Expected SQL Exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, loads data into
+   * TAB_1, TAB_2. Admin grants SELECT on TAB_1, TAB_2 to USER_GROUP of which
+   * user1 is a member.
+   */
+  @Test
+  public void testSelect() throws Exception {
+    // copy data file to test dir
+    File dataDir = context.getDataDir();
+    File 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
+        .addRolesToGroup("user_group", "select_tab1", "select_tab2")
+        .addPermissionsToRole("select_tab1", "server=server1->db=DB_1->table=TAB_1->action=select")
+        .addPermissionsToRole("insert_tab1", "server=server1->db=DB_1->table=TAB_1->action=insert")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1(A) AS SELECT A FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(A STRING)");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can execute query on table
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(A) FROM TAB_1");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 500);
+
+    // negative test: test insert into table
+    try {
+      statement.executeQuery("INSERT INTO TABLE TAB_1 SELECT A FROM TAB_2");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    // negative test: test user can't query view
+    try {
+      statement.executeQuery("SELECT COUNT(A) FROM VIEW_1");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    // negative test: test user can't create a new view
+    try {
+      statement.executeQuery("CREATE VIEW VIEW_2(A) AS SELECT A FROM TAB_1");
+      Assert.fail("Expected SQL Exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, VIEW_1 on TAB_1
+   * loads data into TAB_1, TAB_2. Admin grants SELECT on TAB_1,TAB_2 to
+   * USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testTableViewJoin() throws Exception {
+    // copy data file to test dir
+    File dataDir = context.getDataDir();
+    File dataFile = new File(dataDir, MULTI_TYPE_DATA_FILE_NAME);
+    FileOutputStream to = new FileOutputStream(dataFile);
+    Resources.copy(Resources.getResource(MULTI_TYPE_DATA_FILE_NAME), to);
+    to.close();
+
+    policyFile
+        .addRolesToGroup("user_group", "select_tab1", "select_tab2")
+        .addPermissionsToRole("select_tab1", "server=server1->db=DB_1->table=TAB_1->action=select")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1 AS SELECT A, B FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can execute query TAB_1 JOIN TAB_2
+    ResultSet resultSet = statement
+        .executeQuery("SELECT COUNT(*) FROM TAB_1 T1 JOIN TAB_2 T2 ON (T1.B = T2.B)");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // negative test: test user can't execute query VIEW_1 JOIN TAB_2
+    try {
+      statement
+          .executeQuery("SELECT COUNT(*) FROM VIEW_1 V1 JOIN TAB_2 T2 ON (V1.B = T2.B)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, VIEW_1 on TAB_1
+   * loads data into TAB_1, TAB_2. Admin grants SELECT on TAB_2 to USER_GROUP of
+   * which user1 is a member.
+   */
+  @Test
+  public void testTableViewJoin2() throws Exception {
+
+    File dataDir = context.getDataDir();
+    // copy data file to test dir
+    File dataFile = new File(dataDir, MULTI_TYPE_DATA_FILE_NAME);
+    FileOutputStream to = new FileOutputStream(dataFile);
+    Resources.copy(Resources.getResource(MULTI_TYPE_DATA_FILE_NAME), to);
+    to.close();
+
+    policyFile
+        .addRolesToGroup("user_group", "select_tab2")
+        .addPermissionsToRole("select_tab1", "server=server1->db=DB_1->table=TAB_1->action=select")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1 AS SELECT A, B FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can execute query on TAB_2
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM TAB_2");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // negative test: test user can't execute query VIEW_1 JOIN TAB_2
+    try {
+      statement
+          .executeQuery("SELECT COUNT(*) FROM VIEW_1 JOIN TAB_2 ON (VIEW_1.B = TAB_2.B)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    // negative test: test user can't execute query TAB_1 JOIN TAB_2
+    try {
+      statement
+          .executeQuery("SELECT COUNT(*) FROM TAB_1 JOIN TAB_2 ON (TAB_1.B = TAB_2.B)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, VIEW_1 on TAB_1
+   * loads data into TAB_1, TAB_2. Admin grants SELECT on TAB_2, VIEW_1 to
+   * USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testTableViewJoin3() throws Exception {
+    File dataDir = context.getDataDir();
+    // copy data file to test dir
+    File dataFile = new File(dataDir, MULTI_TYPE_DATA_FILE_NAME);
+    FileOutputStream to = new FileOutputStream(dataFile);
+    Resources.copy(Resources.getResource(MULTI_TYPE_DATA_FILE_NAME), to);
+    to.close();
+
+    policyFile
+        .addRolesToGroup("user_group", "select_tab2", "select_view1")
+        .addPermissionsToRole("select_view1", "server=server1->db=DB_1->table=VIEW_1->action=select")
+        .addPermissionsToRole("select_tab2", "server=server1->db=DB_1->table=TAB_2->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1 AS SELECT A, B FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+    // test user can execute query on TAB_2
+    ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM TAB_2");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // test user can execute query VIEW_1 JOIN TAB_2
+    resultSet = statement
+        .executeQuery("SELECT COUNT(*) FROM VIEW_1 V1 JOIN TAB_2 T2 ON (V1.B = T2.B)");
+    count = 0;
+    countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // test user can execute query on VIEW_1
+    resultSet = statement.executeQuery("SELECT COUNT(*) FROM VIEW_1");
+    count = 0;
+    countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // negative test: test user can't execute query TAB_1 JOIN TAB_2
+    try {
+      statement
+          .executeQuery("SELECT COUNT(*) FROM TAB_1 T1 JOIN TAB_2 T2 ON (T1.B = T2.B)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+
+  /*
+   * Admin creates database DB_1, table TAB_1, TAB_2 in DB_1, VIEW_1 on TAB_1
+   * loads data into TAB_1, TAB_2. Admin grants SELECT on TAB_1, VIEW_1 to
+   * USER_GROUP of which user1 is a member.
+   */
+  @Test
+  public void testTableViewJoin4() throws Exception {
+    File dataDir = context.getDataDir();
+    // copy data file to test dir
+    File dataFile = new File(dataDir, MULTI_TYPE_DATA_FILE_NAME);
+    FileOutputStream to = new FileOutputStream(dataFile);
+    Resources.copy(Resources.getResource(MULTI_TYPE_DATA_FILE_NAME), to);
+    to.close();
+
+    policyFile
+        .addRolesToGroup("user_group", "select_tab1", "select_view1")
+        .addPermissionsToRole("select_view1", "server=server1->db=DB_1->table=VIEW_1->action=select")
+        .addPermissionsToRole("select_tab1", "server=server1->db=DB_1->table=TAB_1->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS DB_1 CASCADE");
+    statement.execute("CREATE DATABASE DB_1");
+    statement.execute("USE DB_1");
+    statement.execute("CREATE TABLE TAB_1(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_1");
+    statement.execute("CREATE VIEW VIEW_1 AS SELECT A, B FROM TAB_1");
+    statement.execute("CREATE TABLE TAB_2(B INT, A STRING) "
+        + " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath()
+        + "' INTO TABLE TAB_2");
+    statement.close();
+    connection.close();
+
+    // test execution
+    connection = context.createConnection("user1", "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE DB_1");
+
+    // test user can execute query VIEW_1 JOIN TAB_1
+    ResultSet resultSet = statement
+        .executeQuery("SELECT COUNT(*) FROM VIEW_1 JOIN TAB_1 ON (VIEW_1.B = TAB_1.B)");
+    int count = 0;
+    int countRows = 0;
+
+    while (resultSet.next()) {
+      count = resultSet.getInt(1);
+      countRows++;
+    }
+    assertTrue("Incorrect row count", countRows == 1);
+    assertTrue("Incorrect result", count == 12);
+
+    // negative test: test user can't execute query TAB_1 JOIN TAB_2
+    try {
+      statement
+          .executeQuery("SELECT COUNT(*) FROM TAB_1 JOIN TAB_2 ON (TAB_1.B = TAB_2.B)");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+
+    statement.close();
+    connection.close();
+
+    // test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE DB_1 CASCADE");
+    statement.close();
+    connection.close();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/aef404c6/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestRuntimeMetadataRetrieval.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestRuntimeMetadataRetrieval.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestRuntimeMetadataRetrieval.java
new file mode 100644
index 0000000..4b0fe8e
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestRuntimeMetadataRetrieval.java
@@ -0,0 +1,401 @@
+/*
+ * 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.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+/**
+ * Metadata tests for show tables and show databases. * Unlike rest of the
+ * access privilege validation which is handled in semantic hooks, these
+ * statements are validaed via a runtime fetch hook
+ */
+public class TestRuntimeMetadataRetrieval
+    extends
+      AbstractTestWithStaticLocalFS {
+  private Context context;
+  private PolicyFile policyFile;
+  private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+  private File dataDir;
+  private File dataFile;
+
+  @Before
+  public void setup() throws Exception {
+    context = createContext();
+    dataDir = context.getDataDir();
+    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.createAdminOnServer1(ADMIN1);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  /**
+   * Steps: 1. admin create db_1 and db_1.tb_1
+   *        2. admin should see all tables
+   *        3. user1 should only see the tables it has any level of privilege
+   */
+  @Test
+  public void testShowTables1() throws Exception {
+    String dbName1 = "db_1";
+    // tables visible to user1 (not access to tb_4
+    String tableNames[] = {"tb_1", "tb_2", "tb_3", "tb_4"};
+    List<String> tableNamesValidation = new ArrayList<String>();
+
+    policyFile
+        .addRolesToGroup("user_group", "tab1_priv,tab2_priv,tab3_priv")
+        .addPermissionsToRole("tab1_priv", "server=server1->db=" + dbName1 + "->table="
+            + tableNames[0] + "->action=select")
+        .addPermissionsToRole("tab2_priv", "server=server1->db=" + dbName1 + "->table="
+            + tableNames[1] + "->action=insert")
+        .addPermissionsToRole("tab3_priv", "server=server1->db=" + dbName1 + "->table="
+            + tableNames[2] + "->action=select")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    String user1TableNames[] = {"tb_1", "tb_2", "tb_3"};
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    createTabs(statement, dbName1, tableNames);
+    // Admin should see all tables
+    ResultSet rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(tableNames));
+
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    // User1 should see tables with any level of access
+    rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(user1TableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin create db_1 and tables
+   * 2. admin should see all tables
+   * 3. user1 should only see the all tables with db level privilege
+   */
+  @Test
+  public void testShowTables2() throws Exception {
+    String dbName1 = "db_1";
+    // tables visible to user1 (not access to tb_4
+    String tableNames[] = {"tb_1", "tb_2", "tb_3", "tb_4"};
+    List<String> tableNamesValidation = new ArrayList<String>();
+
+    policyFile
+        .addRolesToGroup("user_group", "db_priv")
+        .addPermissionsToRole("db_priv", "server=server1->db=" + dbName1)
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    String user1TableNames[] = {"tb_1", "tb_2", "tb_3", "tb_4"};
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    createTabs(statement, dbName1, tableNames);
+    // Admin should see all tables
+    ResultSet rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(tableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    // User1 should see tables with any level of access
+    rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(user1TableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin create db_1 and db_1.tb_1
+   *        2. admin should see all tables
+   *        3. user1 should only see the tables he/she has any level of privilege
+   */
+  @Test
+  public void testShowTables3() throws Exception {
+    String dbName1 = "db_1";
+    // tables visible to user1 (not access to tb_4
+    String tableNames[] = {"tb_1", "tb_2", "tb_3", "newtab_3"};
+    List<String> tableNamesValidation = new ArrayList<String>();
+
+    policyFile
+        .addRolesToGroup("user_group", "tab_priv")
+        .addPermissionsToRole("tab_priv", "server=server1->db=" + dbName1 + "->table="
+            + tableNames[3] + "->action=insert")
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    String adminTableNames[] = {"tb_3", "newtab_3", "tb_2", "tb_1"};
+    String user1TableNames[] = {"newtab_3"};
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    createTabs(statement, dbName1, tableNames);
+    // Admin should see all tables
+    ResultSet rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(adminTableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    // User1 should see tables with any level of access
+    rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(user1TableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin create db_1 and db_1.tb_1
+   *        2. admin should see all tables
+   *        3. user1 should only see the tables with db level privilege
+   */
+  @Test
+  public void testShowTables4() throws Exception {
+    String dbName1 = "db_1";
+    String tableNames[] = {"tb_1", "tb_2", "tb_3", "newtab_3"};
+    List<String> tableNamesValidation = new ArrayList<String>();
+
+    policyFile
+        .addRolesToGroup("user_group", "tab_priv")
+        .addPermissionsToRole("tab_priv", "server=server1->db=" + dbName1)
+        .addGroupsToUser("user1", "user_group")
+        .write(context.getPolicyFile());
+
+    String adminTableNames[] = {"tb_3", "newtab_3", "tb_1", "tb_2"};
+    String user1TableNames[] = {"tb_3", "newtab_3", "tb_1", "tb_2"};
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE IF EXISTS " + dbName1 + " CASCADE");
+    statement.execute("CREATE DATABASE " + dbName1);
+    statement.execute("USE " + dbName1);
+    createTabs(statement, dbName1, tableNames);
+    // Admin should be able to see all tables
+    ResultSet rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(adminTableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + dbName1);
+    // User1 should see tables with any level of access
+    rs = statement.executeQuery("SHOW TABLES");
+    tableNamesValidation.addAll(Arrays.asList(user1TableNames));
+    validateTables(rs, dbName1, tableNamesValidation);
+    statement.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin creates tables in default db
+   *        2. user1 shouldn't see any table when he/she doesn't have any privilege on default
+   */
+  @Test
+  public void testShowTables5() throws Exception {
+    String tableNames[] = {"tb_1", "tb_2", "tb_3", "tb_4"};
+
+    policyFile
+        .addRolesToGroup("user_group", "db_priv")
+        .write(context.getPolicyFile());
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    createTabs(statement, "default", tableNames);
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    // User1 should see tables with any level of access
+    ResultSet rs = statement.executeQuery("SHOW TABLES");
+    // user1 doesn't have access to any tables in default db
+    Assert.assertFalse(rs.next());
+    statement.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin create few dbs
+   *        2. admin can do show databases
+   *        3. users with db level permissions should only those dbs on 'show database'
+   */
+  @Test
+  public void testShowDatabases1() throws Exception {
+    List<String> dbNamesValidation = new ArrayList<String>();
+    String[] dbNames = {"db_1", "db_2", "db_3"};
+    String[] user1DbNames = {"db_1"};
+
+    policyFile
+        .addRolesToGroup("group1", "db1_all")
+        .addPermissionsToRole("db1_all", "server=server1->db=db_1")
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    // create all dbs
+    createDBs(statement, dbNames);
+    ResultSet rs = statement.executeQuery("SHOW DATABASES");
+    dbNamesValidation.addAll(Arrays.asList(dbNames));
+    dbNamesValidation.add("default");
+    // admin should see all dbs
+    validateDBs(rs, dbNamesValidation);
+    rs.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    rs = statement.executeQuery("SHOW DATABASES");
+    dbNamesValidation.addAll(Arrays.asList(user1DbNames));
+    dbNamesValidation.add("default");
+    // user should see only dbs with access
+    validateDBs(rs, dbNamesValidation);
+    rs.close();
+    context.close();
+  }
+
+  /**
+   * Steps: 1. admin create few dbs
+   *        2. admin can do show databases
+   *        3. users with table level permissions should should only those parent dbs on 'show
+   *           database'
+   */
+  @Test
+  public void testShowDatabases2() throws Exception {
+    String[] dbNames = {"db_1", "db_2", "db_3"};
+    List<String> dbNamesValidation = new ArrayList<String>();
+    String[] user1DbNames = {"db_1", "db_2"};
+
+    policyFile
+        .addRolesToGroup("group1", "db1_tab,db2_tab")
+        .addPermissionsToRole("db1_tab", "server=server1->db=db_1->table=tb_1->action=select")
+        .addPermissionsToRole("db2_tab", "server=server1->db=db_2->table=tb_1->action=insert")
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    // verify by SQL
+    // 1, 2
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = context.createStatement(connection);
+    createDBs(statement, dbNames); // create all dbs
+    ResultSet rs = statement.executeQuery("SHOW DATABASES");
+    dbNamesValidation.addAll(Arrays.asList(dbNames));
+    dbNamesValidation.add("default");
+    validateDBs(rs, dbNamesValidation); // admin should see all dbs
+    rs.close();
+    context.close();
+
+    connection = context.createConnection("user1", "foo");
+    statement = context.createStatement(connection);
+    rs = statement.executeQuery("SHOW DATABASES");
+    dbNamesValidation.addAll(Arrays.asList(user1DbNames));
+    dbNamesValidation.add("default");
+    // user should see only dbs with access
+    validateDBs(rs, dbNamesValidation);
+    rs.close();
+    context.close();
+  }
+
+  // create given dbs
+  private void createDBs(Statement statement, String dbNames[])
+      throws SQLException {
+    for (String dbName : dbNames) {
+      statement.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+      statement.execute("CREATE DATABASE " + dbName);
+    }
+  }
+
+  // compare the table resultset with given array of table names
+  private void validateDBs(ResultSet rs, List<String> dbNames)
+      throws SQLException {
+    while (rs.next()) {
+      String dbName = rs.getString(1);
+      Assert.assertTrue(dbName, dbNames.remove(dbName.toLowerCase()));
+    }
+    Assert.assertTrue(dbNames.toString(), dbNames.isEmpty());
+    rs.close();
+  }
+
+  // Create the give tables
+  private void createTabs(Statement statement, String dbName,
+      String tableNames[]) throws SQLException {
+    for (String tabName : tableNames) {
+      statement.execute("DROP TABLE IF EXISTS " + dbName + "." + tabName);
+      statement.execute("create table " + dbName + "." + tabName
+          + " (under_col int comment 'the under column', value string)");
+    }
+  }
+
+  // compare the table resultset with given array of table names
+  private void validateTables(ResultSet rs, String dbName,
+      List<String> tableNames) throws SQLException {
+    while (rs.next()) {
+      String tableName = rs.getString(1);
+      Assert.assertTrue(tableName, tableNames.remove(tableName.toLowerCase()));
+    }
+    Assert.assertTrue(tableNames.toString(), tableNames.isEmpty());
+    rs.close();
+  }
+}