| /* |
| * 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.access.tests.e2e; |
| |
| 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.access.provider.file.PolicyFile; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import com.google.common.io.Resources; |
| |
| public class TestMetadataObjectRetrieval extends |
| AbstractTestWithStaticLocalFS { |
| private PolicyFile policyFile; |
| private File dataFile; |
| |
| @Before |
| public void setup() throws Exception { |
| policyFile = PolicyFile.createAdminOnServer1(ADMIN1); |
| 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(); |
| } |
| } |
| |
| /** |
| * Method called to run positive tests: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * The table is assumed to have two colums under_col int and value string. |
| */ |
| private void positiveDescribeShowTests(String user, String db, String table) throws Exception { |
| Connection connection = context.createConnection(user, "password"); |
| Statement statement = context.createStatement(connection); |
| statement.execute("USE " + db); |
| ResultSet rs = statement.executeQuery("DESCRIBE " + table); |
| assertTrue(rs.next()); |
| assertTrue("describe table fail", rs.getString(1).trim().equals("under_col")); |
| assertTrue("describe table fail", rs.getString(2).trim().equals("int")); |
| assertTrue(rs.next()); |
| assertTrue("describe table fail", rs.getString(1).trim().equals("value")); |
| assertTrue("describe table fail", rs.getString(2).trim().equals("string")); |
| |
| rs = statement.executeQuery("DESCRIBE " + table + " under_col"); |
| assertTrue(rs.next()); |
| assertTrue("describe table fail", rs.getString(1).trim().equals("under_col")); |
| assertTrue("describe table fail", rs.getString(2).trim().equals("int")); |
| |
| rs = statement.executeQuery("DESCRIBE " + table + " value"); |
| assertTrue(rs.next()); |
| assertTrue("describe table fail", rs.getString(1).trim().equals("value")); |
| assertTrue("describe table fail", rs.getString(2).trim().equals("string")); |
| |
| rs = statement.executeQuery("SHOW COLUMNS FROM " + table); |
| assertTrue(rs.next()); |
| assertTrue("show columns from fail", rs.getString(1).trim().equals("under_col")); |
| assertTrue(rs.next()); |
| assertTrue("show columns from fail", rs.getString(1).trim().equals("value")); |
| |
| rs = statement.executeQuery("SHOW CREATE TABLE " + table); |
| assertTrue("SHOW CREATE TABLE fail", rs.next()); |
| |
| rs = statement.executeQuery("SHOW TBLPROPERTIES " + table); |
| assertTrue("SHOW TBLPROPERTIES fail", rs.next()); |
| |
| statement.close(); |
| connection.close(); |
| } |
| /** |
| * Method called to run negative tests: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * The table is assumed to have two columns under_col int and value string. |
| */ |
| private void negativeDescribeShowTests(String user, String db, String table) throws Exception { |
| Connection connection = context.createConnection(user, "password"); |
| Statement statement = context.createStatement(connection); |
| statement.execute("USE " + db); |
| context.assertAuthzException(statement, "DESCRIBE " + table); |
| context.assertAuthzException(statement, "DESCRIBE " + table + " under_col"); |
| context.assertAuthzException(statement, "DESCRIBE " + table + " value"); |
| context.assertAuthzException(statement, "SHOW COLUMNS FROM " + table); |
| context.assertAuthzException(statement, "SHOW CREATE TABLE " + table); |
| context.assertAuthzException(statement, "SHOW TBLPROPERTIES " + table); |
| statement.close(); |
| connection.close(); |
| } |
| |
| |
| /** |
| * Tests to ensure a user with all on server, |
| * insert|select on table can view metadata while |
| * a user with all on a different table cannot |
| * view the metadata. |
| |
| * Test both positive and negative of: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * Positive tests are run with: |
| * all@server |
| * select@table |
| * insert@table |
| * Negative tests are run three times: |
| * none |
| * insert@different table |
| */ |
| @Test |
| public void testAllOnServerSelectInsertNegativeNoneAllOnDifferentTable() |
| throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + TBL2) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1); |
| createDb(ADMIN1, DB1); |
| createTable(ADMIN1, DB1, dataFile, TBL1); |
| positiveDescribeShowTests(ADMIN1, DB1, TBL1); |
| negativeDescribeShowTests(USER1, DB1, TBL1); |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| positiveDescribeShowTests(USER1, DB1, TBL1); |
| policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1); |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| positiveDescribeShowTests(USER1, DB1, TBL1); |
| } |
| |
| /** |
| * Tests to ensure that a user is able to view metadata |
| * with all on db |
| * |
| * Test positive: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * Positive tests are run twice: |
| * all@server |
| * all@db |
| */ |
| @Test |
| public void testAllOnServerAndAllOnDb() throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1); |
| createDb(ADMIN1, DB1); |
| createTable(ADMIN1, DB1, dataFile, TBL1); |
| positiveDescribeShowTests(ADMIN1, DB1, TBL1); |
| positiveDescribeShowTests(USER1, DB1, TBL1); |
| } |
| |
| /** |
| * Test to ensure that all on view do not result in |
| * metadata privileges on the underlying table |
| * |
| * Test both positive and negative of: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * Positive tests are run with all@server |
| * Negative tests are run three times: |
| * none |
| * all@view |
| */ |
| @Test |
| public void testAllOnServerNegativeAllOnView() throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + VIEW1) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .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 VIEW IF EXISTS " + VIEW1); |
| statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10"); |
| positiveDescribeShowTests(ADMIN1, DB1, TBL1); |
| statement.close(); |
| connection.close(); |
| negativeDescribeShowTests(USER1, DB1, TBL1); |
| } |
| |
| /** |
| * Tests to ensure that a user is able to view metadata |
| * with all on table |
| * |
| * Test positive: |
| * describe table |
| * describe table column |
| * show columns from table |
| * show create table table |
| * show tblproperties table |
| * |
| * Positive tests are run twice: |
| * all@server |
| * all@table |
| */ |
| @Test |
| public void testAllOnServerAndAllOnTable() throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1 + "->table=" + TBL1) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1); |
| createDb(ADMIN1, DB1); |
| createTable(ADMIN1, DB1, dataFile, TBL1); |
| positiveDescribeShowTests(ADMIN1, DB1, TBL1); |
| positiveDescribeShowTests(USER1, DB1, TBL1); |
| } |
| |
| |
| /** |
| * Tests that admin and all@db can describe database |
| * and describe database extended. Also tests that a user |
| * with no privileges on a db cannot describe database. |
| */ |
| @Test |
| public void testDescribeDatabasesWithAllOnServerAndAllOnDb() |
| throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=" + DB1) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1, DB2); |
| createDb(ADMIN1, DB1, DB2); |
| createTable(ADMIN1, DB1, dataFile, TBL1); |
| |
| Connection connection = context.createConnection(ADMIN1, "password"); |
| Statement statement = context.createStatement(connection); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next()); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE EXTENDED " + DB1).next()); |
| statement.close(); |
| connection.close(); |
| |
| connection = context.createConnection(USER1, "password"); |
| statement = context.createStatement(connection); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next()); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE EXTENDED " + DB1).next()); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE EXTENDED " + DB2); |
| policyFile.addPermissionsToRole(GROUP1_ROLE, INSERT_DB2_TBL1) |
| .write(context.getPolicyFile()); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE EXTENDED " + DB2); |
| statement.close(); |
| connection.close(); |
| } |
| |
| /** |
| * Tests that a user without db level privileges cannot describe default |
| */ |
| @Test |
| public void testDescribeDefaultDatabase() throws Exception { |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, "server=server1->db=default->table=" + TBL1 + "->action=select", |
| "server=server1->db=" + DB1 + "->table=" + TBL1 + "->action=select") |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1, DB2); |
| createDb(ADMIN1, DB1, DB2); |
| Connection connection = context.createConnection(ADMIN1, "password"); |
| Statement statement = context.createStatement(connection); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE default").next()); |
| statement.execute("USE " + DB1); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE default").next()); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB1).next()); |
| assertTrue(statement.executeQuery("DESCRIBE DATABASE " + DB2).next()); |
| statement.close(); |
| connection.close(); |
| |
| connection = context.createConnection(USER1, "password"); |
| statement = context.createStatement(connection); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE default"); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB1); |
| statement.execute("USE " + DB1); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB1); |
| context.assertAuthzException(statement, "DESCRIBE DATABASE " + DB2); |
| statement.close(); |
| connection.close(); |
| } |
| |
| /** |
| * Tests that users without privileges cannot execute show indexes |
| * and that users with all on table can execute show indexes |
| */ |
| @Test |
| public void testShowIndexes1() throws Exception { |
| // grant privilege to non-existent table to allow use db1 |
| policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_NONTABLE) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .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 |
| + "(value) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH DEFERRED REBUILD"); |
| statement.execute("DROP VIEW IF EXISTS " + VIEW1); |
| statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10"); |
| statement.close(); |
| connection.close(); |
| connection = context.createConnection(USER1, "password"); |
| statement = context.createStatement(connection); |
| statement.execute("USE " + DB1); |
| context.assertAuthzException(statement, "SHOW INDEX ON " + TBL1); |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_VIEW1) |
| .write(context.getPolicyFile()); |
| context.assertAuthzException(statement, "SHOW INDEX ON " + TBL1); |
| policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_VIEW1) |
| .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| verifyIndex(statement, TBL1, INDEX1); |
| policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1) |
| .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| verifyIndex(statement, TBL1, INDEX1); |
| statement.close(); |
| connection.close(); |
| } |
| |
| private void verifyIndex(Statement statement, String table, String index) throws Exception { |
| ResultSet rs = statement.executeQuery("SHOW INDEX ON " + table); |
| assertTrue(rs.next()); |
| assertEquals(index, rs.getString(1).trim()); |
| assertEquals(table, rs.getString(2).trim()); |
| assertEquals("value", rs.getString(3).trim()); |
| assertEquals("db_1__tb_1_index_1__", rs.getString(4).trim()); |
| assertEquals("compact", rs.getString(5).trim()); |
| } |
| |
| /** |
| * Tests that users without privileges cannot execute show partitions |
| * and that users with select on table can execute show partitions |
| */ |
| @Test |
| public void testShowPartitions1() throws Exception { |
| // grant privilege to non-existent table to allow use db1 |
| policyFile.addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_NONTABLE) |
| .addRolesToGroup(GROUP1, GROUP1_ROLE) |
| .addGroupsToUser(USER1, GROUP1) |
| .write(context.getPolicyFile()); |
| dropDb(ADMIN1, DB1); |
| createDb(ADMIN1, DB1); |
| Connection connection = context.createConnection(ADMIN1, "password"); |
| Statement statement = context.createStatement(connection); |
| statement.execute("USE " + DB1); |
| statement.execute("DROP TABLE IF EXISTS " + TBL1); |
| statement.execute("create table " + TBL1 |
| + " (under_col int, value string) PARTITIONED BY (dt INT)"); |
| statement.execute("load data local inpath '" + dataFile.getPath() |
| + "' into table " + TBL1 + " PARTITION (dt=3)"); |
| statement.execute("DROP VIEW IF EXISTS " + VIEW1); |
| statement.execute("CREATE VIEW " + VIEW1 + " (value) AS SELECT value from " + TBL1 + " LIMIT 10"); |
| statement.close(); |
| connection.close(); |
| connection = context.createConnection(USER1, "password"); |
| statement = context.createStatement(connection); |
| statement.execute("USE " + DB1); |
| context.assertAuthzException(statement, "SHOW PARTITIONS " + TBL1); |
| policyFile |
| .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_VIEW1) |
| .write(context.getPolicyFile()); |
| context.assertAuthzException(statement, "SHOW PARTITIONS " + TBL1); |
| policyFile |
| .removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_VIEW1) |
| .addPermissionsToRole(GROUP1_ROLE, SELECT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| verifyParition(statement, TBL1); |
| policyFile.removePermissionsFromRole(GROUP1_ROLE, SELECT_DB1_TBL1) |
| .addPermissionsToRole(GROUP1_ROLE, INSERT_DB1_TBL1) |
| .write(context.getPolicyFile()); |
| verifyParition(statement, TBL1); |
| statement.close(); |
| connection.close(); |
| } |
| |
| private void verifyParition(Statement statement, String table) throws Exception { |
| ResultSet rs = statement.executeQuery("SHOW PARTITIONS " + TBL1); |
| assertTrue(rs.next()); |
| assertEquals("dt=3", rs.getString(1).trim()); |
| } |
| } |