SENTRY-2500: CREATE on server does not provide HMS server side read authorization for get_all_tables(database_name)
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 @@
 
   }
 
-  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 @@
     .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 @@
   }
 
   /**
+   * 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 @@
       }
     };
 
-  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();
+  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();
 
-  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_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 @@
   // 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 @@
     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 @@
       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 @@
   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 @@
       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 @@
       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 @@
     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 @@
     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 @@
     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 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 @@
   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 @@
     setMetastoreListener = false;
     enableAuthorizingObjectStore = false;
     enableAuthorizeReadMetaData = true;
+    enableFilter = true;
     AbstractMetastoreTestWithStaticConfiguration.setupTestStaticConfiguration();
   }
 
@@ -99,6 +108,9 @@
             .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 @@
                     "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 @@
     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 @@
     }
     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();
+  }
 }