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:55 UTC

[6/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/TestSandboxOps.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSandboxOps.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSandboxOps.java
new file mode 100644
index 0000000..63778a7
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSandboxOps.java
@@ -0,0 +1,585 @@
+/*
+ * 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.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.apache.hadoop.fs.Path;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.provider.file.PolicyFiles;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
+
+public class TestSandboxOps  extends AbstractTestWithStaticDFS {
+  private PolicyFile policyFile;
+  private File dataFile;
+  private String loadData;
+  private static final String DB2_POLICY_FILE = "db2-policy-file.ini";
+
+
+  @Before
+  public void setup() throws Exception {
+    context = createContext();
+    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);
+    loadData = "server=server1->uri=file://" + dataFile.getPath();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+  private PolicyFile addTwoUsersWithAllDb() {
+    policyFile
+    .addGroupsToUser("user1", "user_group")
+    .addGroupsToUser("user2", "user_group")
+    .addPermissionsToRole("db1_all", "server=server1->db=db1")
+    .addPermissionsToRole("db2_all", "server=server1->db=db2")
+    .addRolesToGroup("user_group", "db1_all", "db2_all");
+    return policyFile;
+  }
+  /**
+   * Tests to ensure that users with all@db can create tables
+   * and that they cannot create databases or load data
+   */
+  @Test
+  public void testDbPrivileges() throws Exception {
+    addTwoUsersWithAllDb().write(context.getPolicyFile());
+    String[] dbs = new String[] { "db1", "db2" };
+    for (String dbName : dbs) {
+      dropDb(ADMIN1, dbName);
+      createDb(ADMIN1, dbName);
+    }
+    for (String user : new String[] { "user1", "user2" }) {
+      for (String dbName : new String[] { "db1", "db2" }) {
+        Connection userConn = context.createConnection(user, "foo");
+        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 " + tabName + " (id int)");
+        context.assertAuthzException(userStmt, "load data local inpath '" + dataFile + "' into table " + tabName);
+        assertTrue(userStmt.execute("select * from " + tabName));
+        // negative users cannot create databases
+        context.assertAuthzException(userStmt, "CREATE DATABASE " + user + "_db");
+        userStmt.close();
+        userConn.close();
+      }
+    }
+
+    for (String dbName : dbs) {
+      dropDb(ADMIN1, dbName);
+    }
+
+  }
+  /**
+   * 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 {
+    policyFile.write(context.getPolicyFile());
+    Connection adminCon = context.createConnection(ADMIN1, "password");
+    Statement adminStmt = context.createStatement(adminCon);
+    String dbName = "db1";
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+
+    // access the new databases
+    adminStmt.execute("use " + dbName);
+    String tabName = "admin_tab1";
+    adminStmt.execute("create table " + tabName + "(c1 string)");
+    adminStmt.execute("load data local inpath '" + dataFile.getPath() + "' into table "
+        + tabName);
+    adminStmt.execute("select * from " + tabName);
+
+    // cleanup
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE " + dbName + " CASCADE");
+    adminStmt.close();
+    adminCon.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 {
+    policyFile
+    .addPermissionsToRole("db1_tab2_all", "server=server1->db=db1->table=table_2")
+    .addRolesToGroup("group1", "db1_tab2_all")
+    .addGroupsToUser("user3", "group1");
+    policyFile.write(context.getPolicyFile());
+    Connection adminCon = context.createConnection(ADMIN1, "password");
+    Statement adminStmt = context.createStatement(adminCon);
+    String dbName = "db1";
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.execute("use " + dbName);
+    adminStmt.execute("create table table_1 (id int)");
+    adminStmt.execute("create table table_2 (id int)");
+    adminStmt.close();
+    adminCon.close();
+    Connection userConn = context.createConnection("user3", "password");
+    Statement userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    // user3 doesn't have select privilege on table_1, so insert/select should fail
+    context.assertAuthzException(userStmt, "insert overwrite table table_2 select * from table_1");
+    context.assertAuthzException(userStmt, "insert overwrite directory '" + baseDir.getPath() + "' select * from table_1");
+    userConn.close();
+    userStmt.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 {
+    policyFile
+        .addRolesToGroup("user_group1", "db1_all")
+        .addRolesToGroup("user_group2", "db1_tab1_select")
+        .addPermissionsToRole("db1_tab1_select", "server=server1->db=db1->table=table_1->action=select")
+        .addPermissionsToRole("db1_all", "server=server1->db=db1")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+    // create dbs
+    Connection adminCon = context.createConnection("admin1", "foo");
+    Statement adminStmt = context.createStatement(adminCon);
+    String dbName = "db1";
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.execute("use " + dbName);
+    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.execute("ALTER TABLE table_1 SET TBLPROPERTIES (\"createTime\"=\"1375824555\")");
+    adminStmt.close();
+    adminCon.close();
+
+    Connection userConn = context.createConnection("user2", "foo");
+    Statement userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+
+    context.assertAuthzException(userStmt, "alter table table_2 add columns (id int)");
+    context.assertAuthzException(userStmt, "drop database " + dbName);
+    context.assertAuthzException(userStmt, "CREATE INDEX x ON TABLE table_1(name) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'");
+    context.assertAuthzException(userStmt, "CREATE TEMPORARY FUNCTION strip AS 'org.apache.hadoop.hive.ql.udf.generic.GenericUDFPrintf'");
+    context.assertAuthzException(userStmt, "create table foo(id int)");
+    context.assertAuthzException(userStmt, "create table c_tab_2 as select * from table_2"); // no select or create privilege
+    context.assertAuthzException(userStmt, "create table c_tab_1 as select * from table_1"); // no create privilege
+    context.assertAuthzException(userStmt, "ALTER DATABASE " + dbName + " SET DBPROPERTIES ('foo' = 'bar')");
+    context.assertAuthzException(userStmt, "ALTER VIEW v1 SET TBLPROPERTIES ('foo' = 'bar')");
+    context.assertAuthzException(userStmt, "DROP VIEW IF EXISTS v1");
+    context.assertAuthzException(userStmt, "create table table_5 (name string)");
+    context.assertAuthzException(userStmt, "ALTER TABLE table_1  RENAME TO table_99");
+    context.assertAuthzException(userStmt, "insert overwrite table table_2 select * from table_1");
+    context.assertAuthzException(userStmt, "ALTER TABLE table_part_1 ADD IF NOT EXISTS PARTITION (year = 2012)");
+    context.assertAuthzException(userStmt, "ALTER TABLE table_part_1 PARTITION (year = 2012) SET LOCATION '" + baseDir.getPath() + "'");
+    context.assertAuthzException(userStmt, "ALTER TABLE table_1 SET TBLPROPERTIES (\"createTime\"=\"1375824555\")");
+  }
+
+  /**
+   * 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
+   * 3. admin remove all to group1 on DB_2
+   *   positive test case:
+   *     d) user1 has the privilege to create view on tables in DB_1
+   *   negative test case:
+   *     e) user1 cannot create view on tables in DB_1 that select
+   *     from tables in DB_2
+   * 4. admin grant select to group1 on DB_2.ta_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
+   * @throws Exception
+   */
+  @Test
+  public void testSandboxOpt9() throws Exception {
+
+    policyFile
+    .addPermissionsToRole(GROUP1_ROLE, ALL_DB1, ALL_DB2, loadData)
+    .addRolesToGroup(GROUP1, GROUP1_ROLE)
+    .addGroupsToUser(USER1, GROUP1);
+    policyFile.write(context.getPolicyFile());
+
+    dropDb(ADMIN1, DB1, DB2);
+    createDb(ADMIN1, DB1, DB2);
+
+    Connection connection = context.createConnection(USER1, "password");
+    Statement statement = context.createStatement(connection);
+
+    // a
+    statement.execute("USE " + DB1);
+    createTable(USER1, DB1, dataFile, TBL1);
+    statement.execute("DROP VIEW IF EXISTS " + VIEW1);
+    statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10");
+
+    createTable(USER1, DB2, dataFile, TBL2, TBL3);
+    // c
+    context.assertAuthzException(statement, "DROP DATABASE IF EXISTS " + DB1 + " CASCADE");
+    context.assertAuthzException(statement, "DROP DATABASE IF EXISTS " + DB2 + " CASCADE");
+    // d
+    statement.execute("USE " + DB1);
+    policyFile.removePermissionsFromRole(GROUP1_ROLE, ALL_DB2);
+    policyFile.write(context.getPolicyFile());
+    // e
+    // create db1.view1 as select from db2.tbl2
+    statement.execute("DROP VIEW IF EXISTS " + VIEW2);
+    context.assertAuthzException(statement, "CREATE VIEW " + VIEW2 +
+        " (value) AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+    // create db1.tbl2 as select from db2.tbl2
+    statement.execute("DROP TABLE IF EXISTS " + TBL2);
+    context.assertAuthzException(statement, "CREATE TABLE " + TBL2 +
+        " AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+    context.assertAuthzException(statement, "CREATE TABLE " + DB2 + "." + TBL2 +
+        " AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+
+    // f
+    policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB2_TBL2);
+    policyFile.write(context.getPolicyFile());
+    statement.execute("DROP VIEW IF EXISTS " + VIEW2);
+    statement.execute("CREATE VIEW " + VIEW2
+        + " (value) AS SELECT value from " + DB2 + "." + TBL2 + " LIMIT 10");
+
+    // g
+    statement.execute("DROP VIEW IF EXISTS " + VIEW3);
+    context.assertAuthzException(statement, "CREATE VIEW " + VIEW3
+        + " (value) AS SELECT value from " + DB2 + "." + TBL3 + " LIMIT 10");
+    statement.close();
+    connection.close();
+    dropDb(ADMIN1, DB1, DB2);
+  }
+
+  /**
+   * Tests select on table with index.
+   *
+   * Steps:
+   * 1. admin user create a new database DB_1
+   * 2. admin create TABLE_1 in DB_1
+   * 3. admin create INDEX_1 for COLUMN_1 in TABLE_1 in DB_1
+   * 4. admin user grant INSERT and SELECT to user1's group on TABLE_1
+   *
+   *   negative test case:
+   *     a) user1 try to SELECT * FROM TABLE_1 WHERE COLUMN_1 == ...
+   *     should NOT work
+   *     b) user1 should not be able to check the list of view or
+   *     index in DB_1
+   * @throws Exception
+   */
+  @Test
+  public void testSandboxOpt13() throws Exception {
+    // unrelated permission to allow user1 to connect to db1
+    policyFile
+    .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL2)
+    .addRolesToGroup(GROUP1, GROUP1_ROLE)
+    .addGroupsToUser(USER1, GROUP1);
+    policyFile.write(context.getPolicyFile());
+    dropDb(ADMIN1, DB1);
+    createDb(ADMIN1, DB1);
+    createTable(ADMIN1, DB1, dataFile, TBL1);
+    Connection connection = context.createConnection(ADMIN1, "password");
+    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
+        + " (under_col) as 'COMPACT' WITH DEFERRED REBUILD");
+    statement.close();
+    connection.close();
+    connection = context.createConnection(USER1, "password");
+    statement = context.createStatement(connection);
+    statement.execute("USE " + DB1);
+    context.assertAuthzException(statement, "SELECT * FROM " + TBL1 + " WHERE under_col == 5");
+    context.assertAuthzException(statement, "SHOW INDEXES ON " + TBL1);
+    policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1, INSERT_DB1_TBL1, loadData);
+    policyFile.write(context.getPolicyFile());
+    statement.execute("USE " + DB1);
+    assertTrue(statement.execute("SELECT * FROM " + TBL1 + " WHERE under_col == 5"));
+    assertTrue(statement.execute("SHOW INDEXES ON " + TBL1));
+    policyFile.write(context.getPolicyFile());
+    dropDb(ADMIN1, DB1, DB2);
+  }
+
+  /**
+   * Steps:
+   * 1. Admin user creates a new database DB_1
+   * 2. Admin user grants ALL on DB_1 to group GROUP_1
+   * 3. User from GROUP_1 creates table TAB_1, TAB_2 in DB_1
+   * 4. Admin user grants SELECT/INSERT on TAB_1 to group GROUP_2
+   *   a) verify users from GROUP_2 have only SELECT/INSERT
+   *     privileges on TAB_1. They shouldn't be able to perform
+   *     any operation other than those listed as
+   *     requiring SELECT in the privilege model.
+   *   b) verify users from GROUP_2 can't perform queries
+   *     involving join between TAB_1 and TAB_2.
+   *   c) verify users from GROUP_1 can't perform operations
+   *     requiring ALL @SERVER scope:
+   *     *) create database
+   *     *) drop database
+   *     *) show databases
+   *     *) show locks
+   *     *) execute ALTER TABLE .. SET LOCATION on a table in DB_1
+   *     *) execute ALTER PARTITION ... SET LOCATION on a table in DB_1
+   *     *) execute CREATE EXTERNAL TABLE ... in DB_1
+   *     *) execute ADD JAR
+   *     *) execute a query with TRANSOFORM
+   * @throws Exception
+   */
+  @Test
+  public void testSandboxOpt17() throws Exception {
+
+    policyFile
+        .addRolesToGroup("group1", "all_db1", "load_data")
+        .addRolesToGroup("group2", "select_tb1")
+        .addPermissionsToRole("select_tb1", "server=server1->db=db_1->table=tbl_1->action=select")
+        .addPermissionsToRole("all_db1", "server=server1->db=db_1")
+        .addPermissionsToRole("load_data", "server=server1->uri=file://" + dataFile.toString())
+        .addGroupsToUser("user1", "group1")
+        .addGroupsToUser("user2", "group2")
+        .write(context.getPolicyFile());
+    dropDb(ADMIN1, DB1);
+    createDb(ADMIN1, DB1);
+
+    createTable(USER1, DB1, dataFile, TBL1, TBL2);
+    Connection connection = context.createConnection(USER1, "password");
+    Statement statement = context.createStatement(connection);
+    // c
+    statement.execute("USE " + DB1);
+    context.assertAuthzException(statement, "CREATE DATABASE " + DB3);
+    context.assertAuthzException(statement, "DROP DATABASE " + DB1);
+    ResultSet rs = statement.executeQuery("SHOW DATABASES");
+    assertTrue(rs.next());
+    assertEquals(DB1, rs.getString(1));
+    context.assertAuthzException(statement, "ALTER TABLE " + TBL1 +
+        " ADD PARTITION (value = 10) LOCATION '" + dataDir.getPath() + "'");
+    context.assertAuthzException(statement, "ALTER TABLE " + TBL1
+        + " PARTITION (value = 10) SET LOCATION '" + dataDir.getPath() + "'");
+    context.assertAuthzException(statement, "CREATE EXTERNAL TABLE " + TBL3
+        + " (under_col int, value string) LOCATION '" + dataDir.getPath() + "'");
+    statement.close();
+    connection.close();
+
+    connection = context.createConnection(USER2, "password");
+    statement = context.createStatement(connection);
+
+    // a
+    statement.execute("USE " + DB1);
+    context.assertAuthzException(statement, "SELECT * FROM TABLE " + TBL2 + " LIMIT 10");
+    context.assertAuthzException(statement, "EXPLAIN SELECT * FROM TABLE " + TBL2 + " WHERE under_col > 5 LIMIT 10");
+    context.assertAuthzException(statement, "DESCRIBE " + TBL2);
+    context.assertAuthzException(statement, "LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE " + TBL2);
+    context.assertAuthzException(statement, "analyze table " + TBL2 + " compute statistics for columns under_col, value");
+    // b
+    context.assertAuthzException(statement, "SELECT " + TBL1 + ".* FROM " + TBL1 + " JOIN " + TBL2 +
+        " ON (" + TBL1 + ".value = " + TBL2 + ".value)");
+    statement.close();
+    connection.close();
+  }
+
+  /**
+   * Positive and negative tests for INSERT OVERWRITE [LOCAL] DIRECTORY and
+   * LOAD DATA [LOCAL] INPATH. EXPORT/IMPORT are handled in separate junit class.
+   * Formerly testSandboxOpt18
+   */
+  @Test
+  public void testInsertOverwriteAndLoadData() throws Exception {
+    long counter = System.currentTimeMillis();
+    File allowedDir = assertCreateDir(new File(baseDir,
+        "test-" + (counter++)));
+    File restrictedDir = assertCreateDir(new File(baseDir,
+        "test-" + (counter++)));
+    Path allowedDfsDir = assertCreateDfsDir(new Path(dfsBaseDir, "test-" + (counter++)));
+    Path restrictedDfsDir = assertCreateDfsDir(new Path(dfsBaseDir, "test-" + (counter++)));
+
+    policyFile
+        .addRolesToGroup("group1", "all_db1", "load_data")
+        .addPermissionsToRole("all_db1", "server=server1->db=db_1")
+        .addPermissionsToRole("load_data", "server=server1->uri=file://" + allowedDir.getPath() +
+            ", server=server1->uri=file://" + allowedDir.getPath() +
+            ", server=server1->uri=" + allowedDfsDir.toString())
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    dropDb(ADMIN1, DB1);
+    createDb(ADMIN1, DB1);
+    createTable(ADMIN1, DB1, dataFile, TBL1);
+    Connection connection = context.createConnection(USER1, "password");
+    Statement statement = context.createStatement(connection);
+    statement.execute("USE " + DB1);
+    statement.execute("INSERT OVERWRITE LOCAL DIRECTORY 'file://" + allowedDir.getPath() + "' SELECT * FROM " + TBL1);
+    statement.execute("INSERT OVERWRITE DIRECTORY '" + allowedDfsDir + "' SELECT * FROM " + TBL1);
+    statement.execute("LOAD DATA LOCAL INPATH 'file://" + allowedDir.getPath() + "' INTO TABLE " + TBL1);
+    statement.execute("LOAD DATA INPATH '" + allowedDfsDir + "' INTO TABLE " + TBL1);
+    context.assertAuthzException(statement, "INSERT OVERWRITE LOCAL DIRECTORY 'file://" + restrictedDir.getPath() + "' SELECT * FROM " + TBL1);
+    context.assertAuthzException(statement, "INSERT OVERWRITE DIRECTORY '" + restrictedDfsDir + "' SELECT * FROM " + TBL1);
+    context.assertAuthzException(statement, "LOAD DATA INPATH 'file://" + restrictedDir.getPath() + "' INTO TABLE " + TBL1);
+    context.assertAuthzException(statement, "LOAD DATA LOCAL INPATH 'file://" + restrictedDir.getPath() + "' INTO TABLE " + TBL1);
+    statement.close();
+    connection.close();
+  }
+
+  /**
+   * test create table as with cross database ref
+   * @throws Exception
+   */
+  @Test
+  public void testSandboxOpt10() throws Exception {
+
+    String rTab1 = "rtab_1";
+    String rTab2 = "rtab_2";
+
+    policyFile
+    .addPermissionsToRole(GROUP1_ROLE, ALL_DB1, SELECT_DB2_TBL2, loadData)
+    .addRolesToGroup(GROUP1, GROUP1_ROLE)
+    .addGroupsToUser(USER1, GROUP1);
+    policyFile.write(context.getPolicyFile());
+
+    dropDb(ADMIN1, DB1, DB2);
+    createDb(ADMIN1, DB1, DB2);
+    createTable(ADMIN1, DB1, dataFile, TBL1);
+    createTable(ADMIN1, DB2, dataFile, TBL2, TBL3);
+
+    // a
+    Connection connection = context.createConnection(USER1, "password");
+    Statement statement = context.createStatement(connection);
+    statement.execute("USE " + DB1);
+    statement.execute("CREATE TABLE " + rTab1 + " AS SELECT * FROM " + DB2 + "." + TBL2);
+    // user1 doesn't have access to db2, so following create table as should fail
+    context.assertAuthzException(statement, "CREATE TABLE " + rTab2 + " AS SELECT * FROM " + DB2 + "." + TBL3);
+
+    statement.close();
+    connection.close();
+    dropDb(ADMIN1, DB1, DB2);
+  }
+
+   // Create per-db policy file on hdfs and global policy on local.
+  @Test
+  public void testPerDbPolicyOnDFS() throws Exception {
+
+    policyFile
+        .addRolesToGroup("user_group1", "select_tbl1")
+        .addRolesToGroup("user_group2", "select_tbl2")
+        .addPermissionsToRole("select_tbl1", "server=server1->db=db1->table=tbl1->action=select")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .addDatabase("db2", dfsBaseDir.toUri().toString() + "/" + DB2_POLICY_FILE)
+        .write(context.getPolicyFile());
+
+    File db2PolicyFileHandle = new File(baseDir.getPath(), DB2_POLICY_FILE);
+
+    PolicyFile db2PolicyFile = new PolicyFile();
+    db2PolicyFile
+        .addRolesToGroup("user_group2", "select_tbl2")
+        .addPermissionsToRole("select_tbl2", "server=server1->db=db2->table=tbl2->action=select")
+        .write(db2PolicyFileHandle);
+    PolicyFiles.copyFilesToDir(dfsCluster.getFileSystem(), dfsBaseDir, db2PolicyFileHandle);
+
+    // setup db objects needed by the test
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+
+    statement.execute("DROP DATABASE IF EXISTS db1 CASCADE");
+    statement.execute("DROP DATABASE IF EXISTS db2 CASCADE");
+    statement.execute("CREATE DATABASE db1");
+    statement.execute("USE db1");
+    statement.execute("CREATE TABLE tbl1(B INT, A STRING) " +
+                      " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE tbl1");
+    statement.execute("DROP DATABASE IF EXISTS db2 CASCADE");
+    statement.execute("CREATE DATABASE db2");
+    statement.execute("USE db2");
+    statement.execute("CREATE TABLE tbl2(B INT, A STRING) " +
+                      " row format delimited fields terminated by '|'  stored as textfile");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE tbl2");
+    statement.close();
+    connection.close();
+
+    // test per-db file for db2
+
+    connection = context.createConnection("user2", "password");
+    statement = context.createStatement(connection);
+    // test user2 can use db2
+    statement.execute("USE db2");
+    statement.execute("select * from tbl2");
+
+    statement.close();
+    connection.close();
+
+    //test cleanup
+    connection = context.createConnection("admin1", "hive");
+    statement = context.createStatement(connection);
+    statement.execute("DROP DATABASE db1 CASCADE");
+    statement.execute("DROP DATABASE db2 CASCADE");
+    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/TestSentryOnFailureHookLoading.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSentryOnFailureHookLoading.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSentryOnFailureHookLoading.java
new file mode 100644
index 0000000..4cfbbaa
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestSentryOnFailureHookLoading.java
@@ -0,0 +1,129 @@
+/*
+ * 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.io.Resources;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+import junit.framework.Assert;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class TestSentryOnFailureHookLoading extends AbstractTestWithHiveServer {
+
+  private Context context;
+  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>();
+    testProperties.put(HiveAuthzConf.AuthzConfVars.AUTHZ_ONFAILURE_HOOKS.getVar(),
+        DummySentryOnFailureHook.class.getName());
+    policyFile = PolicyFile.createAdminOnServer1("admin1");
+  }
+
+  @After
+  public void teardown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  /* Admin creates database DB_2
+   * user1 tries to drop DB_2, but it has permissions for DB_1.
+   */
+  @Test
+  public void testOnFailureHookLoading() throws Exception {
+
+    // Do not run this test if run with external HiveServer2
+    // This test checks for a static member, which will not
+    // be set if HiveServer2 and the test run in different JVMs
+    String hiveServer2Type = System.getProperty(
+        HiveServerFactory.HIVESERVER2_TYPE);
+    if (hiveServer2Type != null &&
+        HiveServerFactory.HiveServer2Type.valueOf(hiveServer2Type.trim()) !=
+        HiveServerFactory.HiveServer2Type.InternalHiveServer2) {
+      return;
+    }
+
+    context = createContext(testProperties);
+
+    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_group1", "all_db1", "load_data")
+        .addPermissionsToRole("all_db1", "server=server1->db=DB_1")
+        .addGroupsToUser("user1", "user_group1")
+        .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);
+
+    //negative test case: user can't drop another user's database
+    assertFalse(DummySentryOnFailureHook.invoked);
+      try {
+      statement.execute("DROP DATABASE DB_2 CASCADE");
+      Assert.fail("Expected SQL exception");
+    } catch (SQLException e) {
+      assertTrue(DummySentryOnFailureHook.invoked);
+    }
+
+    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();
+  }
+}

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/TestServerConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestServerConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestServerConfiguration.java
new file mode 100644
index 0000000..d02a193
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestServerConfiguration.java
@@ -0,0 +1,209 @@
+/*
+ * 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.assertNotNull;
+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.Map;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
+import org.apache.sentry.binding.hive.HiveAuthzBindingSessionHook;
+import org.apache.sentry.binding.hive.conf.HiveAuthzConf;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Maps;
+import com.google.common.io.Files;
+
+public class TestServerConfiguration extends AbstractTestWithHiveServer {
+
+  private Context context;
+  private Map<String, String> properties;
+  private PolicyFile policyFile;
+
+  @Before
+  public void setup() throws Exception {
+    properties = Maps.newHashMap();
+    policyFile = PolicyFile.createAdminOnServer1("admin1");
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if(context != null) {
+      context.close();
+    }
+  }
+
+  /**
+   * hive.server2.enable.impersonation must be disabled
+   */
+  @Test
+  public void testImpersonationIsDisabled() throws Exception {
+    properties.put(HiveServerFactory.ACCESS_TESTING_MODE, "false");
+    properties.put("hive.server2.enable.impersonation", "true");
+    context = createContext(properties);
+    policyFile.write(context.getPolicyFile());
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    try {
+      statement.execute("create table test (a string)");
+      Assert.fail("Expected SQLException");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+  }
+
+  /**
+   * hive.server2.authentication must be set to LDAP or KERBEROS
+   */
+  @Test
+  public void testAuthenticationIsStrong() throws Exception {
+    properties.put(HiveServerFactory.ACCESS_TESTING_MODE, "false");
+    properties.put("hive.server2.authentication", "NONE");
+    context = createContext(properties);
+    policyFile.write(context.getPolicyFile());
+    System.out.println(Files.toString(context.getPolicyFile(), Charsets.UTF_8));
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    try {
+      statement.execute("create table test (a string)");
+      Assert.fail("Expected SQLException");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+  }
+
+  /**
+   * Test removal of policy file
+   */
+  @Test
+  public void testRemovalOfPolicyFile() throws Exception {
+    context = createContext(properties);
+    File policyFile = context.getPolicyFile();
+    assertTrue("Could not delete " + policyFile, policyFile.delete());
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    try {
+      statement.execute("create table test (a string)");
+      Assert.fail("Expected SQLException");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+  }
+
+  /**
+   * Test corruption of policy file
+   */
+  @Test
+  public void testCorruptionOfPolicyFile() throws Exception {
+    context = createContext(properties);
+    File policyFile = context.getPolicyFile();
+    assertTrue("Could not delete " + policyFile, policyFile.delete());
+    FileOutputStream out = new FileOutputStream(policyFile);
+    out.write("this is not valid".getBytes(Charsets.UTF_8));
+    out.close();
+    Connection connection = context.createConnection("admin1", "hive");
+    Statement statement = context.createStatement(connection);
+    try {
+      statement.execute("create table test (a string)");
+      Assert.fail("Expected SQLException");
+    } catch (SQLException e) {
+      context.verifyAuthzException(e);
+    }
+  }
+
+  @Test
+  public void testAddDeleteDFSRestriction() throws Exception {
+    context = createContext(properties);
+
+    policyFile
+        .addRolesToGroup("group1", "all_db1")
+        .addRolesToGroup("group2", "select_tb1")
+        .addPermissionsToRole("select_tb1", "server=server1->db=db_1->table=tbl_1->action=select")
+        .addPermissionsToRole("all_db1", "server=server1->db=db_1")
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("user1", "password");
+    Statement statement = context.createStatement(connection);
+
+    // disallow external executables. The external.exec is set to false by session hooks
+    context.assertAuthzException(statement, "ADD JAR /usr/lib/hive/lib/hbase.jar");
+    context.assertAuthzException(statement, "ADD FILE /tmp/tt.py");
+    context.assertAuthzException(statement, "DFS -ls");
+    context.assertAuthzException(statement, "DELETE JAR /usr/lib/hive/lib/hbase.jar");
+    context.assertAuthzException(statement, "DELETE FILE /tmp/tt.py");
+    statement.close();
+    connection.close();
+  }
+
+  /**
+   * Test that the required access configs are set by session hook
+   */
+  @Test
+  public void testAccessConfigRestrictions() throws Exception {
+    context = createContext(properties);
+    policyFile.write(context.getPolicyFile());
+
+    String testUser = "user1";
+    // verify the config is set correctly by session hook
+    verifyConfig(testUser, ConfVars.SEMANTIC_ANALYZER_HOOK.varname,
+        HiveAuthzBindingSessionHook.SEMANTIC_HOOK);
+    verifyConfig(testUser, ConfVars.PREEXECHOOKS.varname,
+        HiveAuthzBindingSessionHook.PRE_EXEC_HOOK);
+    verifyConfig(testUser, ConfVars.HIVE_EXEC_FILTER_HOOK.varname,
+        HiveAuthzBindingSessionHook.FILTER_HOOK);
+    verifyConfig(testUser, ConfVars.HIVE_EXTENDED_ENITITY_CAPTURE.varname, "true");
+    verifyConfig(testUser, ConfVars.HIVE_SERVER2_AUTHZ_EXTERNAL_EXEC.varname, "false");
+    verifyConfig(testUser, ConfVars.SCRATCHDIRPERMISSION.varname, HiveAuthzBindingSessionHook.SCRATCH_DIR_PERMISSIONS);
+    verifyConfig(testUser, HiveConf.ConfVars.HIVE_CONF_RESTRICTED_LIST.varname,
+        HiveAuthzBindingSessionHook.ACCESS_RESTRICT_LIST);
+    verifyConfig(testUser, HiveAuthzConf.HIVE_ACCESS_SUBJECT_NAME, testUser);
+   }
+
+  private void verifyConfig(String userName, String confVar, String expectedValue) throws Exception {
+    Connection connection = context.createConnection(userName, "password");
+    Statement statement = context.createStatement(connection);
+    statement.execute("set " + confVar);
+    ResultSet res = statement.getResultSet();
+    assertTrue(res.next());
+    String configValue = res.getString(1);
+    assertNotNull(configValue);
+    String restrictListValues = (configValue.split("="))[1];
+    assertFalse(restrictListValues.isEmpty());
+    for (String restrictConfig: expectedValue.split(",")) {
+      assertTrue(restrictListValues.toLowerCase().contains(restrictConfig.toLowerCase()));
+    }
+
+  }
+}
\ 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/TestUriPermissions.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java
new file mode 100644
index 0000000..aae68e5
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java
@@ -0,0 +1,270 @@
+/*
+ * 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.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import junit.framework.Assert;
+
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestUriPermissions extends AbstractTestWithStaticLocalFS {
+  private Context context;
+  private PolicyFile policyFile;
+
+  private static final String dataFile = "/kv1.dat";
+  private String dataFilePath = this.getClass().getResource(dataFile).getFile();
+
+  @Before
+  public void setup() throws Exception {
+    context = createContext();
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+
+  // test load data into table
+  @Test
+  public void testLoadPrivileges() throws Exception {
+    String dbName = "db1";
+    String tabName = "tab1";
+    Connection userConn = null;
+    Statement userStmt = null;
+
+    policyFile
+        .addRolesToGroup("user_group1", "db1_read", "db1_write", "data_read")
+        .addRolesToGroup("user_group2", "db1_write")
+        .addPermissionsToRole("db1_write", "server=server1->db=" + dbName + "->table=" + tabName + "->action=INSERT")
+        .addPermissionsToRole("db1_read", "server=server1->db=" + dbName + "->table=" + tabName + "->action=SELECT")
+        .addPermissionsToRole("data_read", "server=server1->URI=file://" + dataFilePath
+            + ", server=server1->URI=file://" + dataFilePath)
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+
+    // create dbs
+    Connection adminCon = context.createConnection("admin1", "foo");
+    Statement adminStmt = context.createStatement(adminCon);
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.execute("use " + dbName);
+    adminStmt.execute("CREATE TABLE " + tabName + "(id int)");
+    context.close();
+
+    // positive test, user1 has access to file being loaded
+    userConn = context.createConnection("user1", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    userStmt.execute("load data local inpath '" + dataFilePath +
+        "' into table " + tabName);
+    userStmt.execute("select * from " + tabName + " limit 1");
+    ResultSet res = userStmt.getResultSet();
+    Assert.assertTrue("Table should have data after load", res.next());
+    res.close();
+    context.close();
+
+    // Negative test, user2 doesn't have access to the file being loaded
+    userConn = context.createConnection("user2", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    context.assertAuthzException(userStmt, "load data local inpath '" + dataFilePath +
+        "' into table " + tabName);
+    userStmt.close();
+    userConn.close();
+  }
+
+  // Test alter partition location
+  @Test
+  public void testAlterPartitionLocationPrivileges() throws Exception {
+    String dbName = "db1";
+    String tabName = "tab1";
+    String newPartitionDir = "foo";
+    String tabDir = "file://" + hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR) +
+      "/" + tabName + "/" + newPartitionDir;
+    Connection userConn = null;
+    Statement userStmt = null;
+
+    policyFile
+        .addRolesToGroup("user_group1", "db1_all", "data_read")
+        .addRolesToGroup("user_group2", "db1_all")
+        .addRolesToGroup("user_group3", "db1_tab1_all", "data_read")
+        .addPermissionsToRole("db1_all", "server=server1->db=" + dbName)
+        .addPermissionsToRole("db1_tab1_all", "server=server1->db=" + dbName + "->table=" + tabName)
+        .addPermissionsToRole("data_read", "server=server1->URI=" + tabDir)
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .addGroupsToUser("user3", "user_group3")
+        .write(context.getPolicyFile());
+
+    // create dbs
+    Connection adminCon = context.createConnection("admin1", "foo");
+    Statement adminStmt = context.createStatement(adminCon);
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.execute("use " + dbName);
+    adminStmt.execute("CREATE TABLE " + tabName + " (id int) PARTITIONED BY (dt string)");
+    adminCon.close();
+
+    // positive test: user1 has privilege to alter table add partition but not set location
+    userConn = context.createConnection("user1", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    userStmt.execute("ALTER TABLE " + tabName + " ADD PARTITION (dt = '21-Dec-2012') " +
+            " LOCATION '" + tabDir + "'");
+    // negative test user1 cannot alter partition location
+    context.assertAuthzException(userStmt,
+        "ALTER TABLE " + tabName + " PARTITION (dt = '21-Dec-2012') " + " SET LOCATION '" + tabDir + "'");
+    userConn.close();
+
+    // negative test: user2 doesn't have privilege to alter table add partition
+    userConn = context.createConnection("user2", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    context.assertAuthzException(userStmt,
+        "ALTER TABLE " + tabName + " ADD PARTITION (dt = '22-Dec-2012') " +
+          " LOCATION '" + tabDir + "/foo'");
+    // positive test, user2 can alter managed partitions
+    userStmt.execute("ALTER TABLE " + tabName + " ADD PARTITION (dt = '22-Dec-2012')");
+    userStmt.execute("ALTER TABLE " + tabName + " DROP PARTITION (dt = '22-Dec-2012')");
+    userConn.close();
+
+    // negative test: user3 doesn't have privilege to add/drop partitions
+    userConn = context.createConnection("user3", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    context.assertAuthzException(userStmt,
+        "ALTER TABLE " + tabName + " ADD PARTITION (dt = '22-Dec-2012') " +
+          " LOCATION '" + tabDir + "/foo'");
+    context.assertAuthzException(userStmt,
+        "ALTER TABLE " + tabName + " DROP PARTITION (dt = '21-Dec-2012')");
+    userConn.close();
+
+    // positive test: user1 has privilege to alter drop partition
+    userConn = context.createConnection("user1", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    userStmt.execute("ALTER TABLE " + tabName + " DROP PARTITION (dt = '21-Dec-2012')");
+    userStmt.close();
+    userConn.close();
+  }
+
+  // test alter table set location
+  @Test
+  public void testAlterTableLocationPrivileges() throws Exception {
+    String dbName = "db1";
+    String tabName = "tab1";
+    String tabDir = "file://" + hiveServer.getProperty(HiveServerFactory.WAREHOUSE_DIR) + "/" + tabName;
+    Connection userConn = null;
+    Statement userStmt = null;
+
+    policyFile
+        .addRolesToGroup("user_group1", "server1_all")
+        .addRolesToGroup("user_group2", "db1_all, data_read")
+        .addPermissionsToRole("db1_all", "server=server1->db=" + dbName)
+        .addPermissionsToRole("data_read", "server=server1->URI=" + tabDir)
+        .addPermissionsToRole("server1_all", "server=server1")
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+
+    // create dbs
+    Connection adminCon = context.createConnection("admin1", "foo");
+    Statement adminStmt = context.createStatement(adminCon);
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.execute("use " + dbName);
+    adminStmt.execute("CREATE TABLE " + tabName + " (id int)  PARTITIONED BY (dt string)");
+    adminCon.close();
+
+    // negative test: user2 doesn't have privilege to alter table set partition
+    userConn = context.createConnection("user2", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    context.assertAuthzException(userStmt,
+        "ALTER TABLE " + tabName + " SET LOCATION '" + tabDir +  "'");
+    userConn.close();
+
+    // positive test: user1 has privilege to alter table set partition
+    userConn = context.createConnection("user1", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    userStmt.execute("ALTER TABLE " + tabName + " SET LOCATION '" + tabDir + "'");
+    userConn.close();
+  }
+
+  // Test external table
+  @Test
+  public void testExternalTablePrivileges() throws Exception {
+    String dbName = "db1";
+    Connection userConn = null;
+    Statement userStmt = null;
+    String tableDir = "file://" + context.getDataDir();
+
+    policyFile
+        .addRolesToGroup("user_group1", "db1_all", "data_read")
+        .addRolesToGroup("user_group2", "db1_all")
+        .addPermissionsToRole("db1_all", "server=server1->db=" + dbName)
+        .addPermissionsToRole("data_read", "server=server1->URI=" + tableDir)
+        .addGroupsToUser("user1", "user_group1")
+        .addGroupsToUser("user2", "user_group2")
+        .write(context.getPolicyFile());
+
+    // create dbs
+    Connection adminCon = context.createConnection("admin1", "foo");
+    Statement adminStmt = context.createStatement(adminCon);
+    adminStmt.execute("use default");
+    adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    adminStmt.execute("CREATE DATABASE " + dbName);
+    adminStmt.close();
+    adminCon.close();
+
+    // negative test: user2 doesn't have privilege to create external table in given path
+    userConn = context.createConnection("user2", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    context.assertAuthzException(userStmt,
+        "CREATE EXTERNAL TABLE extab1(id INT) LOCATION '" + tableDir + "'");
+    context.assertAuthzException(userStmt, "CREATE TABLE extab1(id INT) LOCATION '" + tableDir + "'");
+    userStmt.close();
+    userConn.close();
+
+    // positive test: user1 has privilege to create external table in given path
+    userConn = context.createConnection("user1", "foo");
+    userStmt = context.createStatement(userConn);
+    userStmt.execute("use " + dbName);
+    userStmt.execute("CREATE EXTERNAL TABLE extab1(id INT) LOCATION '" + tableDir + "'");
+    userStmt.execute("DROP TABLE extab1");
+    userStmt.execute("CREATE TABLE extab1(id INT) LOCATION '" + tableDir + "'");
+    userStmt.close();
+    userConn.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/TestUserManagement.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUserManagement.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUserManagement.java
new file mode 100644
index 0000000..a7bb393
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUserManagement.java
@@ -0,0 +1,333 @@
+/*
+ * 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.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 TestUserManagement extends AbstractTestWithStaticLocalFS {
+  private static final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+  private static final String dbName = "db1";
+  private static final String tableName = "t1";
+  private static final String tableComment = "Test table";
+  private File dataFile;
+  private Context context;
+  private PolicyFile policyFile;
+
+  @Before
+  public void setUp() throws Exception {
+    context = createContext();
+    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();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (context != null) {
+      context.close();
+    }
+  }
+  private void doCreateDbLoadDataDropDb(String admin, String...users) throws Exception {
+    doDropDb(admin);
+    for (String user : users) {
+      doCreateDb(user);
+      Connection connection = context.createConnection(user, "password");
+      Statement statement = context.createStatement(connection);
+      ResultSet res = statement.executeQuery("SHOW DATABASES");
+      boolean created = false;
+      while (res.next()) {
+        if (res.getString(1).equals(dbName)) {
+          created = true;
+        }
+      }
+      assertTrue("database " + dbName + " is not created", created);
+      doCreateTableLoadData(user);
+      doDropDb(user);
+      statement.close();
+      connection.close();
+    }
+  }
+  private void doDropDb(String user) throws Exception {
+    Connection connection = context.createConnection(user, "password");
+    Statement statement = connection.createStatement();
+    statement.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
+    statement.close();
+    connection.close();
+  }
+  private void doCreateDb(String user) throws Exception {
+    Connection connection = context.createConnection(user, "password");
+    Statement statement = connection.createStatement();
+    statement.execute("CREATE DATABASE " + dbName);
+    statement.close();
+    connection.close();
+  }
+  private void doCreateTableLoadData(String user) throws Exception {
+    Connection connection = context.createConnection(user, "password");
+    Statement statement = context.createStatement(connection);
+    statement.execute("USE " + dbName);
+    statement.execute("CREATE TABLE " + tableName +
+        " (under_col int comment 'the under column', value string) comment '"
+        + tableComment + "'");
+    statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' into table " + tableName);
+    assertTrue(statement.execute("SELECT * FROM " + tableName));
+    statement.close();
+    connection.close();
+  }
+  /**
+   * Basic sanity test
+   */
+  @Test
+  public void testSanity() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile.write(context.getPolicyFile());
+    doCreateDbLoadDataDropDb("admin1", "admin1");
+  }
+
+  /**
+   * Tests admin privileges allow admins to create/drop dbs
+   **/
+  @Test
+  public void testAdmin1() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addGroupsToUser("admin2", "admin")
+        .addGroupsToUser("admin3", "admin")
+        .write(context.getPolicyFile());
+
+    doCreateDbLoadDataDropDb("admin1", "admin1", "admin2", "admin3");
+  }
+
+  /**
+   * Negative case: Tests that when a user is removed
+   * from the policy file their permissions have no effect
+   **/
+  @Test
+  public void testAdmin3() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addGroupsToUser("admin2", "admin")
+        .addGroupsToUser("admin3", "admin")
+        .write(context.getPolicyFile());
+    doCreateDbLoadDataDropDb("admin1", "admin1", "admin2", "admin3");
+
+    // remove admin1 from admin group
+    policyFile
+        .removeGroupsFromUser("admin1", "admin")
+        .write(context.getPolicyFile());
+    // verify admin1 doesn't have admin privilege
+    Connection connection = context.createConnection("admin1", "foo");
+    Statement statement = connection.createStatement();
+    context.assertAuthzException(statement, "CREATE DATABASE somedb");
+    statement.close();
+    connection.close();
+  }
+
+  /**
+   * Tests that users in two groups work correctly
+   **/
+  @Test
+  public void testAdmin5() throws Exception {
+    policyFile = new PolicyFile();
+    policyFile
+        .addRolesToGroup("admin_group1", "admin")
+        .addRolesToGroup("admin_group2", "admin")
+        .addPermissionsToRole("admin", "server=server1")
+        .addGroupsToUser("admin1", "admin_group1", "admin_group2")
+        .addGroupsToUser("admin2", "admin_group1", "admin_group2")
+        .addGroupsToUser("admin3", "admin_group1", "admin_group2")
+        .write(context.getPolicyFile());
+    doCreateDbLoadDataDropDb("admin1", "admin1", "admin2", "admin3");
+  }
+
+  /**
+   * Tests admin group does not infect non-admin group
+   **/
+  @Test
+  public void testAdmin6() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addRolesToGroup("group1", "non_admin_role")
+        .addPermissionsToRole("non_admin_role", "server=server1->db=" + dbName)
+        .addGroupsToUser("user1", "group1")
+        .write(context.getPolicyFile());
+
+    doCreateDbLoadDataDropDb("admin1", "admin1");
+    Connection connection = context.createConnection("user1", "password");
+    Statement statement = connection.createStatement();
+    context.assertAuthzException(statement, "CREATE DATABASE " + dbName);
+    statement.close();
+    connection.close();
+  }
+
+  /**
+   * Tests that user with two roles the most powerful role takes effect
+   **/
+  @Test
+  public void testGroup2() throws Exception {
+    policyFile = new PolicyFile();
+    policyFile
+        .addRolesToGroup("group1", "admin", "analytics")
+        .addPermissionsToRole("admin", "server=server1")
+        .addPermissionsToRole("analytics", "server=server1->db=" + dbName)
+        .addGroupsToUser("user1", "group1")
+        .addGroupsToUser("user2", "group1")
+        .addGroupsToUser("user3", "group1")
+        .write(context.getPolicyFile());
+    doCreateDbLoadDataDropDb("user1", "user1", "user2", "user3");
+  }
+  /**
+   * Tests that user without uri privilege can create table but not load data
+   **/
+  @Test
+  public void testGroup4() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addRolesToGroup("group1", "non_admin_role", "load_data")
+        .addPermissionsToRole("non_admin_role", "server=server1->db=" + dbName)
+        .addGroupsToUser("user1", "group1")
+        .addGroupsToUser("user2", "group1")
+        .addGroupsToUser("user3", "group1")
+        .write(context.getPolicyFile());
+
+    doDropDb("admin1");
+    for(String user : new String[]{"user1", "user2", "user3"}) {
+      doCreateDb("admin1");
+      Connection connection = context.createConnection(user, "password");
+      Statement statement = context.createStatement(connection);
+      statement.execute("USE " + dbName);
+      statement.execute("CREATE TABLE " + tableName +
+          " (under_col int comment 'the under column', value string) comment '"
+          + tableComment + "'");
+      context.assertAuthzException(statement,
+          "LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' into table " + tableName);
+      assertTrue(statement.execute("SELECT * FROM " + tableName));
+      statement.close();
+      connection.close();
+      doDropDb("admin1");
+    }
+  }
+  /**
+   * Tests users can have same name as groups
+   **/
+  @Test
+  public void testGroup5() throws Exception {
+
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addRolesToGroup("group1", "non_admin_role", "load_data")
+        .addPermissionsToRole("non_admin_role", "server=server1->db=" + dbName)
+        .addPermissionsToRole("load_data", "server=server1->URI=file://" + dataFile.getPath())
+        .addGroupsToUser("group1", "group1")
+        .addGroupsToUser("user2", "group1")
+        .addGroupsToUser("user3", "group1")
+        .write(context.getPolicyFile());
+
+    doDropDb("admin1");
+    for(String user : new String[]{"group1", "user2", "user3"}) {
+      doCreateDb("admin1");
+      doCreateTableLoadData(user);
+      doDropDb("admin1");
+    }
+  }
+
+  /**
+   * Tests that group names with special characters are handled correctly
+   **/
+  @Test
+  public void testGroup6() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addRolesToGroup("group1~!@#$%^&*()+-", "analytics", "load_data")
+        .addPermissionsToRole("analytics", "server=server1->db=" + dbName)
+        .addPermissionsToRole("load_data", "server=server1->URI=file://" + dataFile.getPath())
+        .addGroupsToUser("user1", "group1~!@#$%^&*()+-")
+        .addGroupsToUser("user2", "group1~!@#$%^&*()+-")
+        .addGroupsToUser("user3", "group1~!@#$%^&*()+-")
+        .write(context.getPolicyFile());
+
+    doDropDb("admin1");
+    for(String user : new String[]{"user1", "user2", "user3"}) {
+      doCreateDb("admin1");
+      doCreateTableLoadData(user);
+      doDropDb("admin1");
+    }
+  }
+
+  /**
+   * Tests that user names with special characters are handled correctly
+   **/
+  @Test
+  public void testGroup7() throws Exception {
+    policyFile = new PolicyFile();
+    policyFile
+        .addRolesToGroup("group1", "admin")
+        .addPermissionsToRole("admin", "server=server1")
+        .addGroupsToUser("user1~!@#$%^&*()+-", "group1")
+        .addGroupsToUser("user2", "group1")
+        .addGroupsToUser("user3", "group1")
+        .write(context.getPolicyFile());
+    doCreateDbLoadDataDropDb("user1~!@#$%^&*()+-", "user1~!@#$%^&*()+-", "user2", "user3");
+  }
+
+  /**
+   * Tests that users with no privileges cannot list any tables
+   **/
+  @Test
+  public void testGroup8() throws Exception {
+    policyFile = PolicyFile.createAdminOnServer1(ADMIN1);
+    policyFile
+        .addRolesToGroup("group1", "analytics")
+        .addGroupsToUser("user1", "group1")
+        .addGroupsToUser("user2", "group1")
+        .addGroupsToUser("user3", "group1")
+        .write(context.getPolicyFile());
+
+    Connection connection = context.createConnection("admin1", "password");
+    Statement statement = connection.createStatement();
+    statement.execute("DROP DATABASE IF EXISTS db1 CASCADE");
+    statement.execute("CREATE DATABASE db1");
+    statement.execute("USE db1");
+    statement.execute("CREATE TABLE t1 (under_col int, value string)");
+    statement.close();
+    connection.close();
+    String[] users = { "user1", "user2", "user3" };
+    for (String user : users) {
+      connection = context.createConnection(user, "foo");
+      statement = context.createStatement(connection);
+      assertFalse("No results should be returned",
+          statement.executeQuery("SHOW TABLES").next());
+      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/hiveserver/AbstractHiveServer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
new file mode 100644
index 0000000..24a6fe9
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/AbstractHiveServer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.hiveserver;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
+
+import com.google.common.base.Strings;
+
+public abstract class AbstractHiveServer implements HiveServer {
+
+  private static final String LINK_FAILURE_SQL_STATE = "08S01";
+
+  private final Configuration configuration;
+  private final String hostname;
+  private final int port;
+
+  public AbstractHiveServer(Configuration configuration, String hostname,
+      int port) {
+    this.configuration = configuration;
+    this.hostname = hostname;
+    this.port = port;
+  }
+
+  @Override
+  public String getProperty(String key) {
+    return configuration.get(key);
+  }
+
+  @Override
+  public String getURL() {
+    return "jdbc:hive2://" + hostname + ":" + port + "/default";
+  }
+
+  public Connection createConnection(String user, String password) throws Exception{
+    String url = getURL();
+    Connection connection =  DriverManager.getConnection(url, user, password);
+    return connection;
+  }
+
+  protected static String getHostname(HiveConf hiveConf) {
+    return hiveConf.get(ConfVars.HIVE_SERVER2_THRIFT_BIND_HOST.toString(), "localhost").trim();
+  }
+  protected static int getPort(HiveConf hiveConf) {
+    return Integer.parseInt(hiveConf.get(ConfVars.HIVE_SERVER2_THRIFT_PORT.toString(), "10000").trim());
+  }
+  protected static void waitForStartup(HiveServer hiveServer) throws Exception {
+    int waitTime = 0;
+    long startupTimeout = 1000L * 10L;
+    do {
+      Thread.sleep(500L);
+      waitTime += 500L;
+      if (waitTime > startupTimeout) {
+        throw new TimeoutException("Couldn't access new HiveServer: " + hiveServer.getURL());
+      }
+      try {
+        Connection connection =  DriverManager.getConnection(hiveServer.getURL(), "hive", "bar");
+        connection.close();
+        break;
+      } catch (SQLException e) {
+        String state = Strings.nullToEmpty(e.getSQLState()).trim();
+        if (!state.equalsIgnoreCase(LINK_FAILURE_SQL_STATE)) {
+          throw e;
+        }
+      }
+    } while (true);
+  }
+}

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/hiveserver/EmbeddedHiveServer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/EmbeddedHiveServer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/EmbeddedHiveServer.java
new file mode 100644
index 0000000..853f75a
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/EmbeddedHiveServer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.hiveserver;
+
+import org.apache.hadoop.hive.metastore.HiveMetaStore;
+import org.fest.reflect.core.Reflection;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+
+public class EmbeddedHiveServer implements HiveServer {
+
+  @Override
+  public void start() {
+    // Fix for ACCESS-148. Resets a static field
+    // so the default database is created even
+    // though is has been created before in this JVM
+    Reflection.staticField("createDefaultDB")
+    .ofType(boolean.class)
+    .in(HiveMetaStore.HMSHandler.class)
+    .set(false);
+  }
+
+  public Connection createConnection(String user, String password) throws Exception{
+    String url = getURL();
+    Connection connection =  DriverManager.getConnection(url, user, password);
+    return connection;
+  }
+
+  @Override
+  public void shutdown() {
+
+  }
+
+  @Override
+  public String getURL() {
+    return "jdbc:hive2://";
+  }
+
+  @Override
+  public String getProperty(String key) {
+    throw new UnsupportedOperationException();
+  }
+}

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/hiveserver/ExternalHiveServer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/ExternalHiveServer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/ExternalHiveServer.java
new file mode 100644
index 0000000..88edc08
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/ExternalHiveServer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.hiveserver;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+
+public class ExternalHiveServer extends AbstractHiveServer {
+  private static final Logger LOGGER = LoggerFactory
+      .getLogger(ExternalHiveServer.class);
+  private final File confDir;
+  private final File logDir;
+  private Process process;
+
+  public ExternalHiveServer(HiveConf hiveConf, File confDir, File logDir) throws Exception {
+    super(hiveConf, getHostname(hiveConf), getPort(hiveConf));
+    this.confDir = confDir;
+    this.logDir = logDir;
+  }
+
+
+  @Override
+  public synchronized void start() throws Exception {
+    String hiveCommand = System.getProperty("hive.bin.path", "./target/hive/bin/hive");
+    String hadoopHome = System.getProperty("hadoop.home", "./target/hadoop");
+    String hadoopClasspath = getHadoopClasspath();
+    String command = "export ";
+    command += String.format("HIVE_CONF_DIR=\"%s\" HADOOP_HOME=\"%s\" ", confDir.getPath(), hadoopHome);
+    command += String.format("HADOOP_CLASSPATH=\"%s:%s\" ", confDir.getPath(), hadoopClasspath);
+    command += "HADOOP_CLIENT_OPTS=\"-Dhive.log.dir=./target/\"";
+    command += "; ";
+    command += String.format("%s --service hiveserver2 >%s/hs2.out 2>&1 & echo $! > %s/hs2.pid",
+        hiveCommand, logDir.getPath(), logDir.getPath());
+    LOGGER.info("Executing " + command);
+    process = Runtime.getRuntime().
+        exec(new String[]{"/bin/sh", "-c", command});
+    waitForStartup(this);
+  }
+
+  @Override
+  public synchronized void shutdown() throws Exception {
+    if(process != null) {
+      process.destroy();
+      process = null;
+      String pid = Strings.nullToEmpty(Files.readFirstLine(new File(logDir, "hs2.pid"), Charsets.UTF_8)).trim();
+      if(!pid.isEmpty()) {
+        LOGGER.info("Killing " + pid);
+        Process killCommand = Runtime.getRuntime().
+            exec(new String[]{"/bin/sh", "-c", "kill " + pid});
+        // TODO this isn't strictly correct but kill won't output much data
+        String error = read(killCommand.getErrorStream());
+        String output = read(killCommand.getInputStream());
+        LOGGER.info("Kill exit code " + killCommand.waitFor() +
+            ", output = '" + output + "', error = '" + error + "'");
+      }
+    }
+  }
+
+  private String read(InputStream is) throws IOException {
+    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+    StringBuffer buffer = new StringBuffer();
+    try {
+      String line;
+      while((line = reader.readLine()) != null) {
+        buffer.append(line);
+      }
+      return buffer.toString();
+    } finally {
+      reader.close();
+    }
+
+  }
+
+  private String getHadoopClasspath() {
+    List<String> result = Lists.newArrayList();
+    String clazzPath = Preconditions.checkNotNull(System.getProperty("java.class.path"), "java.class.path");
+    String sep = Preconditions.checkNotNull(System.getProperty("path.separator"), "path.separator");
+    for(String item : Splitter.on(sep).omitEmptyStrings().trimResults().split(clazzPath)) {
+      if(item.endsWith("/sentry-tests/target/classes") ||
+          item.endsWith("/sentry-tests/target/test-classes")) {
+        result.add(item);
+      } else {
+        File clazzPathItem = new File(item);
+        String fileName = clazzPathItem.getName();
+        if(clazzPathItem.isFile() && fileName.startsWith("sentry-") && fileName.endsWith(".jar")) {
+          result.add(item);
+        }
+      }
+    }
+    return Joiner.on(sep).join(result);
+  }
+
+}

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/hiveserver/HiveServer.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServer.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServer.java
new file mode 100644
index 0000000..ee6155b
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/hiveserver/HiveServer.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hiveserver;
+
+import java.sql.Connection;
+
+public interface HiveServer {
+
+  public void start() throws Exception;
+
+  public void shutdown() throws Exception;
+
+  public String getURL();
+
+  public String getProperty(String key);
+
+  public Connection createConnection(String user, String password) throws Exception;
+
+}