IMPALA-9231: support customized privilege checks for SHOW visibility

In IMPALA-9002 we introduce a flag simplify_check_on_show_tables which
simplifies privilege checks for SHOW TABLES. Only tables with privileges
implying SELECT privilege will be shown.

This patch provides the same mechanism for SHOW DATABASES. Also augment
the flag to be a list of privilege names and rename it to
min_privilege_set_for_show_stmts. The default value is "any" which
remains the default behavior. If set to "select", only dbs/tables on
which the user has SELECT privilege will be shown. If set to
"select,insert", only dbs/tables on which the user has SELECT or INSERT
privilege will be shown.

Tests:
 - Add tests in test_authorization.py

Change-Id: I631fc5c386a52f0a1f62182473be15fcc3dd8609
Reviewed-on: http://gerrit.cloudera.org:8080/14904
Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
diff --git a/be/src/common/global-flags.cc b/be/src/common/global-flags.cc
index c2a4803..451da40 100644
--- a/be/src/common/global-flags.cc
+++ b/be/src/common/global-flags.cc
@@ -279,12 +279,18 @@
 DEFINE_bool(unlock_zorder_sort, false,
     "(Experimental) If true, enables using ZORDER option for SORT BY.");
 
-DEFINE_bool(simplify_check_on_show_tables, false,
-    "If true, only check SELECT privilege on SHOW TABLES or GET_TABLES when enabling "
-    "authorization. If false, all privileges will be checked for visibility of a table. "
-    "A table will show up if the user has any privileges on it. This flag is used to "
-    "improve SHOW TABLES performance when using Sentry and have thousands of candidate "
-    "tables to be checked. No performance gain is found in using Ranger");
+DEFINE_string(min_privilege_set_for_show_stmts, "any",
+    "Comma separated list of privileges. Any one of them is required to show a database "
+    "or table. Defaults to \"any\" which means if the user has any privilege (CREATE, "
+    "SELECT, INSERT, etc) on a database or table, the database/table is visible in the "
+    "results of SHOW DATABASES/TABLES. If set to \"select\", only dbs/tables on which "
+    "the user has SELECT privilege will be shown. If set to \"select,insert\", only "
+    "dbs/tables on which the user has SELECT or INSERT privilege will be shown. In "
+    "practice, this flag can be set to \"select\" or \"select,insert\" to improve "
+    "performance of SHOW DATABASES/TABLES and GET_SCHEMAS/GET_TABLES, especially when "
+    "using Sentry and having thousands of candidate dbs/tables to be checked with a "
+    "user with large scale of privileges. No significant performance gain when using "
+    "Ranger");
 
 // Set the slow RPC threshold to 2 minutes to avoid false positives (since TransmitData
 // RPCs can take some time to process).
diff --git a/be/src/util/backend-gflag-util.cc b/be/src/util/backend-gflag-util.cc
index c5eb39e..6906e1d 100644
--- a/be/src/util/backend-gflag-util.cc
+++ b/be/src/util/backend-gflag-util.cc
@@ -81,7 +81,7 @@
 DECLARE_string(blacklisted_dbs);
 DECLARE_bool(unlock_zorder_sort);
 DECLARE_string(blacklisted_tables);
-DECLARE_bool(simplify_check_on_show_tables);
+DECLARE_string(min_privilege_set_for_show_stmts);
 DECLARE_int32(num_expected_executors);
 
 namespace impala {
@@ -167,7 +167,7 @@
   cfg.__set_blacklisted_dbs(FLAGS_blacklisted_dbs);
   cfg.__set_unlock_zorder_sort(FLAGS_unlock_zorder_sort);
   cfg.__set_blacklisted_tables(FLAGS_blacklisted_tables);
-  cfg.__set_simplify_check_on_show_tables(FLAGS_simplify_check_on_show_tables);
+  cfg.__set_min_privilege_set_for_show_stmts(FLAGS_min_privilege_set_for_show_stmts);
   cfg.__set_num_expected_executors(FLAGS_num_expected_executors);
   RETURN_IF_ERROR(SerializeThriftMsg(jni_env, &cfg, cfg_bytes));
   return Status::OK();
diff --git a/common/thrift/BackendGflags.thrift b/common/thrift/BackendGflags.thrift
index 7fc47d5..3489793 100644
--- a/common/thrift/BackendGflags.thrift
+++ b/common/thrift/BackendGflags.thrift
@@ -142,7 +142,7 @@
 
   59: required bool unlock_zorder_sort
 
-  60: required bool simplify_check_on_show_tables
+  60: required string min_privilege_set_for_show_stmts
 
   61: required bool mt_dop_auto_fallback
 
diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
index 8038913..e590d91 100644
--- a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
+++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java
@@ -30,7 +30,7 @@
  * An interface used to check whether a user has access to a given resource.
  */
 public interface AuthorizationChecker {
-  /*
+  /**
    * Returns true if the given user has permission to execute the given
    * request, false otherwise. Always returns true if authorization is disabled or the
    * given user is an admin user.
@@ -38,6 +38,14 @@
   boolean hasAccess(User user, PrivilegeRequest request) throws InternalException;
 
   /**
+   * Returns true if the given user has permission to execute any of the given
+   * requests, false otherwise. Always returns true if authorization is disabled or the
+   * given user is an admin user.
+   */
+  boolean hasAnyAccess(User user, Set<PrivilegeRequest> requests)
+      throws InternalException;
+
+  /**
    * Creates a a new {@link AuthorizationContext}. {@link AuthorizationContext} gets
    * created per authorization execution.
    *
diff --git a/fe/src/main/java/org/apache/impala/authorization/BaseAuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/BaseAuthorizationChecker.java
index 9e171d9..3920f83 100644
--- a/fe/src/main/java/org/apache/impala/authorization/BaseAuthorizationChecker.java
+++ b/fe/src/main/java/org/apache/impala/authorization/BaseAuthorizationChecker.java
@@ -47,7 +47,7 @@
 
   protected final AuthorizationConfig config_;
 
-  /*
+  /**
    * Creates a new AuthorizationChecker based on the config values.
    */
   protected BaseAuthorizationChecker(AuthorizationConfig config) {
@@ -55,7 +55,7 @@
     config_ = config;
   }
 
-  /*
+  /**
    * Returns true if the given user has permission to execute the given
    * request, false otherwise. Always returns true if authorization is disabled or the
    * given user is an admin user.
@@ -83,6 +83,20 @@
     return authorizeResource(authzCtx, user, request);
   }
 
+  @Override
+  public boolean hasAnyAccess(User user, Set<PrivilegeRequest> requests)
+      throws InternalException {
+    Preconditions.checkNotNull(user);
+    Preconditions.checkNotNull(requests);
+
+    for (PrivilegeRequest request : requests) {
+      if (hasAccess(user, request)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * Executes code after the authorization check.
    * Override this method to add custom post-authorization check.
diff --git a/fe/src/main/java/org/apache/impala/authorization/PrivilegeRequestBuilder.java b/fe/src/main/java/org/apache/impala/authorization/PrivilegeRequestBuilder.java
index f87518d..a41b098 100644
--- a/fe/src/main/java/org/apache/impala/authorization/PrivilegeRequestBuilder.java
+++ b/fe/src/main/java/org/apache/impala/authorization/PrivilegeRequestBuilder.java
@@ -17,7 +17,11 @@
 
 package org.apache.impala.authorization;
 
+import java.util.EnumSet;
+import java.util.Set;
+
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
 import org.apache.impala.catalog.FeDb;
 import org.apache.impala.catalog.FeTable;
 
@@ -33,6 +37,7 @@
   private final AuthorizableFactory authzFactory_;
   private Authorizable authorizable_;
   private Privilege privilege_;
+  private EnumSet<Privilege> privilegeSet_;
   private boolean grantOption_ = false;
 
   public PrivilegeRequestBuilder(AuthorizableFactory authzFactory) {
@@ -152,6 +157,14 @@
   }
 
   /**
+   * Specifies any of the privileges the user needs to have.
+   */
+  public PrivilegeRequestBuilder anyOf(EnumSet<Privilege> privileges) {
+    privilegeSet_ = privileges;
+    return this;
+  }
+
+  /**
    * Specifies the user needs "ALL" privileges
    */
   public PrivilegeRequestBuilder all() {
@@ -184,4 +197,14 @@
     Preconditions.checkNotNull(privilege_);
     return new PrivilegeRequest(authorizable_, privilege_, grantOption_);
   }
+
+  public Set<PrivilegeRequest> buildSet() {
+    Preconditions.checkNotNull(authorizable_);
+    Preconditions.checkNotNull(privilegeSet_);
+    Set<PrivilegeRequest> privileges = Sets.newHashSet();
+    for (Privilege p : privilegeSet_) {
+      privileges.add(new PrivilegeRequest(authorizable_, p, grantOption_));
+    }
+    return privileges;
+  }
 }
diff --git a/fe/src/main/java/org/apache/impala/service/BackendConfig.java b/fe/src/main/java/org/apache/impala/service/BackendConfig.java
index cf6b767..47c4660 100644
--- a/fe/src/main/java/org/apache/impala/service/BackendConfig.java
+++ b/fe/src/main/java/org/apache/impala/service/BackendConfig.java
@@ -193,8 +193,8 @@
     backendCfg_.setUnlock_zorder_sort(zOrdering);
   }
 
-  public boolean simplifyCheckOnShowTables() {
-    return backendCfg_.simplify_check_on_show_tables;
+  public String getMinPrivilegeSetForShowStmts() {
+    return backendCfg_.min_privilege_set_for_show_stmts;
   }
 
   // Inits the auth_to_local configuration in the static KerberosName class.
diff --git a/fe/src/main/java/org/apache/impala/service/Frontend.java b/fe/src/main/java/org/apache/impala/service/Frontend.java
index 2bf1e98..5c36f37 100644
--- a/fe/src/main/java/org/apache/impala/service/Frontend.java
+++ b/fe/src/main/java/org/apache/impala/service/Frontend.java
@@ -23,6 +23,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -168,6 +169,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicates;
+import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.Uninterruptibles;
@@ -249,6 +251,8 @@
   private final FeCatalogManager catalogManager_;
   private final AuthorizationFactory authzFactory_;
   private final AuthorizationManager authzManager_;
+  // Privileges in which the user should have any of them to see a database or table,
+  private final EnumSet<Privilege> minPrivilegeSetForShowStmts_;
   /**
    * Authorization checker. Initialized and periodically loaded by a task
    * running on the {@link #policyReader_} thread.
@@ -296,6 +300,7 @@
     catalogManager_.setAuthzChecker(authzChecker_);
     authzManager_ = authzFactory.newAuthorizationManager(catalogManager_,
         authzChecker_::get);
+    minPrivilegeSetForShowStmts_ = getMinPrivilegeSetForShowStmts();
     impaladTableUsageTracker_ = ImpaladTableUsageTracker.createFromConfig(
         BackendConfig.INSTANCE);
     queryHookManager_ = QueryEventHookManager.createFromConfig(BackendConfig.INSTANCE);
@@ -307,6 +312,24 @@
     }
   }
 
+  /**
+   * Returns the required privilege set for showing a database or table.
+   */
+  private EnumSet<Privilege> getMinPrivilegeSetForShowStmts() throws InternalException {
+    String configStr = BackendConfig.INSTANCE.getMinPrivilegeSetForShowStmts();
+    if (Strings.isNullOrEmpty(configStr)) return EnumSet.of(Privilege.ANY);
+    EnumSet<Privilege> privileges = EnumSet.noneOf(Privilege.class);
+    for (String pStr : configStr.toUpperCase().split(",")) {
+      try {
+        privileges.add(Privilege.valueOf(pStr.trim()));
+      } catch (IllegalArgumentException e) {
+        LOG.error("Illegal privilege name '{}'", pStr, e);
+        throw new InternalException("Failed to parse privileges: " + configStr, e);
+      }
+    }
+    return privileges.isEmpty() ? EnumSet.of(Privilege.ANY) : privileges;
+  }
+
   public FeCatalog getCatalog() { return catalogManager_.getOrCreateCatalog(); }
 
   public AuthorizationChecker getAuthzChecker() { return authzChecker_.get(); }
@@ -774,10 +797,6 @@
     FeCatalog catalog = getCatalog();
     List<String> tblNames = catalog.getTableNames(dbName, matcher);
     if (authzFactory_.getAuthorizationConfig().isEnabled()) {
-      Privilege requiredPrivilege = Privilege.ANY;
-      if (BackendConfig.INSTANCE.simplifyCheckOnShowTables()) {
-        requiredPrivilege = Privilege.SELECT;
-      }
       Iterator<String> iter = tblNames.iterator();
       while (iter.hasNext()) {
         String tblName = iter.next();
@@ -794,10 +813,12 @@
           LOG.info("Table {} not yet loaded, ignoring it in table listing.",
               dbName + "." + tblName);
         }
-        PrivilegeRequest privilegeRequest = new PrivilegeRequestBuilder(
+        Set<PrivilegeRequest> requests = new PrivilegeRequestBuilder(
             authzFactory_.getAuthorizableFactory())
-            .allOf(requiredPrivilege).onAnyColumn(dbName, tblName, tableOwner).build();
-        if (!authzChecker_.get().hasAccess(user, privilegeRequest)) {
+            .anyOf(minPrivilegeSetForShowStmts_)
+            .onAnyColumn(dbName, tblName, tableOwner)
+            .buildSet();
+        if (!authzChecker_.get().hasAnyAccess(user, requests)) {
           iter.remove();
         }
       }
@@ -940,10 +961,12 @@
       // Default DB should always be shown.
       return true;
     }
-    PrivilegeRequest request = new PrivilegeRequestBuilder(
-        authzFactory_.getAuthorizableFactory()).any().onAnyColumn(
-            db.getName(), db.getOwnerUser()).build();
-    return authzChecker_.get().hasAccess(user, request);
+    Set<PrivilegeRequest> requests = new PrivilegeRequestBuilder(
+        authzFactory_.getAuthorizableFactory())
+        .anyOf(minPrivilegeSetForShowStmts_)
+        .onAnyColumn(db.getName(), db.getOwnerUser())
+        .buildSet();
+    return authzChecker_.get().hasAnyAccess(user, requests);
   }
 
   /**
diff --git a/tests/authorization/test_authorization.py b/tests/authorization/test_authorization.py
index d58dea2..885d184 100644
--- a/tests/authorization/test_authorization.py
+++ b/tests/authorization/test_authorization.py
@@ -486,16 +486,21 @@
       self.execute_query_expect_success(client,
                                         "select * from functional.alltypes limit 1")
 
-  @pytest.mark.execute_serially
-  @CustomClusterTestSuite.with_args(
-    impalad_args="--server_name=server1 --sentry_config=%s "
-                 "--authorized_proxy_user_config=%s=* "
-                 "--simplify_check_on_show_tables=true" %
-                 (SENTRY_CONFIG_FILE, getuser()),
-    catalogd_args="--sentry_config={0}".format(SENTRY_CONFIG_FILE),
-    sentry_config=SENTRY_CONFIG_FILE_OO,  # Enable Sentry Object Ownership
-    sentry_log_dir="{0}/test_fast_show_tables_with_sentry".format(SENTRY_BASE_LOG_DIR))
-  def test_fast_show_tables_with_sentry(self, unique_role, unique_name):
+  @staticmethod
+  def _verify_show_dbs(result, unique_name, visibility_privileges=PRIVILEGES):
+    """ Helper function for verifying the results of SHOW DATABASES below.
+    Only show databases with privileges implying any of the visibility_privileges.
+    """
+    for priv in PRIVILEGES:
+      # Result lines are in the format of "db_name\tdb_comment"
+      db_name = 'db_%s_%s\t' % (unique_name, priv)
+      if priv != 'all' and priv not in visibility_privileges:
+        assert db_name not in result.data
+      else:
+        assert db_name in result.data
+
+  def _test_sentry_show_stmts_helper(self, unique_role, unique_name,
+                                     visibility_privileges):
     unique_db = unique_name + "_db"
     # TODO: can we create and use a temp username instead of using root?
     another_user = 'root'
@@ -511,52 +516,138 @@
       self.client.execute("drop database if exists %s cascade" % unique_db)
       self.client.execute("create database %s" % unique_db)
       for priv in PRIVILEGES:
+        self.client.execute("create database db_%s_%s" % (unique_name, priv))
+        self.client.execute("grant {0} on database db_{1}_{2} to role {3}"
+                            .format(priv, unique_name, priv, unique_role))
         self.client.execute("create table %s.tbl_%s (i int)" % (unique_db, priv))
         self.client.execute("grant {0} on table {1}.tbl_{2} to role {3}"
                             .format(priv, unique_db, priv, unique_role))
       self.client.execute("grant role %s to group %s" %
                           (unique_role, another_user_grp))
 
-      # Owner (current user) can still see all the tables
+      # Owner (current user) can still see all the owned databases and tables
+      result = self.client.execute("show databases")
+      TestAuthorization._verify_show_dbs(result, unique_name)
       result = self.client.execute("show tables in %s" % unique_db)
       assert result.data == ["tbl_%s" % p for p in PRIVILEGES]
 
-      # Check SHOW TABLES using another username
+      # Check SHOW DATABASES and SHOW TABLES using another username
       # Create another client so we can user another username
       root_impalad_client = self.create_impala_client()
       result = self.execute_query_expect_success(
-        root_impalad_client, "show tables in %s" % unique_db, user=another_user)
-      # Only show tables with privileges implying SELECT privilege
-      assert result.data == ['tbl_all', 'tbl_select']
+          root_impalad_client, "show databases", user=another_user)
+      TestAuthorization._verify_show_dbs(result, unique_name, visibility_privileges)
+      result = self.execute_query_expect_success(
+          root_impalad_client, "show tables in %s" % unique_db, user=another_user)
+      # Only show tables with privileges implying any of the visibility privileges
+      assert 'tbl_all' in result.data   # ALL can imply to any privilege
+      for p in visibility_privileges:
+        assert 'tbl_%s' % p in result.data
     finally:
-      self.role_cleanup(unique_role)
       self.client.execute("drop database if exists %s cascade" % unique_db)
+      for priv in PRIVILEGES:
+        self.client.execute(
+            "drop database if exists db_%s_%s cascade" % (unique_name, priv))
+      self.role_cleanup(unique_role)
 
   @pytest.mark.execute_serially
   @CustomClusterTestSuite.with_args(
-    impalad_args="--server-name=server1 --ranger_service_type=hive "
-                 "--ranger_app_id=impala --authorization_provider=ranger "
-                 "--simplify_check_on_show_tables=true",
-    catalogd_args="--server-name=server1 --ranger_service_type=hive "
-                  "--ranger_app_id=impala --authorization_provider=ranger")
-  def test_fast_show_tables_with_ranger(self, unique_role, unique_name):
+    impalad_args="--server_name=server1 --sentry_config=%s "
+                 "--authorized_proxy_user_config=%s=* "
+                 "--min_privilege_set_for_show_stmts=select" %
+                 (SENTRY_CONFIG_FILE, getuser()),
+    catalogd_args="--sentry_config={0}".format(SENTRY_CONFIG_FILE),
+    sentry_config=SENTRY_CONFIG_FILE_OO,  # Enable Sentry Object Ownership
+    sentry_log_dir="{0}/test_sentry_show_stmts_with_select".format(SENTRY_BASE_LOG_DIR))
+  def test_sentry_show_stmts_with_select(self, unique_role, unique_name):
+    self._test_sentry_show_stmts_helper(unique_role, unique_name, ['select'])
+
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args="--server_name=server1 --sentry_config=%s "
+                 "--authorized_proxy_user_config=%s=* "
+                 "--min_privilege_set_for_show_stmts=select,insert" %
+                 (SENTRY_CONFIG_FILE, getuser()),
+    catalogd_args="--sentry_config={0}".format(SENTRY_CONFIG_FILE),
+    sentry_config=SENTRY_CONFIG_FILE_OO,  # Enable Sentry Object Ownership
+    sentry_log_dir="{0}/test_sentry_show_stmts_with_select_insert"
+                   .format(SENTRY_BASE_LOG_DIR))
+  def test_sentry_show_stmts_with_select_insert(self, unique_role, unique_name):
+    self._test_sentry_show_stmts_helper(unique_role, unique_name,
+                                        ['select', 'insert'])
+
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args="--server_name=server1 --sentry_config=%s "
+                 "--authorized_proxy_user_config=%s=* "
+                 "--min_privilege_set_for_show_stmts=any" %
+                 (SENTRY_CONFIG_FILE, getuser()),
+    catalogd_args="--sentry_config={0}".format(SENTRY_CONFIG_FILE),
+    sentry_config=SENTRY_CONFIG_FILE_OO,  # Enable Sentry Object Ownership
+    sentry_log_dir="{0}/test_sentry_show_stmts_with_any".format(SENTRY_BASE_LOG_DIR))
+  def test_sentry_show_stmts_with_any(self, unique_role, unique_name):
+    self._test_sentry_show_stmts_helper(unique_role, unique_name, PRIVILEGES)
+
+  def _test_ranger_show_stmts_helper(self, unique_name, visibility_privileges):
     unique_db = unique_name + "_db"
     admin_client = self.create_impala_client()
     try:
       admin_client.execute("drop database if exists %s cascade" % unique_db, user=ADMIN)
       admin_client.execute("create database %s" % unique_db, user=ADMIN)
       for priv in PRIVILEGES:
+        admin_client.execute("create database db_%s_%s" % (unique_name, priv))
+        admin_client.execute("grant {0} on database db_{1}_{2} to user {3}"
+                             .format(priv, unique_name, priv, getuser()))
         admin_client.execute("create table %s.tbl_%s (i int)" % (unique_db, priv))
         admin_client.execute("grant {0} on table {1}.tbl_{2} to user {3}"
-                            .format(priv, unique_db, priv, getuser()))
+                             .format(priv, unique_db, priv, getuser()))
 
-      # Admin can still see all the tables
+      # Admin can still see all the databases and tables
+      result = admin_client.execute("show databases")
+      TestAuthorization._verify_show_dbs(result, unique_name)
       result = admin_client.execute("show tables in %s" % unique_db)
       assert result.data == ["tbl_%s" % p for p in PRIVILEGES]
 
-      # Check SHOW TABLES using another username
+      # Check SHOW DATABASES and SHOW TABLES using another username
+      result = self.client.execute("show databases")
+      TestAuthorization._verify_show_dbs(result, unique_name, visibility_privileges)
       result = self.client.execute("show tables in %s" % unique_db)
-      # Only show tables with privileges implying SELECT privilege
-      assert result.data == ['tbl_all', 'tbl_select']
+      # Only show tables with privileges implying any of the visibility privileges
+      assert 'tbl_all' in result.data   # ALL can imply to any privilege
+      for p in visibility_privileges:
+        assert 'tbl_%s' % p in result.data
     finally:
       admin_client.execute("drop database if exists %s cascade" % unique_db)
+      for priv in PRIVILEGES:
+        admin_client.execute(
+            "drop database if exists db_%s_%s cascade" % (unique_name, priv))
+
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args="--server-name=server1 --ranger_service_type=hive "
+                 "--ranger_app_id=impala --authorization_provider=ranger "
+                 "--min_privilege_set_for_show_stmts=select",
+    catalogd_args="--server-name=server1 --ranger_service_type=hive "
+                  "--ranger_app_id=impala --authorization_provider=ranger")
+  def test_ranger_show_stmts_with_select(self, unique_name):
+    self._test_ranger_show_stmts_helper(unique_name, ['select'])
+
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args="--server-name=server1 --ranger_service_type=hive "
+                 "--ranger_app_id=impala --authorization_provider=ranger "
+                 "--min_privilege_set_for_show_stmts=select,insert",
+    catalogd_args="--server-name=server1 --ranger_service_type=hive "
+                  "--ranger_app_id=impala --authorization_provider=ranger")
+  def test_ranger_show_stmts_with_select_insert(self, unique_name):
+    self._test_ranger_show_stmts_helper(unique_name, ['select', 'insert'])
+
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args="--server-name=server1 --ranger_service_type=hive "
+                 "--ranger_app_id=impala --authorization_provider=ranger "
+                 "--min_privilege_set_for_show_stmts=any",
+    catalogd_args="--server-name=server1 --ranger_service_type=hive "
+                  "--ranger_app_id=impala --authorization_provider=ranger")
+  def test_ranger_show_stmts_with_any(self, unique_name):
+    self._test_ranger_show_stmts_helper(unique_name, PRIVILEGES)