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;
+
+}