This is an automated email from the ASF dual-hosted git repository. linaataustin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sentry.git
The following commit(s) were added to refs/heads/master by this push: new 33db3ca SENTRY-2500: CREATE on server does not provide HMS server side read authorization for get_all_tables(database_name) 33db3ca is described below commit 33db3ca694a58e9bd85f5f9303627172f8b277e2 Author: lina.li <lina...@cloudera.com> AuthorDate: Tue Feb 19 09:56:29 2019 -0600 SENTRY-2500: CREATE on server does not provide HMS server side read authorization for get_all_tables(database_name) --- .../hive/authz/MetastoreAuthzObjectFilter.java | 22 +- .../hive/authz/TestMetastoreAuthzObjectFilter.java | 44 ++-- .../metastore/TestSentryMetaStoreFilterHook.java | 42 ++- .../hive/AbstractTestWithStaticConfiguration.java | 9 + .../sentry/tests/e2e/hive/StaticUserGroup.java | 5 +- .../tests/e2e/hive/TestShowMetadataPrivileges.java | 2 +- ...stractMetastoreTestWithStaticConfiguration.java | 12 + .../tests/e2e/metastore/TestMetastoreEndToEnd.java | 281 +++++++++++++++++++++ 8 files changed, 368 insertions(+), 49 deletions(-) diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/MetastoreAuthzObjectFilter.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/MetastoreAuthzObjectFilter.java index 178780e..e64d1a5 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/MetastoreAuthzObjectFilter.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/authz/MetastoreAuthzObjectFilter.java @@ -55,7 +55,7 @@ public class MetastoreAuthzObjectFilter<T> { } - private final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + private static final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() .addInputObjectPriviledge( AuthorizableType.Column, EnumSet.of( @@ -67,12 +67,12 @@ public class MetastoreAuthzObjectFilter<T> { .setOperationType(HiveOperationType.QUERY) .build(); - private final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + private static final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() .addInputObjectPriviledge( AuthorizableType.Column, EnumSet.of( DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, - DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) .setOperationScope(HiveOperationScope.TABLE) .setOperationType( HiveAuthzPrivileges.HiveOperationType.INFO) @@ -92,6 +92,22 @@ public class MetastoreAuthzObjectFilter<T> { } /** + * Return the required privileges for listing databases on a server + * @return the required privileges for authorizing listing databases on a server + */ + public static HiveAuthzPrivileges getListDatabasesPrivileges() { + return LIST_DATABASES_PRIVILEGES; + } + + /** + * Return the required privileges for listing tables in a database + * @return the required privileges for authorizing listing tables in a database + */ + public static HiveAuthzPrivileges getListTablePrivileges() { + return LIST_TABLES_PRIVILEGES; + } + + /** * Filter a list of {@code dbNames} objects based on the authorization privileges of {@code subject}. * * @param username The username to request authorization from. diff --git a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/authz/TestMetastoreAuthzObjectFilter.java b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/authz/TestMetastoreAuthzObjectFilter.java index 3ca89be..2fff9c4 100644 --- a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/authz/TestMetastoreAuthzObjectFilter.java +++ b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/authz/TestMetastoreAuthzObjectFilter.java @@ -78,28 +78,28 @@ public class TestMetastoreAuthzObjectFilter { } }; - private final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() - .addInputObjectPriviledge( - AuthorizableType.Column, - EnumSet.of( - DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, - DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, - DBModelAction.LOCK)) - .addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.SELECT)) - .setOperationScope(HiveOperationScope.CONNECT) - .setOperationType(HiveOperationType.QUERY) - .build(); - - private final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() - .addInputObjectPriviledge( - AuthorizableType.Column, - EnumSet.of( - DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, - DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) - .setOperationScope(HiveOperationScope.TABLE) - .setOperationType( - HiveAuthzPrivileges.HiveOperationType.INFO) - .build(); + public static final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge( + AuthorizableType.Column, + EnumSet.of( + DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, + DBModelAction.LOCK)) + .addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.SELECT)) + .setOperationScope(HiveOperationScope.CONNECT) + .setOperationType(HiveOperationType.QUERY) + .build(); + + public static final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() + .addInputObjectPriviledge( + AuthorizableType.Column, + EnumSet.of( + DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) + .setOperationScope(HiveOperationScope.TABLE) + .setOperationType( + HiveAuthzPrivileges.HiveOperationType.INFO) + .build(); /** * Internal class used by AssertJ extract() method to extract the object name of diff --git a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/metastore/TestSentryMetaStoreFilterHook.java b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/metastore/TestSentryMetaStoreFilterHook.java index 1f7148b..a498f98 100644 --- a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/metastore/TestSentryMetaStoreFilterHook.java +++ b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/metastore/TestSentryMetaStoreFilterHook.java @@ -54,28 +54,26 @@ public class TestSentryMetaStoreFilterHook { // Mock the HiveAuthzBinding to avoid making real connections to a Sentry server private HiveAuthzBinding mockBinding = Mockito.mock(HiveAuthzBinding.class); private final HiveAuthzPrivileges LIST_DATABASES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() - .addInputObjectPriviledge( - AuthorizableType.Column, - EnumSet.of( - DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, - DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, - DBModelAction.LOCK)) - .addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.SELECT)) - .setOperationScope(HiveOperationScope.CONNECT) - .setOperationType(HiveOperationType.QUERY) - .build(); - + .addInputObjectPriviledge( + AuthorizableType.Column, + EnumSet.of( + DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, + DBModelAction.LOCK)) + .addInputObjectPriviledge(AuthorizableType.URI, EnumSet.of(DBModelAction.SELECT)) + .setOperationScope(HiveOperationScope.CONNECT) + .setOperationType(HiveOperationType.QUERY) + .build(); private final HiveAuthzPrivileges LIST_TABLES_PRIVILEGES = new HiveAuthzPrivileges.AuthzPrivilegeBuilder() - .addInputObjectPriviledge( - AuthorizableType.Column, - EnumSet.of( - DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, - DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) - .setOperationScope(HiveOperationScope.TABLE) - .setOperationType( - HiveAuthzPrivileges.HiveOperationType.INFO) - .build(); - + .addInputObjectPriviledge( + AuthorizableType.Column, + EnumSet.of( + DBModelAction.SELECT, DBModelAction.INSERT, DBModelAction.ALTER, + DBModelAction.CREATE, DBModelAction.DROP, DBModelAction.INDEX, DBModelAction.LOCK)) + .setOperationScope(HiveOperationScope.TABLE) + .setOperationType( + HiveAuthzPrivileges.HiveOperationType.INFO) + .build(); private HiveAuthzConf authzConf = new HiveAuthzConf(); private final Server SERVER1 = new Server("server1"); @@ -187,7 +185,7 @@ public class TestSentryMetaStoreFilterHook { SentryMetaStoreFilterHook filterHook = new SentryMetaStoreFilterHook(null, authzConf, getMockBinding(USER1)); - // Verify that only db2 is returned by the filter + // Verify that only t2 is returned by the filter restrictTablesNamesOnBinding(USER1, DB1, Arrays.asList("t1", "t3")); assertThat(filterHook.filterTableNames(DB1, Arrays.asList("t1", "t2", "t3"))).containsExactly("t2"); assertThat(filterHook.filterTables(Arrays.asList( diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java index d63957a..cc0465a 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java @@ -108,10 +108,12 @@ public abstract class AbstractTestWithStaticConfiguration extends RulesForE2ETes USER2_1 = StaticUserGroup.USER2_1, USER3_1 = StaticUserGroup.USER3_1, USER4_1 = StaticUserGroup.USER4_1, + USER5_1 = StaticUserGroup.USER5_1, USERGROUP1 = StaticUserGroup.USERGROUP1, USERGROUP2 = StaticUserGroup.USERGROUP2, USERGROUP3 = StaticUserGroup.USERGROUP3, USERGROUP4 = StaticUserGroup.USERGROUP4, + USERGROUP5 = StaticUserGroup.USERGROUP5, GROUP1_ROLE = "group1_role", DB1 = "db_1", DB2 = "db_2", @@ -137,6 +139,7 @@ public abstract class AbstractTestWithStaticConfiguration extends RulesForE2ETes protected static boolean enableHiveConcurrency = false; protected static boolean enableAuthorizingObjectStore = true; protected static boolean enableAuthorizeReadMetaData = false; + protected static boolean enableFilter = false; // indicate if the database need to be clear for every test case in one test class protected static boolean clearDbPerTest = true; @@ -289,6 +292,12 @@ public abstract class AbstractTestWithStaticConfiguration extends RulesForE2ETes properties.put(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL.varname, ConfVars.METASTORE_RAW_STORE_IMPL.defaultStrVal); } + if (enableFilter) { + properties.put(ConfVars.METASTORE_FILTER_HOOK.varname, "org.apache.sentry.binding.metastore.SentryMetaStoreFilterHook"); + } else { + properties.put(ConfVars.METASTORE_FILTER_HOOK.varname, ConfVars.METASTORE_FILTER_HOOK.defaultStrVal); + } + if (enableAuthorizeReadMetaData) { properties.put("senry.metastore.read.authorization.enabled", "true"); } else { diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/StaticUserGroup.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/StaticUserGroup.java index 8306e95..c7e941b 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/StaticUserGroup.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/StaticUserGroup.java @@ -27,11 +27,13 @@ public class StaticUserGroup { USER2_1 = "user2_1", USER3_1 = "user3_1", USER4_1 = "user4_1", + USER5_1 = "user5_1", HIVE = "hive", USERGROUP1 = "user_group1", USERGROUP2 = "user_group2", USERGROUP3 = "user_group3", - USERGROUP4 = "user_group4"; + USERGROUP4 = "user_group4", + USERGROUP5 = "user_group5"; private static final Map<String, String> staticMapping; static { @@ -46,6 +48,7 @@ public class StaticUserGroup { staticMapping.put(USER2_1, USERGROUP2); staticMapping.put(USER3_1, USERGROUP3); staticMapping.put(USER4_1, USERGROUP4); + staticMapping.put(USER5_1, USERGROUP5); } public static Map<String, String> getStaticMapping(){ diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestShowMetadataPrivileges.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestShowMetadataPrivileges.java index 88e697b..6a88d0b 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestShowMetadataPrivileges.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestShowMetadataPrivileges.java @@ -49,7 +49,7 @@ public class TestShowMetadataPrivileges extends AbstractTestWithStaticConfigurat return Arrays.asList(new Object[][] { { null, NOT_ALLOWED }, // Means no privileges { DBModelAction.ALL, ALLOWED }, - { DBModelAction.CREATE, NOT_ALLOWED }, + { DBModelAction.CREATE, ALLOWED }, { DBModelAction.SELECT, ALLOWED }, { DBModelAction.INSERT, ALLOWED }, { DBModelAction.ALTER, ALLOWED }, diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java index f1600c5..2a321fd 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/AbstractMetastoreTestWithStaticConfiguration.java @@ -221,6 +221,18 @@ public abstract class AbstractMetastoreTestWithStaticConfiguration extends client.dropDatabase(dbName, true, true, true); } + public void dropAllMetastoreDBIfExists(HiveMetaStoreClient client, boolean dropDefault) throws Exception { + List<String> dbNames = client.getAllDatabases(); + + for (String dbName : dbNames) { + if (!dropDefault && dbName.equalsIgnoreCase("default")) { + continue; + } + + client.dropDatabase(dbName, true, true, true); + } + } + public void execHiveSQLwithOverlay(final String sqlStmt, final String userName, Map<String, String> overLay) throws Exception { final HiveConf hiveConf = new HiveConf(); diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestMetastoreEndToEnd.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestMetastoreEndToEnd.java index 6327f16..cb201bb 100644 --- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestMetastoreEndToEnd.java +++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/metastore/TestMetastoreEndToEnd.java @@ -25,10 +25,15 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.security.PrivilegedExceptionAction; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Map; import org.apache.hadoop.hive.metastore.api.Database; +import org.apache.hadoop.security.UserGroupInformation; import org.junit.Assert; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; @@ -56,12 +61,15 @@ public class TestMetastoreEndToEnd extends private PolicyFile policyFile; private File dataFile; private static final String dbName = "db_1"; + private static final String dbName2 = "db_2"; private static final String db_all_role = "all_db1"; private static final String uri_role = "uri_role"; private static final String tab1_all_role = "tab1_all_role"; private static final String tab1_read_role = "tab1_read_role"; private static final String tab2_all_role = "tab2_all_role"; private static final String tab2_read_role = "tab2_read_role"; + private static final String server_create_role = "server_create_role"; + private static final String db2_all_role = "db2_all_role"; private static final String tabName1 = "tab1"; private static final String tabName2 = "tab2"; private static final String tabName3 = "tab3"; @@ -71,6 +79,7 @@ public class TestMetastoreEndToEnd extends setMetastoreListener = false; enableAuthorizingObjectStore = false; enableAuthorizeReadMetaData = true; + enableFilter = true; AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration(); } @@ -99,6 +108,9 @@ public class TestMetastoreEndToEnd extends .addRolesToGroup(USERGROUP2, tab2_all_role) .addRolesToGroup(USERGROUP3, tab1_read_role) .addRolesToGroup(USERGROUP3, tab2_read_role) + .addRolesToGroup(USERGROUP4, tab1_all_role) + .addRolesToGroup(USERGROUP4, db2_all_role) + .addRolesToGroup(USERGROUP5, server_create_role) .addPermissionsToRole(db_all_role, "server=server1->db=" + dbName) .addPermissionsToRole("read_db_role", "server=server1->db=" + dbName + "->action=SELECT") @@ -110,6 +122,9 @@ public class TestMetastoreEndToEnd extends "server=server1->db=" + dbName + "->table=" + tabName1 + "->action=SELECT") .addPermissionsToRole(tab2_read_role, "server=server1->db=" + dbName + "->table=" + tabName2 + "->action=SELECT") + .addPermissionsToRole(db2_all_role, + "server=server1->db=" + dbName2 + "->action=ALL") + .addPermissionsToRole(server_create_role, "server=server1" + "->action=CREATE") .setUserGroupMapping(StaticUserGroup.getStaticMapping()); writePolicyFile(policyFile); } @@ -681,6 +696,122 @@ public class TestMetastoreEndToEnd extends client.close(); } + private void verifyReturnedList(HashSet<String> expectedSet, List<String> actualList) { + assertThat(expectedSet.size()).isEqualTo(actualList.size()); + + for (String actualItem : actualList) { + assertThat(expectedSet).contains(actualItem); + } + } + + private void verifyReturnedList(HashSet<String> expectedSet, List<String> actualList, boolean strict) { + + // expectedSet and actualList contain same items, but may differ in order + if (strict ) { + verifyReturnedList(expectedSet, actualList); + return; + } + + // check all items in expectedSet are in actualList, but actualList may contain extra items + for (String actualItem : actualList) { + if (expectedSet.contains(actualItem)) { + expectedSet.remove(actualItem); + } + } + + assertThat(expectedSet.size()).isEqualTo(0); + } + + @Test + public void testListDatabases() throws Exception { + List<String> dbNames; + HashSet<String> allDatabaseNames = new HashSet<>(Arrays.asList("default", dbName, dbName2)); + + // Create databases and verify the admin can list the database names + final HiveMetaStoreClient client = context.getMetaStoreClient(ADMIN1); + dropAllMetastoreDBIfExists(client, false); + createMetastoreDB(client, dbName); + createMetastoreDB(client, dbName2); + UserGroupInformation clientUgi = UserGroupInformation.createRemoteUser(ADMIN1); + dbNames = clientUgi.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(allDatabaseNames, dbNames, true); + client.close(); + + // Verify a user with ALL privileges on a database can get its name + // and cannot get database name that has no privilege on + // USER1_1 has ALL at dbName + final HiveMetaStoreClient client_USER1_1 = context.getMetaStoreClient(USER1_1); + UserGroupInformation clientUgi_USER1_1 = UserGroupInformation.createRemoteUser(USER1_1); + dbNames = clientUgi_USER1_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER1_1.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(new HashSet<>(Arrays.asList("default", dbName)), dbNames, true); + client_USER1_1.close(); + + // USER2_1 has SELECT at dbName + final HiveMetaStoreClient client_USER2_1 = context.getMetaStoreClient(USER2_1); + UserGroupInformation clientUgi_USER2_1 = UserGroupInformation.createRemoteUser(USER2_1); + dbNames = clientUgi_USER2_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER2_1.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(new HashSet<>(Arrays.asList("default", dbName)), dbNames, true); + //assertThat(dbNames.get(0)).isEqualToIgnoringCase(dbName); + client.close(); + + // USER3_1 has SELECT at dbName.tabName1 and dbName.tabName2 + final HiveMetaStoreClient client_USER3_1 = context.getMetaStoreClient(USER3_1); + UserGroupInformation clientUgi_USER3_1 = UserGroupInformation.createRemoteUser(USER3_1); + dbNames = clientUgi_USER3_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER3_1.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(new HashSet<>(Arrays.asList("default", dbName)), dbNames,true); + client.close(); + + // USER4_1 has ALL at dbName.tabName1 and dbName2 + final HiveMetaStoreClient client_USER4_1 = context.getMetaStoreClient(USER4_1); + UserGroupInformation clientUgi_USER4_1 = UserGroupInformation.createRemoteUser(USER4_1); + dbNames = clientUgi_USER4_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER4_1.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(allDatabaseNames, dbNames, true); + client.close(); + + // USER5_1 has CREATE at server + final HiveMetaStoreClient client_USER5_1 = context.getMetaStoreClient(USER5_1); + UserGroupInformation clientUgi_USER5_1 = UserGroupInformation.createRemoteUser(USER5_1); + dbNames = clientUgi_USER5_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER5_1.getAllDatabases(); + } + }); + assertThat(dbNames).isNotNull(); + verifyReturnedList(allDatabaseNames, dbNames, true); + client.close(); + } + @Test public void testReadTable() throws Exception { Table tbl; @@ -723,4 +854,154 @@ public class TestMetastoreEndToEnd extends } client.close(); } + + @Test + public void testListTables() throws Exception { + List<String> tableNames; + HashSet<String> expectedTableNames = new HashSet<>(Arrays.asList(tabName1, tabName2)); + + // Create databases and verify the admin can list the database names + final HiveMetaStoreClient client = context.getMetaStoreClient(ADMIN1); + dropMetastoreDBIfExists(client, dbName); + createMetastoreDB(client, dbName); + createMetastoreTable(client, dbName, tabName1, + Lists.newArrayList(new FieldSchema("col1", "int", ""))); + createMetastoreTable(client, dbName, tabName2, + Lists.newArrayList(new FieldSchema("col1", "int", ""))); + createMetastoreTable(client, dbName, tabName3, + Lists.newArrayList(new FieldSchema("col1", "int", ""))); + UserGroupInformation clientUgi = UserGroupInformation.createRemoteUser(ADMIN1); + tableNames = clientUgi.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(3); + + dropMetastoreDBIfExists(client, dbName2); + createMetastoreDB(client, dbName2); + createMetastoreTable(client, dbName2, tabName1, + Lists.newArrayList(new FieldSchema("col1", "int", ""))); + createMetastoreTable(client, dbName2, tabName2, + Lists.newArrayList(new FieldSchema("col1", "int", ""))); + tableNames = clientUgi.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(2); + client.close(); + + // Verify a user with ALL privileges on a database can get its name + // and cannot get database name that has no privilege on + // USER1_1 has ALL on dbName + final HiveMetaStoreClient client_USER1_1 = context.getMetaStoreClient(USER1_1); + UserGroupInformation clientUgi_USER1_1 = UserGroupInformation.createRemoteUser(USER1_1); + tableNames = clientUgi_USER1_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER1_1.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(3); + tableNames = clientUgi_USER1_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER1_1.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(0); + + // USER2_1 has SELECT on dbName + final HiveMetaStoreClient client_USER2_1 = context.getMetaStoreClient(USER2_1); + UserGroupInformation clientUgi_USER2_1 = UserGroupInformation.createRemoteUser(USER2_1); + tableNames = clientUgi_USER2_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER2_1.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(3); + tableNames = clientUgi_USER2_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER2_1.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(0); + + // USER3_1 has SELECT on dbName.tabName1 and dbName.tabName2 + final HiveMetaStoreClient client_USER3_1 = context.getMetaStoreClient(USER3_1); + UserGroupInformation clientUgi_USER3_1 = UserGroupInformation.createRemoteUser(USER3_1); + tableNames = clientUgi_USER3_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER3_1.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(2); + assertThat(expectedTableNames).contains(tableNames.get(0)); + assertThat(expectedTableNames).contains(tableNames.get(1)); + tableNames = clientUgi_USER3_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER3_1.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(0); + client.close(); + + // USER4_1 ALL on dbName.tabName1 and dbName2 + final HiveMetaStoreClient client_USER4_1 = context.getMetaStoreClient(USER4_1); + UserGroupInformation clientUgi_USER4_1 = UserGroupInformation.createRemoteUser(USER4_1); + tableNames = clientUgi_USER4_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER4_1.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(1); // only has access to tabName1 and tabName2 + assertThat(tableNames.get(0)).isEqualToIgnoringCase(tabName1); + tableNames = clientUgi_USER4_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER4_1.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(2); + client.close(); + + // USER5_1 CREATE on server + final HiveMetaStoreClient client_USER5_1 = context.getMetaStoreClient(USER5_1); + UserGroupInformation clientUgi_USER5_1 = UserGroupInformation.createRemoteUser(USER5_1); + tableNames = clientUgi_USER5_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER5_1.getAllTables(dbName); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(3); + tableNames = clientUgi_USER5_1.doAs(new PrivilegedExceptionAction<List<String>>() { + @Override + public List<String> run() throws Exception { + return client_USER5_1.getAllTables(dbName2); + } + }); + assertThat(tableNames).isNotNull(); + assertThat(tableNames.size()).isEqualTo(2); + client.close(); + } }