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

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


The following commit(s) were added to refs/heads/master by this push:
     new 9be2a9c50 [KYUUBI #5503][FOLLOWUP][AUTHZ] Authz should skip inner plan 
that have been verified
9be2a9c50 is described below

commit 9be2a9c508882d81d99e736a814bce457f2082b5
Author: Angerszhuuuu <[email protected]>
AuthorDate: Tue Oct 31 16:35:31 2023 +0800

    [KYUUBI #5503][FOLLOWUP][AUTHZ] Authz should skip inner plan that have been 
verified
    
    ### _Why are the changes needed?_
    To close #5503
    For sql such as lateral join in test `[KYUUBI #5503][AUTHZ] Check plan auth 
checked should not set tag to all child nodes`, it will first verify subquery 
in `lateral` then verify whole plan, if there is a view, when verify the whole 
plan, the `PermanentViewMarker` will be remove by spark's optimizer.
    Then it will verify both source table `table1` and `table2`.
    So I think we need to do 3 things:
    
    1. Mark all PermanentViewMarker's children's all nodes as checked and 
Subquery's all child marks as checked.
    2. `isAuthChecked` should only check the first level of the plan to avoid 
skipping the check of the whole plan in the demo test
    3. in `buildQuery`, if the current node has the tag, we just skip it.
    
    Without this pr, the SQL in test will both check `table1` and `table2`
    
    ### _How was this patch tested?_
    - [x] Add some test cases that check the changes thoroughly including 
negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [ ] [Run 
test](https://kyuubi.readthedocs.io/en/master/contributing/code/testing.html#running-tests)
 locally before make a pull request
    
    ### _Was this patch authored or co-authored using generative AI tooling?_
    No
    
    Closes #5563 from AngersZhuuuu/KYUUBI-5503-FOLLOWUP.
    
    Closes #5503
    
    c1a427f58 [Angerszhuuuu] Update Authorization.scala
    d6b2899db [Angerszhuuuu] update
    633bc91e0 [Angerszhuuuu] Update Authorization.scala
    7a006b136 [Angerszhuuuu] [KYUUBI #5503][FOLLOWUP][AUTHZ] Authz should skip 
inner plan that have been verified
    
    Authored-by: Angerszhuuuu <[email protected]>
    Signed-off-by: Cheng Pan <[email protected]>
---
 .../plugin/spark/authz/PrivilegesBuilder.scala     |  3 +
 .../plugin/spark/authz/rule/Authorization.scala    | 29 ++++----
 .../spark/authz/gen/PolicyJsonFileGenerator.scala  | 13 ++++
 .../src/test/resources/sparkSql_hive_jenkins.json  | 77 ++++++++++++++++++----
 .../plugin/spark/authz/RangerTestResources.scala   |  1 +
 .../authz/ranger/RangerSparkExtensionSuite.scala   | 42 +++++++++++-
 6 files changed, 137 insertions(+), 28 deletions(-)

diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/PrivilegesBuilder.scala
 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/PrivilegesBuilder.scala
index 07ed71011..833499280 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/PrivilegesBuilder.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/PrivilegesBuilder.scala
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory
 
 import org.apache.kyuubi.plugin.spark.authz.OperationType.OperationType
 import org.apache.kyuubi.plugin.spark.authz.PrivilegeObjectActionType._
+import org.apache.kyuubi.plugin.spark.authz.rule.Authorization.KYUUBI_AUTHZ_TAG
 import 
org.apache.kyuubi.plugin.spark.authz.rule.permanentview.PermanentViewMarker
 import org.apache.kyuubi.plugin.spark.authz.serde._
 import org.apache.kyuubi.plugin.spark.authz.util.AuthZUtils._
@@ -80,6 +81,8 @@ object PrivilegesBuilder {
     }
 
     plan match {
+      case p if p.getTagValue(KYUUBI_AUTHZ_TAG).nonEmpty =>
+
       case p: Project => buildQuery(p.child, privilegeObjects, p.projectList, 
conditionList, spark)
 
       case j: Join =>
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/rule/Authorization.scala
 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/rule/Authorization.scala
index db50873b3..6c7d0afa6 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/rule/Authorization.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/rule/Authorization.scala
@@ -18,7 +18,7 @@
 package org.apache.kyuubi.plugin.spark.authz.rule
 
 import org.apache.spark.sql.SparkSession
-import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
+import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, Subquery}
 import org.apache.spark.sql.catalyst.rules.Rule
 import org.apache.spark.sql.catalyst.trees.TreeNodeTag
 
@@ -42,20 +42,27 @@ object Authorization {
 
   val KYUUBI_AUTHZ_TAG = TreeNodeTag[Unit]("__KYUUBI_AUTHZ_TAG")
 
+  private def markAllNodesAuthChecked(plan: LogicalPlan): LogicalPlan = {
+    plan.transformDown { case p =>
+      p.setTagValue(KYUUBI_AUTHZ_TAG, ())
+      p
+    }
+  }
+
   protected def markAuthChecked(plan: LogicalPlan): LogicalPlan = {
-    plan match {
-      case _: PermanentViewMarker =>
-        plan.transformUp { case p =>
-          p.setTagValue(KYUUBI_AUTHZ_TAG, ())
-          p
-        }
-      case _ =>
-        plan.setTagValue(KYUUBI_AUTHZ_TAG, ())
+    plan.setTagValue(KYUUBI_AUTHZ_TAG, ())
+    plan transformDown {
+      case pvm: PermanentViewMarker =>
+        markAllNodesAuthChecked(pvm)
+      case subquery: Subquery =>
+        markAllNodesAuthChecked(subquery)
     }
-    plan
   }
 
   protected def isAuthChecked(plan: LogicalPlan): Boolean = {
-    plan.find(_.getTagValue(KYUUBI_AUTHZ_TAG).nonEmpty).nonEmpty
+    plan match {
+      case subquery: Subquery => isAuthChecked(subquery.child)
+      case p => p.getTagValue(KYUUBI_AUTHZ_TAG).nonEmpty
+    }
   }
 }
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/test/gen/scala/org/apache/kyuubi/plugin/spark/authz/gen/PolicyJsonFileGenerator.scala
 
b/extensions/spark/kyuubi-spark-authz/src/test/gen/scala/org/apache/kyuubi/plugin/spark/authz/gen/PolicyJsonFileGenerator.scala
index 7faddd0c7..7996c8ecc 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/test/gen/scala/org/apache/kyuubi/plugin/spark/authz/gen/PolicyJsonFileGenerator.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/test/gen/scala/org/apache/kyuubi/plugin/spark/authz/gen/PolicyJsonFileGenerator.scala
@@ -108,6 +108,7 @@ class PolicyJsonFileGenerator extends AnyFunSuite {
       policyAccessForDefaultBobUse,
       policyAccessForDefaultBobSelect,
       policyAccessForPermViewAccessOnly,
+      policyAccessForTable2AccessOnly,
       // row filter
       policyFilterForSrcTableKeyLessThan20,
       policyFilterForPermViewKeyLessThan20,
@@ -345,4 +346,16 @@ class PolicyJsonFileGenerator extends AnyFunSuite {
         users = List(permViewOnlyUser),
         accesses = allowTypes(select),
         delegateAdmin = true)))
+
+  private val policyAccessForTable2AccessOnly = KRangerPolicy(
+    name = "someone_access_table2",
+    resources = Map(
+      databaseRes(defaultDb),
+      tableRes("table2"),
+      allColumnRes),
+    policyItems = List(
+      KRangerPolicyItem(
+        users = List(table2OnlyUser),
+        accesses = allowTypes(select),
+        delegateAdmin = true)))
 }
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/test/resources/sparkSql_hive_jenkins.json
 
b/extensions/spark/kyuubi-spark-authz/src/test/resources/sparkSql_hive_jenkins.json
index 6c160d321..76d8c788a 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/test/resources/sparkSql_hive_jenkins.json
+++ 
b/extensions/spark/kyuubi-spark-authz/src/test/resources/sparkSql_hive_jenkins.json
@@ -544,6 +544,55 @@
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
+    "name" : "someone_access_table2",
+    "policyType" : 0,
+    "policyPriority" : 0,
+    "description" : "",
+    "isAuditEnabled" : true,
+    "resources" : {
+      "database" : {
+        "values" : [ "default" ],
+        "isExcludes" : false,
+        "isRecursive" : false
+      },
+      "column" : {
+        "values" : [ "*" ],
+        "isExcludes" : false,
+        "isRecursive" : false
+      },
+      "table" : {
+        "values" : [ "table2" ],
+        "isExcludes" : false,
+        "isRecursive" : false
+      }
+    },
+    "conditions" : [ ],
+    "policyItems" : [ {
+      "accesses" : [ {
+        "type" : "select",
+        "isAllowed" : true
+      } ],
+      "users" : [ "user_table2_only" ],
+      "groups" : [ ],
+      "roles" : [ ],
+      "conditions" : [ ],
+      "delegateAdmin" : true
+    } ],
+    "denyPolicyItems" : [ ],
+    "allowExceptions" : [ ],
+    "denyExceptions" : [ ],
+    "dataMaskPolicyItems" : [ ],
+    "rowFilterPolicyItems" : [ ],
+    "options" : { },
+    "validitySchedules" : [ ],
+    "policyLabels" : [ ],
+    "isDenyAllElse" : false
+  }, {
+    "id" : 9,
+    "guid" : "45c48cce-2e2d-3fbd-aa1a-fc51c7c6ad26",
+    "isEnabled" : true,
+    "version" : 1,
+    "service" : "hive_jenkins",
     "name" : "src_key_less_than_20",
     "policyType" : 2,
     "policyPriority" : 0,
@@ -586,8 +635,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 9,
-    "guid" : "45c48cce-2e2d-3fbd-aa1a-fc51c7c6ad26",
+    "id" : 10,
+    "guid" : "d3d94468-02a4-3259-b55d-38e6d163e820",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -633,8 +682,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 10,
-    "guid" : "d3d94468-02a4-3259-b55d-38e6d163e820",
+    "id" : 11,
+    "guid" : "6512bd43-d9ca-36e0-ac99-0b0a82652dca",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -685,8 +734,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 11,
-    "guid" : "6512bd43-d9ca-36e0-ac99-0b0a82652dca",
+    "id" : 12,
+    "guid" : "c20ad4d7-6fe9-3759-aa27-a0c99bff6710",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -737,8 +786,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 12,
-    "guid" : "c20ad4d7-6fe9-3759-aa27-a0c99bff6710",
+    "id" : 13,
+    "guid" : "c51ce410-c124-310e-8db5-e4b97fc2af39",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -789,8 +838,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 13,
-    "guid" : "c51ce410-c124-310e-8db5-e4b97fc2af39",
+    "id" : 14,
+    "guid" : "aab32389-22bc-325a-af60-6eb525ffdc56",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -841,8 +890,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 14,
-    "guid" : "aab32389-22bc-325a-af60-6eb525ffdc56",
+    "id" : 15,
+    "guid" : "9bf31c7f-f062-336a-96d3-c8bd1f8f2ff3",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
@@ -893,8 +942,8 @@
     "policyLabels" : [ ],
     "isDenyAllElse" : false
   }, {
-    "id" : 15,
-    "guid" : "9bf31c7f-f062-336a-96d3-c8bd1f8f2ff3",
+    "id" : 16,
+    "guid" : "c74d97b0-1eae-357e-84aa-9d5bade97baf",
     "isEnabled" : true,
     "version" : 1,
     "service" : "hive_jenkins",
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/RangerTestResources.scala
 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/RangerTestResources.scala
index 468c2c50b..4f870d504 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/RangerTestResources.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/RangerTestResources.scala
@@ -28,6 +28,7 @@ object RangerTestUsers {
   val createOnlyUser = "create_only_user"
   val defaultTableOwner = "default_table_owner"
   val permViewOnlyUser = "user_perm_view_only"
+  val table2OnlyUser = "user_table2_only"
 
   // non-authorized users
   val invisibleUser = "i_am_invisible"
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/RangerSparkExtensionSuite.scala
 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/RangerSparkExtensionSuite.scala
index 672d7208f..d3f190687 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/RangerSparkExtensionSuite.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/RangerSparkExtensionSuite.scala
@@ -957,12 +957,17 @@ class HiveCatalogRangerSparkExtensionSuite extends 
RangerSparkExtensionSuite {
     assume(isSparkV32OrGreater, "Spark 3.1 not support lateral subquery.")
     val db1 = defaultDb
     val table1 = "table1"
+    val table2 = "table2"
     val perm_view = "perm_view"
     withSingleCallEnabled {
       withCleanTmpResources(
-        Seq((s"$db1.$table1", "table"), (s"$db1.$perm_view", "view"))) {
+        Seq(
+          (s"$db1.$table1", "table"),
+          (s"$db1.$table2", "table"),
+          (s"$db1.$perm_view", "view"))) {
         doAs(admin, sql(s"CREATE TABLE IF NOT EXISTS $db1.$table1 (id int, 
scope int)"))
-        doAs(admin, sql(s"CREATE VIEW $db1.$perm_view AS SELECT * FROM 
$db1.$table1"))
+        doAs(admin, sql(s"CREATE TABLE IF NOT EXISTS $db1.$table2 (id int, 
scope int)"))
+        doAs(admin, sql(s"CREATE VIEW $db1.$perm_view AS SELECT * FROM 
$db1.$table2"))
         interceptContains[AccessControlException](
           doAs(
             someone,
@@ -992,7 +997,38 @@ class HiveCatalogRangerSparkExtensionSuite extends 
RangerSparkExtensionSuite {
                  |)
                  |""".stripMargin).show()))(
           s"does not have [select] privilege on " +
-            s"[$db1/$table1/id,$db1/$table1/scope]")
+            s"[$db1/$table1/id]")
+
+        interceptContains[AccessControlException](
+          doAs(
+            someone,
+            sql(
+              s"""
+                 |SELECT t1.id
+                 |FROM $db1.$table1 t1,
+                 |LATERAL (
+                 |  SELECT *
+                 |  FROM $db1.$table2 t2
+                 |  WHERE t1.id = t2.id
+                 |)
+                 |""".stripMargin).show()))(
+          s"does not have [select] privilege on " +
+            s"[$db1/$table2/id,$db1/$table2/scope]")
+        interceptContains[AccessControlException](
+          doAs(
+            table2OnlyUser,
+            sql(
+              s"""
+                 |SELECT t1.id
+                 |FROM $db1.$table1 t1,
+                 |LATERAL (
+                 |  SELECT *
+                 |  FROM $db1.$table2 t2
+                 |  WHERE t1.id = t2.id
+                 |)
+                 |""".stripMargin).show()))(
+          s"does not have [select] privilege on " +
+            s"[$db1/$table1/id]")
       }
     }
   }

Reply via email to