http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataPermissions.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataPermissions.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataPermissions.java new file mode 100644 index 0000000..05420d1 --- /dev/null +++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMetadataPermissions.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.tests.e2e.hive; + +import java.sql.Connection; +import java.sql.Statement; + +import org.junit.Assert; + +import org.apache.sentry.provider.file.PolicyFile; +import org.junit.Before; +import org.junit.Test; + + +public class TestMetadataPermissions extends AbstractTestWithStaticConfiguration { + private PolicyFile policyFile; + + @Before + public void setup() throws Exception { + policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP); + policyFile.setUserGroupMapping(StaticUserGroup.getStaticMapping()); + writePolicyFile(policyFile); + + Connection adminCon = context.createConnection(ADMIN1); + Statement adminStmt = context.createStatement(adminCon); + for (String dbName : new String[] { "" + DB1, DB2 }) { + adminStmt.execute("USE default"); + adminStmt.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE"); + adminStmt.execute("CREATE DATABASE " + dbName); + adminStmt.execute("USE " + dbName); + for (String tabName : new String[] { "tab1", "tab2" }) { + adminStmt.execute("CREATE TABLE " + tabName + " (id int)"); + } + } + + policyFile + .addRolesToGroup(USERGROUP1, "db1_all", "db2_all") + .addRolesToGroup(USERGROUP2, "db1_all") + .addPermissionsToRole("db1_all", "server=server1->db=" + DB1) + .addPermissionsToRole("db2_all", "server=server1->db=" + DB2); + + writePolicyFile(policyFile); + } + + /** + * Ensure that a user with no privileges on a database cannot + * query that databases metadata. + */ + @Test + public void testDescPrivilegesNegative() throws Exception { + Connection connection = context.createConnection(USER2_1); + Statement statement = context.createStatement(connection); + context.assertAuthzException(statement, "USE " + DB2); +// TODO when DESCRIBE db.table is supported tests should be uncommented +// for (String tabName : new String[] { "tab1", "tab2" }) { +// context.assertAuthzException(statement, "DESCRIBE " + DB1 + "." + tabName); +// context.assertAuthzException(statement, "DESCRIBE EXTENDED " + DB1 + "." + tabName); +// } + statement.close(); + connection.close(); + } + + /** + * Ensure that a user cannot describe databases to which the user + * has no privilege. + */ + @Test + public void testDescDbPrivilegesNegative() throws Exception { + Connection connection = context.createConnection(USER2_1); + Statement statement = context.createStatement(connection); + context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2); + context.assertAuthzException(statement, "DESCRIBE DATABASE EXTENDED " + DB2); + statement.close(); + connection.close(); + } + + /** + * Ensure that a user with privileges on a database can describe + * the database. + */ + @Test + public void testDescDbPrivilegesPositive() throws Exception { + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + for (String dbName : new String[] { DB1, DB2 }) { + statement.execute("USE " + dbName); + Assert.assertTrue(statement.executeQuery("DESCRIBE DATABASE " + dbName).next()); + Assert.assertTrue(statement.executeQuery("DESCRIBE DATABASE EXTENDED " + dbName).next()); + } + statement.close(); + connection.close(); + } + + /** + * Ensure that a user with privileges on a table can describe the table. + */ + @Test + public void testDescPrivilegesPositive() throws Exception { + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + for (String dbName : new String[] { DB1, DB2 }) { + statement.execute("USE " + dbName); + Assert.assertTrue(statement.executeQuery("DESCRIBE DATABASE " + dbName).next()); + for (String tabName : new String[] { "tab1", "tab2" }) { + Assert.assertTrue(statement.executeQuery("DESCRIBE " + tabName).next()); + Assert.assertTrue(statement.executeQuery("DESCRIBE EXTENDED " + tabName).next()); + + } + } + statement.close(); + connection.close(); + } + +}
http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMovingToProduction.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMovingToProduction.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMovingToProduction.java new file mode 100644 index 0000000..a6edf03 --- /dev/null +++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestMovingToProduction.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.tests.e2e.hive; + +import org.apache.sentry.provider.file.PolicyFile; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.junit.Before; +import org.junit.Test; + +import com.google.common.io.Resources; + +public class TestMovingToProduction extends AbstractTestWithStaticConfiguration { + private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat"; + private PolicyFile policyFile; + + + @Before + public void setup() throws Exception { + 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 = PolicyFile.setAdminOnServer1(ADMINGROUP) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()); + writePolicyFile(policyFile); + } + + /** + * Steps: + * 1. admin create DB_1, admin create GROUP_1, GROUP_2 + * 2. admin grant all to GROUP_1 on DB_1 + * 3. user in GROUP_1 create table tb_1 and load data into + * 4. admin create table production.tb_1. + * 5. admin grant all to GROUP_1 on production.tb_1. + * positive test cases: + * a)verify user in GROUP_1 can load data from DB_1.tb_1 to production.tb_1 + * b)verify user in GROUP_1 has proper privilege on production.tb_1 + * (read and insert) + * negative test cases: + * c)verify user in GROUP_2 cannot load data from DB_1.tb_1 + * to production.tb_1 + * d)verify user in GROUP_1 cannot drop production.tb_1 + */ + @Test + public void testMovingTable1() throws Exception { + String tableName1 = "tb_1"; + Connection connection = context.createConnection(ADMIN1); + 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("CREATE DATABASE " + DB2); + statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + tableName1); + statement.execute("create table " + DB2 + "." + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.close(); + connection.close(); + + policyFile + .addRolesToGroup(USERGROUP1, "all_db1", "load_data") + .addPermissionsToRole("load_data", "server=server1->uri=file://" + dataDir.getPath()) + .addPermissionsToRole("all_db1", "server=server1->db=" + DB1); + writePolicyFile(policyFile); + + + // a + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB1); + statement.execute("DROP TABLE IF EXISTS " + tableName1); + statement.execute("create table " + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.execute("LOAD DATA LOCAL INPATH 'file://" + dataDir.getPath() + + "' INTO TABLE " + tableName1); + + policyFile + .addRolesToGroup(USERGROUP1, "insert_proddb_tbl1") + .addPermissionsToRole("insert_proddb_tbl1", "server=server1->db=" + DB2 + "->table=tb_1->action=insert"); + writePolicyFile(policyFile); + statement.execute("USE " + DB2); + statement.execute("INSERT OVERWRITE TABLE " + + tableName1 + " SELECT * FROM " + DB1 + + "." + tableName1); + + // b + policyFile + .addRolesToGroup(USERGROUP1, "select_proddb_tbl1") + .addPermissionsToRole("select_proddb_tbl1", "server=server1->db=" + DB2 + "->table=tb_1->action=select"); + writePolicyFile(policyFile); + + ResultSet resultSet = statement.executeQuery("SELECT * FROM " + tableName1 + " LIMIT 10"); + int count = 0; + while(resultSet.next()) { + count++; + } + assertEquals(10, count); + statement.execute("DESCRIBE " + tableName1); + + // c + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + context.assertAuthzException(statement, "USE " + DB2); + context.assertAuthzException(statement, "INSERT OVERWRITE TABLE " + + DB2 + "." + tableName1 + " SELECT * FROM " + DB1 + + "." + tableName1); + context.assertAuthzException(statement, "SELECT * FROM " + DB2 + "." + tableName1 + " LIMIT 10"); + statement.close(); + connection.close(); + + // d + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + context.assertAuthzException(statement, "DROP TABLE " + tableName1); + statement.close(); + connection.close(); + } + + /** + * repeat above tests, only difference is don't do 'USE <database>' + * in this test. Instead, access table objects across database by + * database.table + * @throws Exception + */ + @Test + public void testMovingTable2() throws Exception { + String tableName1 = "tb_1"; + Connection connection = context.createConnection(ADMIN1); + 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("CREATE DATABASE " + DB2); + statement.execute("DROP TABLE IF EXISTS " + DB2 + "." + tableName1); + statement.execute("create table " + DB2 + "." + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.close(); + connection.close(); + + policyFile + .addRolesToGroup(USERGROUP1, "all_db1", "load_data") + .addPermissionsToRole("all_db1", "server=server1->db=" + DB1) + .addPermissionsToRole("load_data", "server=server1->uri=file://" + dataDir.getPath()); + writePolicyFile(policyFile); + + // a + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("DROP TABLE IF EXISTS " + DB1 + "." + tableName1); + statement.execute("create table " + DB1 + "." + tableName1 + + " (under_col int comment 'the under column', value string)"); + statement.execute("LOAD DATA LOCAL INPATH 'file://" + dataDir.getPath() + + "' INTO TABLE " + DB1 + "." + tableName1); + + policyFile + .addRolesToGroup(USERGROUP1, "insert_proddb_tbl1") + .addPermissionsToRole("insert_proddb_tbl1", "server=server1->db=" + DB2 + "->table=tb_1->action=insert"); + writePolicyFile(policyFile); + + statement.execute("INSERT OVERWRITE TABLE " + + DB2 + "." + tableName1 + " SELECT * FROM " + DB1 + + "." + tableName1); + + // b + policyFile + .addRolesToGroup(USERGROUP1, "select_proddb_tbl1") + .addPermissionsToRole("select_proddb_tbl1", "server=server1->db=" + DB2 + "->table=tb_1->action=select"); + writePolicyFile(policyFile); + + assertTrue("user1 should be able to select data from " + + DB2 + "." + DB2 + "." + tableName1, statement.execute("SELECT * FROM " + + DB2 + "." + tableName1 + " LIMIT 10")); + assertTrue("user1 should be able to describe table " + DB2 + "." + tableName1, + statement.execute("DESCRIBE " + DB2 + "." + tableName1)); + + // c + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + + context.assertAuthzException(statement, "INSERT OVERWRITE TABLE " + + DB2 + "." + tableName1 + " SELECT * FROM " + DB1 + + "." + tableName1); + + context.assertAuthzException(statement, "SELECT * FROM " + + DB2 + "." + tableName1 + " LIMIT 10"); + statement.close(); + connection.close(); + + // d + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + context.assertAuthzException(statement, "DROP TABLE " + tableName1); + statement.close(); + connection.close(); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestOperations.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestOperations.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestOperations.java new file mode 100644 index 0000000..06a5752 --- /dev/null +++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestOperations.java @@ -0,0 +1,1116 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.tests.e2e.hive; + +import java.io.File; +import java.io.FileOutputStream; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.sentry.provider.file.PolicyFile; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.google.common.io.Resources; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestOperations extends AbstractTestWithStaticConfiguration { + private static final Logger LOGGER = LoggerFactory + .getLogger(TestOperations.class); + + private PolicyFile policyFile; + final String tableName = "tb1"; + + static Map<String, String> privileges = new HashMap<String, String>(); + static { + privileges.put("all_server", "server=server1->action=all"); + privileges.put("create_server", "server=server1->action=create"); + privileges.put("all_db1", "server=server1->db=" + DB1 + "->action=all"); + privileges.put("select_db1", "server=server1->db=" + DB1 + "->action=select"); + privileges.put("insert_db1", "server=server1->db=" + DB1 + "->action=insert"); + privileges.put("create_db1", "server=server1->db=" + DB1 + "->action=create"); + privileges.put("drop_db1", "server=server1->db=" + DB1 + "->action=drop"); + privileges.put("alter_db1", "server=server1->db=" + DB1 + "->action=alter"); + privileges.put("create_db2", "server=server1->db=" + DB2 + "->action=create"); + + privileges.put("all_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=all"); + privileges.put("select_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=select"); + privileges.put("insert_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=insert"); + privileges.put("alter_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=alter"); + privileges.put("alter_db1_ptab", "server=server1->db=" + DB1 + "->table=ptab->action=alter"); + privileges.put("index_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=index"); + privileges.put("lock_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=lock"); + privileges.put("drop_db1_tb1", "server=server1->db=" + DB1 + "->table=tb1->action=drop"); + privileges.put("insert_db2_tb2", "server=server1->db=" + DB2 + "->table=tb2->action=insert"); + privileges.put("select_db1_view1", "server=server1->db=" + DB1 + "->table=view1->action=select"); + + } + + @Before + public void setup() throws Exception{ + policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()); + writePolicyFile(policyFile); + } + + private void adminCreate(String db, String table) throws Exception{ + adminCreate(db, table, false); + } + + private void adminCreate(String db, String table, boolean partitioned) throws Exception{ + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("DROP DATABASE IF EXISTS " + db + " CASCADE"); + statement.execute("CREATE DATABASE " + db); + if(table !=null) { + if (partitioned) { + statement.execute("CREATE table " + db + "." + table + " (a string) PARTITIONED BY (b string)"); + } else{ + statement.execute("CREATE table " + db + "." + table + " (a string)"); + } + + } + statement.close(); + connection.close(); + } + + private void adminCreatePartition() throws Exception{ + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("USE " + DB1); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '1') "); + statement.close(); + connection.close(); + } + + /* Test all operations that require create on Server + 1. Create database : HiveOperation.CREATEDATABASE + */ + @Test + public void testCreateOnServer() throws Exception{ + policyFile + .addPermissionsToRole("create_server", privileges.get("create_server")) + .addRolesToGroup(USERGROUP1, "create_server"); + + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Create database " + DB2); + statement.close(); + connection.close(); + + //Negative case + policyFile + .addPermissionsToRole("create_db1", privileges.get("create_db1")) + .addRolesToGroup(USERGROUP2, "create_db1"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + context.assertSentrySemanticException(statement, "CREATE database " + DB1, semanticException); + statement.close(); + connection.close(); + + } + + @Test + public void testInsertInto() throws Exception{ + File dataFile; + 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(); + + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addPermissionsToRole("all_uri", "server=server1->uri=file://" + dataDir) + .addRolesToGroup(USERGROUP1, "all_db1", "all_uri"); + + + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("create table bar (key int)"); + statement.execute("load data local inpath '" + dataFile.getPath() + "' into table bar"); + statement.execute("create table foo (key int) partitioned by (part int) stored as parquet"); + statement.execute("insert into table foo PARTITION(part=1) select key from bar"); + + statement.close(); + connection.close(); + } + + /* Test all operations that require create on Database alone + 1. Create table : HiveOperation.CREATETABLE + */ + @Test + public void testCreateOnDatabase() throws Exception{ + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("create_db1", privileges.get("create_db1")) + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addRolesToGroup(USERGROUP1, "create_db1") + .addRolesToGroup(USERGROUP2, "all_db1"); + + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("CREATE TABLE " + DB1 + ".tb2(a int)"); + statement.close(); + connection.close(); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("CREATE TABLE " + DB1 + ".tb3(a int)"); + + statement.close(); + connection.close(); + + //Negative case + policyFile + .addPermissionsToRole("all_db1_tb1", privileges.get("select_db1")) + .addRolesToGroup(USERGROUP3, "all_db1_tb1"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertSentrySemanticException(statement, "CREATE TABLE " + DB1 + ".tb1(a int)", semanticException); + statement.close(); + connection.close(); + } + + /* Test all operations that require drop on Database alone + 1. Drop database : HiveOperation.DROPDATABASE + */ + @Test + public void testDropOnDatabase() throws Exception{ + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("drop_db1", privileges.get("drop_db1")) + .addRolesToGroup(USERGROUP1, "drop_db1"); + + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("DROP DATABASE " + DB1); + statement.close(); + connection.close(); + + adminCreate(DB1, null); + + policyFile + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addRolesToGroup(USERGROUP2, "all_db1"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("DROP DATABASE " + DB1); + + statement.close(); + connection.close(); + + //Negative case + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("select_db1", privileges.get("select_db1")) + .addRolesToGroup(USERGROUP3, "select_db1"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertSentrySemanticException(statement, "drop database " + DB1, semanticException); + statement.close(); + connection.close(); + } + + /* Test all operations that require alter on Database alone + 1. Alter database : HiveOperation.ALTERDATABASE + */ + @Test + public void testAlterOnDatabase() throws Exception{ + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("alter_db1", privileges.get("alter_db1")) + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addRolesToGroup(USERGROUP2, "all_db1") + .addRolesToGroup(USERGROUP1, "alter_db1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("ALTER DATABASE " + DB1 + " SET DBPROPERTIES ('comment'='comment')"); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("ALTER DATABASE " + DB1 + " SET DBPROPERTIES ('comment'='comment')"); + statement.close(); + connection.close(); + + //Negative case + adminCreate(DB1, null); + policyFile + .addPermissionsToRole("select_db1", privileges.get("select_db1")) + .addRolesToGroup(USERGROUP3, "select_db1"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertSentrySemanticException(statement, "ALTER DATABASE " + DB1 + " SET DBPROPERTIES ('comment'='comment')", semanticException); + statement.close(); + connection.close(); + } + + /* SELECT/INSERT on DATABASE + 1. HiveOperation.DESCDATABASE + */ + @Test + public void testDescDB() throws Exception { + adminCreate(DB1, tableName); + policyFile + .addPermissionsToRole("select_db1", privileges.get("select_db1")) + .addPermissionsToRole("insert_db1", privileges.get("insert_db1")) + .addRolesToGroup(USERGROUP1, "select_db1") + .addRolesToGroup(USERGROUP2, "insert_db1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("describe database " + DB1); + statement.close(); + connection.close(); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("describe database " + DB1); + statement.close(); + connection.close(); + + //Negative case + policyFile + .addPermissionsToRole("all_db1_tb1", privileges.get("all_db1_tb1")) + .addRolesToGroup(USERGROUP3, "all_db1_tb1"); + writePolicyFile(policyFile); + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertSentrySemanticException(statement, "describe database " + DB1, semanticException); + statement.close(); + connection.close(); + + } + + private void assertSemanticException(Statement stmt, String command) throws SQLException{ + context.assertSentrySemanticException(stmt, command, semanticException); + } + + /* + 1. Analyze table (HiveOperation.QUERY) : select + insert on table + */ + @Test + public void testSelectAndInsertOnTable() throws Exception { + adminCreate(DB1, tableName, true); + adminCreatePartition(); + policyFile + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP1, "select_db1_tb1", "insert_db1_tb1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ANALYZE TABLE tb1 PARTITION (b='1' ) COMPUTE STATISTICS"); + statement.close(); + connection.close(); + } + + /* Operations which require select on table alone + 1. HiveOperation.QUERY + 2. HiveOperation.SHOW_TBLPROPERTIES + 3. HiveOperation.SHOW_CREATETABLE + 4. HiveOperation.SHOWINDEXES + 5. HiveOperation.SHOWCOLUMNS + 6. Describe tb1 : HiveOperation.DESCTABLE5. + 7. HiveOperation.SHOWPARTITIONS + 8. TODO: show functions? + 9. HiveOperation.SHOW_TABLESTATUS + */ + @Test + public void testSelectOnTable() throws Exception { + adminCreate(DB1, tableName, true); + adminCreatePartition(); + policyFile + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addRolesToGroup(USERGROUP1, "select_db1_tb1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("select * from tb1"); + + statement.executeQuery("SHOW Partitions tb1"); + statement.executeQuery("SHOW TBLPROPERTIES tb1"); + statement.executeQuery("SHOW CREATE TABLE tb1"); + statement.executeQuery("SHOW indexes on tb1"); + statement.executeQuery("SHOW COLUMNS from tb1"); + statement.executeQuery("SHOW functions '.*'"); + statement.executeQuery("SHOW TABLE EXTENDED IN " + DB1 + " LIKE 'tb*'"); + + statement.executeQuery("DESCRIBE tb1"); + statement.executeQuery("DESCRIBE tb1 PARTITION (b=1)"); + + statement.close(); + connection.close(); + + //Negative case + adminCreate(DB2, tableName); + policyFile + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP3, "insert_db1_tb1"); + writePolicyFile(policyFile); + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + context.assertSentrySemanticException(statement, "select * from tb1", semanticException); + context.assertSentrySemanticException(statement, + "SHOW TABLE EXTENDED IN " + DB2 + " LIKE 'tb*'", semanticException); + + statement.close(); + connection.close(); + + + } + + /* Operations which require insert on table alone + 1. HiveOperation.SHOW_TBLPROPERTIES + 2. HiveOperation.SHOW_CREATETABLE + 3. HiveOperation.SHOWINDEXES + 4. HiveOperation.SHOWCOLUMNS + 5. HiveOperation.DESCTABLE + 6. HiveOperation.SHOWPARTITIONS + 7. TODO: show functions? + 8. TODO: lock, unlock, Show locks + 9. HiveOperation.SHOW_TABLESTATUS + */ + @Test + public void testInsertOnTable() throws Exception { + adminCreate(DB1, tableName, true); + adminCreatePartition(); + policyFile + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP1, "insert_db1_tb1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + /*statement.execute("LOCK TABLE tb1 EXCLUSIVE"); + statement.execute("UNLOCK TABLE tb1"); + */ + statement.executeQuery("SHOW TBLPROPERTIES tb1"); + statement.executeQuery("SHOW CREATE TABLE tb1"); + statement.executeQuery("SHOW indexes on tb1"); + statement.executeQuery("SHOW COLUMNS from tb1"); + statement.executeQuery("SHOW functions '.*'"); + //statement.executeQuery("SHOW LOCKS tb1"); + statement.executeQuery("SHOW TABLE EXTENDED IN " + DB1 + " LIKE 'tb*'"); + + //NoViableAltException + //statement.executeQuery("SHOW transactions"); + //statement.executeQuery("SHOW compactions"); + statement.executeQuery("DESCRIBE tb1"); + statement.executeQuery("DESCRIBE tb1 PARTITION (b=1)"); + statement.executeQuery("SHOW Partitions tb1"); + + + statement.close(); + connection.close(); + } + + /* Test all operations that require alter on table + 1. HiveOperation.ALTERTABLE_PROPERTIES + 2. HiveOperation.ALTERTABLE_SERDEPROPERTIES + 3. HiveOperation.ALTERTABLE_CLUSTER_SORT + 4. HiveOperation.ALTERTABLE_TOUCH + 5. HiveOperation.ALTERTABLE_PROTECTMODE + 6. HiveOperation.ALTERTABLE_FILEFORMAT + 7. HiveOperation.ALTERTABLE_RENAMEPART + 8. HiveOperation.ALTERPARTITION_SERDEPROPERTIES + 9. TODO: archive partition + 10. TODO: unarchive partition + 11. HiveOperation.ALTERPARTITION_FILEFORMAT + 12. TODO: partition touch (is it same as HiveOperation.ALTERTABLE_TOUCH?) + 13. HiveOperation.ALTERPARTITION_PROTECTMODE + 14. HiveOperation.ALTERTABLE_RENAMECOL + 15. HiveOperation.ALTERTABLE_ADDCOLS + 16. HiveOperation.ALTERTABLE_REPLACECOLS + 17. TODO: HiveOperation.ALTERVIEW_PROPERTIES + 18. TODO: HiveOperation.ALTERTABLE_SERIALIZER + 19. TODO: HiveOperation.ALTERPARTITION_SERIALIZER + */ + @Test + public void testAlterTable() throws Exception { + adminCreate(DB1, tableName, true); + + Connection connection; + Statement statement; + //Setup + connection = context.createConnection(ADMIN1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '10') "); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '1') "); + statement.execute("DROP TABLE IF EXISTS ptab"); + statement.execute("CREATE TABLE ptab (a int) STORED AS PARQUET"); + + policyFile + .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1")) + .addPermissionsToRole("alter_db1_ptab", privileges.get("alter_db1_ptab")) + .addRolesToGroup(USERGROUP1, "alter_db1_tb1", "alter_db1_ptab") + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP2, "insert_db1_tb1"); + writePolicyFile(policyFile); + + //Negative test cases + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 SET TBLPROPERTIES ('comment' = 'new_comment')"); + assertSemanticException(statement, "ALTER TABLE tb1 SET SERDEPROPERTIES ('field.delim' = ',')"); + assertSemanticException(statement, "ALTER TABLE tb1 CLUSTERED BY (a) SORTED BY (a) INTO 1 BUCKETS"); + assertSemanticException(statement, "ALTER TABLE tb1 TOUCH"); + // OFFLINE and NO_DROP were removed from tables and partitions after Hive 2.0.0 (HIVE-11145) + //assertSemanticException(statement, "ALTER TABLE tb1 ENABLE NO_DROP cascade"); + //assertSemanticException(statement, "ALTER TABLE tb1 DISABLE OFFLINE"); + assertSemanticException(statement, "ALTER TABLE tb1 SET FILEFORMAT RCFILE"); + + assertSemanticException(statement, "ALTER TABLE tb1 PARTITION (b = 10) RENAME TO PARTITION (b = 2)"); + assertSemanticException(statement, "ALTER TABLE tb1 PARTITION (b = 10) SET SERDEPROPERTIES ('field.delim' = ',')"); + //assertSemanticException(statement, "ALTER TABLE tb1 ARCHIVE PARTITION (b = 2)"); + //assertSemanticException(statement, "ALTER TABLE tb1 UNARCHIVE PARTITION (b = 2)"); + assertSemanticException(statement, "ALTER TABLE tb1 PARTITION (b = 10) SET FILEFORMAT RCFILE"); + assertSemanticException(statement, "ALTER TABLE tb1 TOUCH PARTITION (b = 10)"); + // OFFLINE and NO_DROP were removed from tables and partitions after Hive 2.0.0 (HIVE-11145) + // assertSemanticException(statement, "ALTER TABLE tb1 PARTITION (b = 10) DISABLE NO_DROP"); + // assertSemanticException(statement, "ALTER TABLE tb1 PARTITION (b = 10) DISABLE OFFLINE"); + + assertSemanticException(statement, "ALTER TABLE tb1 CHANGE COLUMN a c int"); + assertSemanticException(statement, "ALTER TABLE tb1 ADD COLUMNS (a int)"); + assertSemanticException(statement, "ALTER TABLE ptab REPLACE COLUMNS (a int, c int)"); + assertSemanticException(statement, "MSCK REPAIR TABLE tb1"); + + //assertSemanticException(statement, "ALTER VIEW view1 SET TBLPROPERTIES ('comment' = 'new_comment')"); + + + statement.close(); + connection.close(); + + //Positive cases + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 SET TBLPROPERTIES ('comment' = 'new_comment')"); + statement.execute("ALTER TABLE tb1 SET SERDEPROPERTIES ('field.delim' = ',')"); + statement.execute("ALTER TABLE tb1 CLUSTERED BY (a) SORTED BY (a) INTO 1 BUCKETS"); + statement.execute("ALTER TABLE tb1 TOUCH"); + // OFFLINE and NO_DROP were removed from tables and partitions after Hive 2.0.0 (HIVE-11145) + // statement.execute("ALTER TABLE tb1 ENABLE NO_DROP"); + // statement.execute("ALTER TABLE tb1 DISABLE OFFLINE"); + statement.execute("ALTER TABLE tb1 SET FILEFORMAT RCFILE"); + + statement.execute("ALTER TABLE tb1 PARTITION (b = 1) RENAME TO PARTITION (b = 2)"); + statement.execute("ALTER TABLE tb1 PARTITION (b = 2) SET SERDEPROPERTIES ('field.delim' = ',')"); + //statement.execute("ALTER TABLE tb1 ARCHIVE PARTITION (b = 2)"); + //statement.execute("ALTER TABLE tb1 UNARCHIVE PARTITION (b = 2)"); + statement.execute("ALTER TABLE tb1 PARTITION (b = 2) SET FILEFORMAT RCFILE"); + statement.execute("ALTER TABLE tb1 TOUCH PARTITION (b = 2)"); + // OFFLINE and NO_DROP were removed from tables and partitions after Hive 2.0.0 (HIVE-11145) + //statement.execute("ALTER TABLE tb1 PARTITION (b = 2) DISABLE NO_DROP"); + //statement.execute("ALTER TABLE tb1 PARTITION (b = 2) DISABLE OFFLINE"); + + statement.execute("set hive.metastore.disallow.incompatible.col.type.changes=false"); + statement.execute("ALTER TABLE tb1 CHANGE COLUMN a c int"); + statement.execute("ALTER TABLE tb1 ADD COLUMNS (a int)"); + statement.execute("ALTER TABLE ptab REPLACE COLUMNS (a int, c int)"); + statement.execute("MSCK REPAIR TABLE tb1"); + + //statement.execute("ALTER VIEW view1 SET TBLPROPERTIES ('comment' = 'new_comment')"); + + statement.close(); + connection.close(); + } + + /* Test all operations that require index on table alone + 1. Create index : HiveOperation.CREATEINDEX + 2. Drop index : HiveOperation.DROPINDEX + 3. HiveOperation.ALTERINDEX_REBUILD + 4. TODO: HiveOperation.ALTERINDEX_PROPS + */ + @Test + public void testIndexTable() throws Exception { + adminCreate(DB1, tableName, true); + policyFile + .addPermissionsToRole("index_db1_tb1", privileges.get("index_db1_tb1")) + .addRolesToGroup(USERGROUP1, "index_db1_tb1") + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP2, "insert_db1_tb1"); + writePolicyFile(policyFile); + + Connection connection; + Statement statement; + + //Positive cases + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("CREATE INDEX table01_index ON TABLE tb1 (a) AS 'COMPACT' WITH DEFERRED REBUILD"); + statement.execute("ALTER INDEX table01_index ON tb1 REBUILD"); + statement.close(); + connection.close(); + + //Negative case + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "CREATE INDEX table02_index ON TABLE tb1 (a) AS 'COMPACT' WITH DEFERRED REBUILD"); + assertSemanticException(statement, "ALTER INDEX table01_index ON tb1 REBUILD"); + assertSemanticException(statement, "DROP INDEX table01_index ON tb1"); + statement.close(); + connection.close(); + + //Positive cases + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("DROP INDEX table01_index ON tb1"); + statement.close(); + connection.close(); + } + + /* Test all operations that require drop on table alone + 1. Create index : HiveOperation.DROPTABLE + */ + @Test + public void testDropTable() throws Exception { + adminCreate(DB1, tableName, true); + policyFile + .addPermissionsToRole("drop_db1_tb1", privileges.get("drop_db1_tb1")) + .addRolesToGroup(USERGROUP1, "drop_db1_tb1") + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP2, "insert_db1_tb1"); + writePolicyFile(policyFile); + + Connection connection; + Statement statement; + + //Negative case + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "drop table " + tableName); + + statement.close(); + connection.close(); + + //Positive cases + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("drop table " + tableName); + + statement.close(); + connection.close(); + } + + @Ignore + @Test + public void testLockTable() throws Exception { + //TODO + } + + /* Operations that require alter + drop on table + 1. HiveOperation.ALTERTABLE_DROPPARTS + */ + @Test + public void dropPartition() throws Exception { + adminCreate(DB1, tableName, true); + policyFile + .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1")) + .addPermissionsToRole("drop_db1_tb1", privileges.get("drop_db1_tb1")) + .addRolesToGroup(USERGROUP1, "alter_db1_tb1", "drop_db1_tb1") + .addRolesToGroup(USERGROUP2, "alter_db1_tb1"); + + writePolicyFile(policyFile); + + Connection connection; + Statement statement; + //Setup + connection = context.createConnection(ADMIN1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '10') "); + + //Negative case + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 DROP PARTITION (b = 10)"); + + //Positive case + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 DROP PARTITION (b = 10)"); + statement.close(); + connection.close(); + } + + /* + 1. HiveOperation.ALTERTABLE_RENAME + */ + @Test + public void renameTable() throws Exception { + adminCreate(DB1, tableName); + policyFile + .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1")) + .addPermissionsToRole("create_db1", privileges.get("create_db1")) + .addRolesToGroup(USERGROUP1, "alter_db1_tb1", "create_db1") + .addRolesToGroup(USERGROUP2, "create_db1") + .addRolesToGroup(USERGROUP3, "alter_db1_tb1"); + + writePolicyFile(policyFile); + + Connection connection; + Statement statement; + + //Negative cases + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 RENAME TO tb2"); + statement.close(); + connection.close(); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 RENAME TO tb2"); + statement.close(); + connection.close(); + + //Positive case + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 RENAME TO tb2"); + statement.close(); + connection.close(); + } + + /* Test all operations which require alter on table (+ all on URI) + 1. HiveOperation.ALTERTABLE_LOCATION + 2. HiveOperation.ALTERTABLE_ADDPARTS + 3. TODO: HiveOperation.ALTERPARTITION_LOCATION + 4. TODO: HiveOperation.ALTERTBLPART_SKEWED_LOCATION + */ + @Test + public void testAlterOnTableAndURI() throws Exception { + adminCreate(DB1, tableName, true); + String tabLocation = dfs.getBaseDir() + "/" + Math.random(); + policyFile + .addPermissionsToRole("alter_db1_tb1", privileges.get("alter_db1_tb1")) + .addPermissionsToRole("all_uri", "server=server1->uri=" + tabLocation) + .addRolesToGroup(USERGROUP1, "alter_db1_tb1", "all_uri") + .addRolesToGroup(USERGROUP2, "alter_db1_tb1"); + + writePolicyFile(policyFile); + + //Case with out uri + Connection connection = context.createConnection(USER2_1); + Statement statement = context.createStatement(connection); + statement.execute("USE " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 SET LOCATION '" + tabLocation + "'"); + assertSemanticException(statement, "ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '3') LOCATION '" + tabLocation + "/part'"); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '1') "); + + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("ALTER TABLE tb1 SET LOCATION '" + tabLocation + "'"); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '3') LOCATION '" + tabLocation + "/part'"); + statement.execute("ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '10') "); + statement.close(); + connection.close(); + + //Negative case: User2_1 has privileges on table but on on uri + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + context.assertSentrySemanticException(statement, "ALTER TABLE tb1 SET LOCATION '" + tabLocation + "'", + semanticException); + context.assertSentrySemanticException(statement, + "ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '3') LOCATION '" + tabLocation + "/part'", + semanticException); + statement.close(); + connection.close(); + + //Negative case: User3_1 has only insert privileges on table + policyFile + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP3, "insert_db1_tb1", "all_uri"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + assertSemanticException(statement, "ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '2') "); + assertSemanticException(statement, "ALTER TABLE tb1 SET LOCATION '" + tabLocation + "'"); + + assertSemanticException(statement, "ALTER TABLE tb1 ADD IF NOT EXISTS PARTITION (b = '3') LOCATION '" + + tabLocation + "/part'"); + statement.close(); + connection.close(); + + + } + + /* Create on Database and select on table + 1. Create view : HiveOperation.CREATEVIEW + */ + @Test + public void testCreateView() throws Exception { + adminCreate(DB1, tableName); + adminCreate(DB2, null); + policyFile + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addPermissionsToRole("create_db2", privileges.get("create_db2")) + .addRolesToGroup(USERGROUP1, "select_db1_tb1", "create_db2"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("use " + DB2); + statement.execute("create view view1 as select a from " + DB1 + ".tb1"); + statement.close(); + connection.close(); + + //Negative case + policyFile + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addRolesToGroup(USERGROUP3, "insert_db1_tb1", "create_db2"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB2); + context.assertSentrySemanticException(statement, "create view view1 as select a from " + DB1 + ".tb1", + semanticException); + statement.close(); + connection.close(); + + + } + + /* + 1. HiveOperation.IMPORT : Create on db + all on URI + 2. HiveOperation.EXPORT : SELECT on table + all on uri + */ + + @Test + public void testExportImport() throws Exception { + File dataFile; + 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(); + + dropDb(ADMIN1, DB1); + createDb(ADMIN1, DB1); + createTable(ADMIN1, DB1, dataFile, tableName); + String location = dfs.getBaseDir() + "/" + Math.random(); + policyFile + .addPermissionsToRole("create_db1", privileges.get("create_db1")) + .addPermissionsToRole("all_uri", "server=server1->uri="+ location) + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addPermissionsToRole("insert_db1", privileges.get("insert_db1")) + .addRolesToGroup(USERGROUP1, "select_db1_tb1", "all_uri") + .addRolesToGroup(USERGROUP2, "create_db1", "all_uri") + .addRolesToGroup(USERGROUP3, "insert_db1", "all_uri"); + writePolicyFile(policyFile); + Connection connection; + Statement statement; + + //Negative case + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + context.assertSentrySemanticException(statement, "export table tb1 to '" + location + "'", + semanticException); + statement.close(); + connection.close(); + + //Positive + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("export table tb1 to '" + location + "'" ); + statement.close(); + connection.close(); + + //Negative + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + context.assertSentrySemanticException(statement, "import table tb2 from '" + location + "'", + semanticException); + statement.close(); + connection.close(); + + //Positive + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("import table tb2 from '" + location + "'"); + statement.close(); + connection.close(); + + } + + /* + 1. HiveOperation.LOAD: INSERT on table + all on uri + */ + @Test + public void testLoad() throws Exception { + File dataFile; + 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(); + + adminCreate(DB1, tableName); + + policyFile + .addPermissionsToRole("insert_db1_tb1", privileges.get("insert_db1_tb1")) + .addPermissionsToRole("all_uri", "server=server1->uri=file://" + dataDir) + .addRolesToGroup(USERGROUP1, "insert_db1_tb1", "all_uri"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("load data local inpath '" + dataFile.getPath() + "' into table tb1" ); + statement.close(); + connection.close(); + } + + /* + 1. HiveOperation.CREATETABLE_AS_SELECT : Create on db + select on table + */ + @Test + public void testCTAS() throws Exception { + adminCreate(DB1, tableName); + adminCreate(DB2, null); + + String location = dfs.getBaseDir() + "/" + Math.random(); + + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("Use " + DB1); + statement.execute("create view view1 as select a from " + DB1 + ".tb1"); + statement.close(); + connection.close(); + + policyFile + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addPermissionsToRole("select_db1_view1", privileges.get("select_db1_view1")) + .addPermissionsToRole("create_db2", privileges.get("create_db2")) + .addPermissionsToRole("all_uri", "server=server1->uri=" + location) + .addRolesToGroup(USERGROUP1, "select_db1_tb1", "create_db2") + .addRolesToGroup(USERGROUP2, "select_db1_view1", "create_db2") + .addRolesToGroup(USERGROUP3, "select_db1_tb1", "create_db2,all_uri"); + writePolicyFile(policyFile); + + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB2); + statement.execute("create table tb2 as select a from " + DB1 + ".tb1"); + //Ensure CTAS fails without URI + context.assertSentrySemanticException(statement, "create table tb3 location '" + location + + "' as select a from " + DB1 + ".tb1", + semanticException); + context.assertSentrySemanticException(statement, "create table tb3 as select a from " + DB1 + ".view1", + semanticException); + + + statement.close(); + connection.close(); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("Use " + DB2); + statement.execute("create table tb3 as select a from " + DB1 + ".view1" ); + context.assertSentrySemanticException(statement, "create table tb4 as select a from " + DB1 + ".tb1", + semanticException); + + statement.close(); + connection.close(); + + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + //CTAS is valid with URI + statement.execute("Use " + DB2); + statement.execute("create table tb4 location '" + location + + "' as select a from " + DB1 + ".tb1"); + + statement.close(); + connection.close(); + + } + + + /* + 1. INSERT : IP: select on table, OP: insert on table + all on uri(optional) + */ + @Test + public void testInsert() throws Exception { + File dataFile; + 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(); + + dropDb(ADMIN1, DB1); + dropDb(ADMIN1, DB2); + createDb(ADMIN1, DB1); + createDb(ADMIN1, DB2); + createTable(ADMIN1, DB1, dataFile, tableName); + createTable(ADMIN1, DB2, null, "tb2"); + String location = dfs.getBaseDir() + "/" + Math.random(); + + policyFile + .addPermissionsToRole("select_db1_tb1", privileges.get("select_db1_tb1")) + .addPermissionsToRole("insert_db2_tb2", privileges.get("insert_db2_tb2")) + .addRolesToGroup(USERGROUP1, "select_db1_tb1", "insert_db2_tb2") + .addPermissionsToRole("all_uri", "server=server1->uri=" + location) + .addRolesToGroup(USERGROUP2, "select_db1_tb1", "all_uri"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + assertSemanticException(statement, "insert overwrite directory '" + location + "' select * from " + DB1 + ".tb1"); + statement.execute("insert overwrite table " + DB2 + ".tb2 select * from " + DB1 + ".tb1"); + statement.close(); + connection.close(); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("insert overwrite directory '" + location + "' select * from " + DB1 + ".tb1" ); + assertSemanticException(statement, "insert overwrite table " + DB2 + ".tb2 select * from " + DB1 + ".tb1"); + statement.close(); + connection.close(); + } + + @Test + public void testFullyQualifiedTableName() throws Exception{ + Connection connection; + Statement statement; + connection = context.createConnection(ADMIN1); + statement = context.createStatement(connection); + statement.execute("create database " + DB1); + statement.execute("create table " + DB1 + ".tb1(a int)"); + statement.execute("DROP table " + DB1 + ".tb1"); + statement.execute("create table " + DB1 + ".tb1(a int)"); + statement.execute("use " + DB1); + statement.execute("drop table tb1"); + } + + @Test + public void testExternalTables() throws Exception{ + createDb(ADMIN1, DB1); + File externalTblDir = new File(dataDir, "exttab"); + assertTrue("Unable to create directory for external table test" , externalTblDir.mkdir()); + + policyFile + .addPermissionsToRole("create_db1", privileges.get("create_db1")) + .addPermissionsToRole("all_uri", "server=server1->uri=file://" + dataDir.getPath()) + .addRolesToGroup(USERGROUP1, "create_db1", "all_uri") + .addRolesToGroup(USERGROUP2, "create_db1"); + writePolicyFile(policyFile); + + Connection connection = context.createConnection(USER2_1); + Statement statement = context.createStatement(connection); + assertSemanticException(statement, "create external table " + DB1 + ".tb1(a int) stored as " + + "textfile location 'file:" + externalTblDir.getAbsolutePath() + "'"); + //Create external table on HDFS + assertSemanticException(statement, "create external table " + DB1 + ".tb2(a int) location '/user/hive/warehouse/blah'"); + statement.close(); + connection.close(); + + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("create external table " + DB1 + ".tb1(a int) stored as " + + "textfile location 'file:" + externalTblDir.getAbsolutePath() + "'"); + statement.close(); + connection.close(); + + + } + + @Test + public void testCaseSensitivity() throws Exception { + Statement statement = null; + Connection connection = null; + try { + createDb(ADMIN1, DB1); + String scratchLikeDir = context.getProperty(HiveConf.ConfVars.SCRATCHDIR.varname); + String extParentDir = dfs.assertCreateDir(scratchLikeDir + "/ABC/hhh").toUri().toString(); + String extTableDir = dfs.assertCreateDir(scratchLikeDir + "/abc/hhh").toUri().toString(); + LOGGER.info("Created extParentDir = " + extParentDir + ", extTableDir = " + extTableDir); + policyFile + .addPermissionsToRole("all_db1", privileges.get("all_db1")) + .addPermissionsToRole("all_uri", "server=server1->uri=" + extParentDir) + .addRolesToGroup(USERGROUP1, "all_db1", "all_uri"); + writePolicyFile(policyFile); + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + assertSemanticException(statement, + "create external table " + DB1 + ".tb1(a int) location '" + extTableDir + "'"); + } finally { + if (statement != null) { + statement.close(); + } + if (connection != null) { + connection.close(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDBConfiguration.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDBConfiguration.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDBConfiguration.java new file mode 100644 index 0000000..985f969 --- /dev/null +++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDBConfiguration.java @@ -0,0 +1,408 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.tests.e2e.hive; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.apache.sentry.policy.db.SimpleDBPolicyEngine; +import org.apache.sentry.provider.file.PolicyFile; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.io.Resources; + +/** + * Test privileges per database policy files + */ +public class TestPerDBConfiguration extends AbstractTestWithStaticConfiguration { + + private static final String MULTI_TYPE_DATA_FILE_NAME = "emp.dat"; + private static final String DB2_POLICY_FILE = "db2-policy-file.ini"; + + private static File dataFile; + private PolicyFile policyFile; + private static String prefix; + + @BeforeClass + public static void setupTestStaticConfiguration() throws Exception { + AbstractTestWithStaticConfiguration.setupTestStaticConfiguration(); + } + + @Before + public void setup() throws Exception { + String hiveServer2 = System.getProperty("sentry.e2etest.hiveServer2Type", "InternalHiveServer2"); + String policyOnHDFS = System.getProperty("sentry.e2etest.hive.policyOnHDFS", "true"); + if(policyOnHDFS.trim().equalsIgnoreCase("true") && (hiveServer2.equals("UnmanagedHiveServer2") )){ + String policyLocation = System.getProperty("sentry.e2etest.hive.policy.location", "/user/hive/sentry"); + prefix = "hdfs://" + policyLocation + "/"; + }else { + prefix = "file://" + context.getPolicyFile().getParent() + "/"; + } + + policyFile = super.setupPolicy(); + super.setup(); + prepareDBDataForTest(); + } + + protected static void prepareDBDataForTest() throws Exception { + // copy data file to test dir + dataDir = context.getDataDir(); + dataFile = new File(dataDir, MULTI_TYPE_DATA_FILE_NAME); + FileOutputStream to = new FileOutputStream(dataFile); + Resources.copy(Resources.getResource(MULTI_TYPE_DATA_FILE_NAME), to); + to.close(); + + // setup db objects needed by the test + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + + statement.execute("DROP DATABASE IF EXISTS " + DB1 + " 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.execute("CREATE TABLE tbl5(B INT, A STRING) " + + " row format delimited fields terminated by '|' stored as textfile"); + + statement.execute("DROP DATABASE IF EXISTS db3 CASCADE"); + statement.execute("CREATE DATABASE db3"); + statement.execute("USE db3"); + statement.execute("CREATE TABLE tbl3(B INT, A STRING) " + + " row format delimited fields terminated by '|' stored as textfile"); + statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE tbl3"); + + statement.execute("DROP DATABASE IF EXISTS db4 CASCADE"); + statement.execute("CREATE DATABASE db4"); + statement.execute("USE db4"); + statement.execute("CREATE TABLE tbl4(B INT, A STRING) " + + " row format delimited fields terminated by '|' stored as textfile"); + statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE tbl4"); + statement.close(); + connection.close(); + } + + @After + public void teardown() throws Exception { + // one test turns this on so let's disable it in the teardown method + System.setProperty(SimpleDBPolicyEngine.ACCESS_ALLOW_URI_PER_DB_POLICYFILE, "false"); + } + + @Test + public void testPerDB() throws Exception { + PolicyFile db2PolicyFile = new PolicyFile(); + File db2PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB2_POLICY_FILE); + db2PolicyFile + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl2", "server=server1->db=" + DB2 + "->table=tbl2->action=select") + .write(db2PolicyFileHandle); + + policyFile + .addRolesToGroup(USERGROUP1, "select_tbl1") + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl1", "server=server1->db=" + DB1 +"->table=tbl1->action=select") + .addDatabase(DB2, prefix + db2PolicyFileHandle.getName()) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + // test execution + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("USE " + DB1); + // test user1 can execute query on tbl1 + verifyCount(statement, "SELECT COUNT(*) FROM tbl1", 1, 12); + + // user1 cannot query db2.tbl2 + context.assertAuthzException(statement, "USE " + DB2); + context.assertAuthzException(statement, "SELECT COUNT(*) FROM " + DB2 + ".tbl2"); + statement.close(); + connection.close(); + + // test per-db file for db2 + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + // test user2 can execute query on tbl2 + verifyCount(statement, "SELECT COUNT(*) FROM tbl2", 1, 12); + + // user2 cannot query db1.tbl1 + context.assertAuthzException(statement, "SELECT COUNT(*) FROM " + DB1 + ".tbl1"); + context.assertAuthzException(statement, "USE " + DB1); + + statement.close(); + connection.close(); + + } + + /** + * Multiple DB files with some containing badly formatted rules + * The privileges should work for good files + * No access for bad formatted ones + * @throws Exception + */ + @Test + public void testMultiPerDBwithErrors() throws Exception { + String DB3_POLICY_FILE = "db3-policy-file.ini"; + String DB4_POLICY_FILE = "db4-policy-file.ini"; + + File db2PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB2_POLICY_FILE); + File db3PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB3_POLICY_FILE); + File db4PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB4_POLICY_FILE); + + PolicyFile db2PolicyFile = new PolicyFile(); + PolicyFile db3PolicyFile = new PolicyFile(); + PolicyFile db4PolicyFile = new PolicyFile(); + db2PolicyFile + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl2", "server=server1->db=" + DB2 + "->table=tbl2->action=select") + .write(db2PolicyFileHandle); + db3PolicyFile + .addRolesToGroup(USERGROUP3, "select_tbl3_BAD") + .addPermissionsToRole("select_tbl3_BAD", "server=server1->db=db3------>table->action=select") + .write(db3PolicyFileHandle); + db4PolicyFile + .addRolesToGroup(USERGROUP4, "select_tbl4") + .addPermissionsToRole("select_tbl4", "server=server1->db=db4->table=tbl4->action=select") + .write(db4PolicyFileHandle); + policyFile + .addRolesToGroup(USERGROUP1, "select_tbl1") + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl1", "server=server1->db=" + DB1 +"->table=tbl1->action=select") + .addDatabase(DB2, prefix + db2PolicyFileHandle.getName()) + .addDatabase("db3", prefix + db3PolicyFileHandle.getName()) + .addDatabase("db4", prefix + db4PolicyFileHandle.getName()) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + // test execution + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("USE " + DB1); + // test user1 can execute query on tbl1 + verifyCount(statement, "SELECT COUNT(*) FROM tbl1", 1, 12); + connection.close(); + + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + // test user1 can execute query on tbl1 + verifyCount(statement, "SELECT COUNT(*) FROM tbl2", 1, 12); + connection.close(); + + // verify no access to db3 due to badly formatted rule in db3 policy file + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertAuthzException(statement, "USE db3"); + // test user1 can execute query on tbl1 + context.assertAuthzException(statement, "SELECT COUNT(*) FROM db3.tbl3"); + connection.close(); + + connection = context.createConnection(USER4_1); + statement = context.createStatement(connection); + statement.execute("USE db4"); + // test user1 can execute query on tbl1 + verifyCount(statement, "SELECT COUNT(*) FROM tbl4", 1, 12); + connection.close(); + } + + @Test + public void testPerDBPolicyFileWithURI() throws Exception { + File db2PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB2_POLICY_FILE); + PolicyFile db2PolicyFile = new PolicyFile(); + db2PolicyFile + .addRolesToGroup(USERGROUP2, "select_tbl5", "data_read", "insert_tbl5") + .addPermissionsToRole("select_tbl5", + "server=server1->db=" + DB2 + "->table=tbl5->action=select") + .addPermissionsToRole("insert_tbl5", + "server=server1->db=" + DB2 + "->table=tbl5->action=insert") + .addPermissionsToRole("data_read", "server=server1->URI=file://" + dataFile) + .write(db2PolicyFileHandle); + + policyFile + .addRolesToGroup(USERGROUP1, "select_tbl1") + .addRolesToGroup(USERGROUP2, "select_tbl5") + .addPermissionsToRole("select_tbl1", "server=server1->db=" + DB1 +"->table=tbl1->action=select") + .addDatabase(DB2, prefix + db2PolicyFileHandle.getName()) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + // ugly hack: needs to go away once this becomes a config property. Note that this property + // will not be set with external HS and this test will fail. Hope is this fix will go away + // by then. + System.setProperty(SimpleDBPolicyEngine.ACCESS_ALLOW_URI_PER_DB_POLICYFILE, "true"); + // test execution + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("USE " + DB1); + // test user1 can execute query on tbl1 + verifyCount(statement, "SELECT COUNT(*) FROM tbl1", 1, 12); + + // user1 cannot query db2.tbl5 + context.assertAuthzException(statement, "USE " + DB2); + context.assertAuthzException(statement, "SELECT COUNT(*) FROM " + DB2 + ".tbl5"); + statement.close(); + connection.close(); + + // test per-db file for db2 + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + // test user2 can execute query on tbl5 + verifyCount(statement, "SELECT COUNT(*) FROM tbl5", 1, 0); + + // verify user2 can execute LOAD + statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE tbl5"); + + // user2 cannot query db1.tbl1 + context.assertAuthzException(statement, "SELECT COUNT(*) FROM " + DB1 + ".tbl1"); + context.assertAuthzException(statement, "USE " + DB1); + + // once we disable this property all queries should fail + System.setProperty(SimpleDBPolicyEngine.ACCESS_ALLOW_URI_PER_DB_POLICYFILE, "false"); + context.assertAuthzException(statement, "USE " + DB2); + + // re-enable for clean + System.setProperty(SimpleDBPolicyEngine.ACCESS_ALLOW_URI_PER_DB_POLICYFILE, "true"); + + statement.close(); + connection.close(); + } + + /** + * Test 'use default' statement. It should work as long as the user as privilege to assess any object in system + * @throws Exception + */ + @Test + public void testDefaultDb() throws Exception { + policyFile + .addRolesToGroup(USERGROUP1, "select_tbl1") + .addPermissionsToRole("select_tbl1", "server=server1->db=" + DB1 +"->table=tbl1->action=select") + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + // user_1 should be able to access default + Connection connection = context.createConnection(USER1_1); + Statement statement = context.createStatement(connection); + statement.execute("USE default"); + statement.close(); + connection.close(); + + // user_2 should NOT be able to access default since it does have access to any other object + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + context.assertAuthzException(statement, "USE default"); + statement.close(); + connection.close(); + + } + + @Test + public void testDefaultDBwithDbPolicy() throws Exception { + File db2PolicyFileHandle = new File(context.getPolicyFile().getParent(), DB2_POLICY_FILE); + File defaultPolicyFileHandle = new File(context.getPolicyFile().getParent(), "default.ini"); + + policyFile + .addRolesToGroup(USERGROUP1, "select_tbl1") + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl1", "server=server1->db=" + DB1 +"->table=tbl1->action=select") + .addDatabase(DB2, prefix + db2PolicyFileHandle.getName()) + .addDatabase("default", prefix + defaultPolicyFileHandle.getName()) + .setUserGroupMapping(StaticUserGroup.getStaticMapping()) + .write(context.getPolicyFile()); + + PolicyFile db2PolicyFile = new PolicyFile(); + db2PolicyFile + .addRolesToGroup(USERGROUP2, "select_tbl2") + .addPermissionsToRole("select_tbl2", "server=server1->db=" + DB2 + "->table=tbl2->action=select") + .write(db2PolicyFileHandle); + + PolicyFile defaultPolicyFile = new PolicyFile(); + defaultPolicyFile + .addRolesToGroup(USERGROUP2, "select_def") + .addPermissionsToRole("select_def", "server=server1->db=default->table=dtab->action=select") + .write(defaultPolicyFileHandle); + + // setup db objects needed by the test + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + statement.execute("USE default"); + statement.execute("DROP TABLE IF EXISTS dtab"); + statement.execute("CREATE TABLE dtab(B INT, A STRING) " + + " row format delimited fields terminated by '|' stored as textfile"); + // user_1 should be able to switch to default, but not the tables from default + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB1); + statement.execute("USE default"); + context.assertAuthzException(statement, "SELECT * FROM dtab"); + statement.execute("USE " + DB1); + context.assertAuthzException(statement, "SELECT * FROM default.dtab"); + + statement.close(); + connection.close(); + + // user_2 should be able to access default and select from default's tables + connection = context.createConnection(USER2_1); + statement = context.createStatement(connection); + statement.execute("USE " + DB2); + statement.execute("USE default"); + statement.execute("SELECT * FROM dtab"); + statement.execute("USE " + DB2); + statement.execute("SELECT * FROM default.dtab"); + statement.close(); + connection.close(); + + // user_3 should NOT be able to switch to default since it doesn't have access to any objects + connection = context.createConnection(USER3_1); + statement = context.createStatement(connection); + context.assertAuthzException(statement, "USE default"); + statement.close(); + connection.close(); + } + + private void verifyCount(Statement statement, String query, int exceptedCountRows, + int exceptedCount) throws SQLException { + ResultSet resultSet = statement.executeQuery(query); + int count = 0; + int countRows = 0; + + while (resultSet.next()) { + count = resultSet.getInt(1); + countRows++; + } + assertTrue("Incorrect row count:" + countRows, countRows == exceptedCountRows); + assertTrue("Incorrect result:" + count, count == exceptedCount); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/bfb354f2/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDatabasePolicyFile.java ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDatabasePolicyFile.java b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDatabasePolicyFile.java new file mode 100644 index 0000000..c8712e7 --- /dev/null +++ b/sentry-tests/sentry-tests-hive-v2/src/test/java/org/apache/sentry/tests/e2e/hive/TestPerDatabasePolicyFile.java @@ -0,0 +1,118 @@ +/* + * 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.provider.file.PolicyFile; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.sql.Connection; +import java.sql.Statement; + +public class TestPerDatabasePolicyFile extends AbstractTestWithStaticConfiguration { + private static final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat"; + private PolicyFile policyFile; + private File dataDir; + private File dataFile; + + @Before + public void setup() throws Exception { + policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP); + writePolicyFile(policyFile); + dataDir = context.getDataDir(); + dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME); + FileOutputStream to = new FileOutputStream(dataFile); + Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to); + to.close(); + } + + private void createSampleDbTable(Statement statement, String db, String table) + throws Exception { + statement.execute("DROP DATABASE IF EXISTS " + db + " CASCADE"); + statement.execute("CREATE DATABASE " + db); + statement.execute("USE " + db); + statement.execute("CREATE TABLE " + table + "(a STRING)"); + statement.execute("LOAD DATA LOCAL INPATH '" + dataFile.getPath() + "' INTO TABLE " + table); + + } + + /** + * Ensure that db specific file cannot grant to other db + */ + @Test + public void testDbSpecificFileGrantsToOtherDb() throws Exception { + doTestDbSpecificFileGrants("server=server1->db=" + DB1); + } + /** + * Ensure that db specific file cannot grant to all db + */ + @Test + public void testDbSpecificFileGrantsToAllDb() throws Exception { + doTestDbSpecificFileGrants("server=server1"); + } + /** + * Ensure that db specific file cannot grant to all servers + */ + @Test + public void testDbSpecificFileGrantsToAllServers() throws Exception { + doTestDbSpecificFileGrants("server=*"); + } + /** + * Ensure that db specific file cannot grant to all + */ + @Test + public void testDbSpecificFileGrantsToAll() throws Exception { + doTestDbSpecificFileGrants("*"); + } + + public void doTestDbSpecificFileGrants(String grant) throws Exception { + + policyFile + .setUserGroupMapping(StaticUserGroup.getStaticMapping()); + writePolicyFile(policyFile); + + + // setup db objects needed by the test + Connection connection = context.createConnection(ADMIN1); + Statement statement = context.createStatement(connection); + createSampleDbTable(statement, DB1, "tbl1"); + createSampleDbTable(statement, DB2, "tbl1"); + statement.close(); + connection.close(); + + File specificPolicyFileFile = new File(baseDir, "db2-policy.ini"); + + PolicyFile specificPolicyFile = new PolicyFile() + .addPermissionsToRole("db1_role", grant) + .addRolesToGroup("group1", "db1_role"); + specificPolicyFile.write(specificPolicyFileFile); + + policyFile.addDatabase(DB2, specificPolicyFileFile.getPath()); + writePolicyFile(policyFile); + + // test execution + connection = context.createConnection(USER1_1); + statement = context.createStatement(connection); + // test user can query table + context.assertAuthzException(statement, "USE " + DB1); + context.assertAuthzException(statement, "SELECT COUNT(a) FROM " + DB1 + ".tbl1"); + } +} \ No newline at end of file
