You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2019/04/16 20:24:53 UTC

[impala] 02/05: IMPALA-6718: Add support for column-level permissions on views

This is an automated email from the ASF dual-hosted git repository.

tarmstrong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git

commit 53798b0454332df44efce0032a88ef49e770a095
Author: Fredy Wijaya <fw...@cloudera.com>
AuthorDate: Mon Apr 8 14:08:38 2019 -0700

    IMPALA-6718: Add support for column-level permissions on views
    
    This patch adds support for column-level permissions on views. This
    behavior is compatible with Hive column-level permissons on views. The
    following statements are now supported.
    
    GRANT select(col) ON db.my_view TO ROLE my_role -- Sentry only
    REVOKE select(col) ON db.my_view FROM ROLE my_role -- Sentry only
    
    GRANT select(col) ON db.my_view TO USER my_user -- Ranger only
    REVOKE select(col) ON db.my_view FROM USER my_user -- Ranger only
    
    GRANT select(col) ON db.my_view TO GROUP my_group -- Ranger only
    REVOKE select(col) ON db.my_view FROM GROUP my_group -- Ranger only
    
    Testing:
    - Updated AuthorizationStmtTest to with new test cases
    - Ran all FE tests
    - Ran all E2E authorization tests
    
    Change-Id: If81e683212cba22cc0fa5fc091ec3c799fa33e14
    Reviewed-on: http://gerrit.cloudera.org:8080/12959
    Reviewed-by: Impala Public Jenkins <im...@cloudera.com>
    Tested-by: Impala Public Jenkins <im...@cloudera.com>
---
 .../org/apache/impala/analysis/PrivilegeSpec.java  |  4 --
 .../org/apache/impala/analysis/SelectStmt.java     | 50 +++++++++++++++++++++
 .../impala/analysis/AnalyzeAuthStmtsTest.java      |  7 ++-
 .../impala/analysis/AuthorizationStmtTest.java     | 51 ++++++++++++----------
 4 files changed, 82 insertions(+), 30 deletions(-)

diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
index 9dd4168..e03c850 100644
--- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
+++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java
@@ -245,10 +245,6 @@ public class PrivilegeSpec extends StmtNode {
           "in a column privilege spec.");
     }
     FeTable table = analyzeTargetTable(analyzer);
-    if (table instanceof FeView) {
-      throw new AnalysisException("Column-level privileges on views are not " +
-          "supported.");
-    }
     if (table instanceof FeDataSourceTable) {
       throw new AnalysisException("Column-level privileges on external data " +
           "source tables are not supported.");
diff --git a/fe/src/main/java/org/apache/impala/analysis/SelectStmt.java b/fe/src/main/java/org/apache/impala/analysis/SelectStmt.java
index 4cd1db0..580929e 100644
--- a/fe/src/main/java/org/apache/impala/analysis/SelectStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/SelectStmt.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.impala.analysis.Path.PathType;
+import org.apache.impala.authorization.Privilege;
 import org.apache.impala.catalog.Column;
 import org.apache.impala.catalog.FeTable;
 import org.apache.impala.catalog.FeView;
@@ -208,6 +209,7 @@ public class SelectStmt extends QueryStmt {
 
       analyzeSelectClause();
       verifyResultExprs();
+      registerViewColumnPrivileges();
       analyzeWhereClause();
       createSortInfo(analyzer_);
 
@@ -538,6 +540,54 @@ public class SelectStmt extends QueryStmt {
     }
 
     /**
+     * Registers view column privileges only when the view a catalog view.
+     */
+    private void registerViewColumnPrivileges() {
+      for (TableRef tableRef: fromClause_.getTableRefs()) {
+        if (!(tableRef instanceof InlineViewRef)) continue;
+        InlineViewRef inlineViewRef = (InlineViewRef) tableRef;
+        FeView view = inlineViewRef.getView();
+        // For, local views (CTE), the view definition is explicitly defined in the query,
+        // this requires registering base column privileges instead of view column
+        // privileges. For example:
+        //
+        // with v as (select id as foo from functional.alltypes) select foo from v
+        //
+        // The query will register "functional.alltypes.id" column instead of
+        // "v.foo" column. This behavior is similar to inline views, e.g.
+        //
+        // select foo from (select id as foo from functional.alltypes) v
+        //
+        // The query will register "functional.alltypes.id" column instead of "v.foo"
+        // column.
+        //
+        // Contrasting this with catalog views.
+        //
+        // create view v(foo) as select id from functional.alltypes
+        // select v.foo from v
+        //
+        // The "select v.foo from v" query requires "v.foo" view column privilege because
+        // the "v" view definition is not exposed in the query. This behavior is also
+        // consistent with view access, such that the query requires a "select" privilege
+        // on "v" view and not "functional.alltypes" table.
+        boolean isCatalogView = view != null && !view.isLocalView();
+        if (!isCatalogView) continue;
+        for (Expr expr: getResultExprs()) {
+          List<Expr> slotRefs = new ArrayList<>();
+          expr.collectAll(Predicates.instanceOf(SlotRef.class), slotRefs);
+          for (Expr e: slotRefs) {
+            SlotRef slotRef = (SlotRef) e;
+            analyzer_.registerPrivReq(builder -> builder
+                .allOf(Privilege.SELECT)
+                .onColumn(view.getDb().getName(), view.getName(),
+                    slotRef.getDesc().getLabel())
+                .build());
+          }
+        }
+      }
+    }
+
+    /**
      * Analyze the HAVING clause. The HAVING clause is a predicate, not a list
      * (like GROUP BY or ORDER BY) and so cannot contain ordinals.
      *
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
index 1ff7033..8c44de7 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java
@@ -233,6 +233,9 @@ public class AnalyzeAuthStmtsTest extends FrontendTestBase {
             "alltypes %s %s", formatArgs), createAnalysisCtx("functional"));
         AnalyzesOk(String.format("%s SELECT (id, bool_col) ON TABLE " +
             "functional_kudu.alltypessmall %s %s", formatArgs));
+        // Column-level privileges on a VIEW
+        AnalyzesOk(String.format("%s SELECT (id, bool_col) ON TABLE " +
+            "functional.alltypes_hive_view %s %s", formatArgs));
         // Empty column list
         AnalysisError(String.format("%s SELECT () ON TABLE functional.alltypes " +
             "%s %s", formatArgs), "Empty column list in column privilege spec.");
@@ -243,10 +246,6 @@ public class AnalyzeAuthStmtsTest extends FrontendTestBase {
         AnalysisError(String.format("%s ALL (id, tinyint_col) ON TABLE " +
             "functional.alltypes %s %s", formatArgs), "Only 'SELECT' privileges " +
             "are allowed in a column privilege spec.");
-        // Column-level privileges on a VIEW
-        AnalysisError(String.format("%s SELECT (id, bool_col) ON TABLE " +
-            "functional.alltypes_hive_view %s %s", formatArgs), "Column-level " +
-            "privileges on views are not supported.");
         // Columns/table that don't exist
         AnalysisError(String.format("%s SELECT (invalid_col) ON TABLE " +
             "functional.alltypes %s %s", formatArgs), "Error setting column-level " +
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
index feb14f5..4fdfc92 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
@@ -544,26 +544,30 @@ public class AuthorizationStmtTest extends FrontendTestBase {
 
 
     // Select a specific column on a view.
-    // Column-level privileges on views are not currently supported.
-    authorize("select id from functional.alltypes_view")
-        .ok(onServer(TPrivilegeLevel.ALL))
-        .ok(onServer(TPrivilegeLevel.OWNER))
-        .ok(onServer(TPrivilegeLevel.SELECT))
-        .ok(onDatabase("functional", TPrivilegeLevel.ALL))
-        .ok(onDatabase("functional", TPrivilegeLevel.OWNER))
-        .ok(onDatabase("functional", TPrivilegeLevel.SELECT))
-        .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.ALL))
-        .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.OWNER))
-        .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT))
-        .error(selectError("functional.alltypes_view"))
-        .error(selectError("functional.alltypes_view"), onServer(allExcept(
-            TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER, TPrivilegeLevel.SELECT)))
-        .error(selectError("functional.alltypes_view"), onDatabase("functional",
-            allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER,
-            TPrivilegeLevel.SELECT)))
-        .error(selectError("functional.alltypes_view"), onTable("functional",
-            "alltypes_view", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER,
-            TPrivilegeLevel.SELECT)));
+    for (AuthzTest test: new AuthzTest[]{
+        authorize("select id from functional.alltypes_view"),
+        authorize("select 2 * v.id from functional.alltypes_view v"),
+        authorize("select cast(id as bigint) from functional.alltypes_view")}) {
+      test.ok(onServer(TPrivilegeLevel.ALL))
+          .ok(onServer(TPrivilegeLevel.OWNER))
+          .ok(onServer(TPrivilegeLevel.SELECT))
+          .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+          .ok(onDatabase("functional", TPrivilegeLevel.OWNER))
+          .ok(onDatabase("functional", TPrivilegeLevel.SELECT))
+          .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.ALL))
+          .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.OWNER))
+          .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT))
+          .ok(onColumn("functional", "alltypes_view", "id", TPrivilegeLevel.SELECT))
+          .error(selectError("functional.alltypes_view"))
+          .error(selectError("functional.alltypes_view"), onServer(allExcept(
+              TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER, TPrivilegeLevel.SELECT)))
+          .error(selectError("functional.alltypes_view"), onDatabase("functional",
+              allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER,
+                  TPrivilegeLevel.SELECT)))
+          .error(selectError("functional.alltypes_view"), onTable("functional",
+              "alltypes_view", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER,
+                  TPrivilegeLevel.SELECT)));
+    }
 
     // Constant select.
     authorize("select 1").ok();
@@ -795,7 +799,6 @@ public class AuthorizationStmtTest extends FrontendTestBase {
     }
 
     // Union on views.
-    // Column-level privileges on views are not currently supported.
     authorize("select id from functional.alltypes_view union all " +
         "select x from functional.alltypes_view_sub")
         .ok(onServer(TPrivilegeLevel.ALL))
@@ -810,6 +813,8 @@ public class AuthorizationStmtTest extends FrontendTestBase {
             onTable("functional", "alltypes_view_sub", TPrivilegeLevel.OWNER))
         .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT),
             onTable("functional", "alltypes_view_sub", TPrivilegeLevel.SELECT))
+        .ok(onColumn("functional", "alltypes_view", "id", TPrivilegeLevel.SELECT),
+            onColumn("functional", "alltypes_view_sub", "x", TPrivilegeLevel.SELECT))
         .error(selectError("functional.alltypes_view"))
         .error(selectError("functional.alltypes_view"), onServer(allExcept(
             TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER, TPrivilegeLevel.SELECT)))
@@ -902,7 +907,6 @@ public class AuthorizationStmtTest extends FrontendTestBase {
     }
 
     // Insert with select on a target view.
-    // Column-level privileges on views are not currently supported.
     authorize("insert into functional.alltypes partition(month, year) " +
         "select * from functional.alltypes_view where id < 100")
         .ok(onServer(TPrivilegeLevel.ALL))
@@ -917,6 +921,9 @@ public class AuthorizationStmtTest extends FrontendTestBase {
             onTable("functional", "alltypes_view", TPrivilegeLevel.OWNER))
         .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
             onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT))
+        .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+            onColumn("functional", "alltypes_view", ALLTYPES_COLUMNS,
+                TPrivilegeLevel.SELECT))
         .error(selectError("functional.alltypes_view"))
         .error(selectError("functional.alltypes_view"), onServer(allExcept(
             TPrivilegeLevel.ALL, TPrivilegeLevel.OWNER, TPrivilegeLevel.INSERT,