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

yao 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 754b57fdc [KYUUBI #5692][Bug] Authz not skip explain command
754b57fdc is described below

commit 754b57fdcea7647ad7856e07c9fcb979801d719c
Author: Angerszhuuuu <[email protected]>
AuthorDate: Mon Nov 20 10:33:51 2023 +0800

    [KYUUBI #5692][Bug] Authz not skip explain command
    
    ### _Why are the changes needed?_
    To close #5692
    
    Currently explain command still will check privilege of child logical plan.
    
    `EXPLAIN SELECT id FROM $db1.$table1`
    
    ```
    CommandResult [plan#15], Execute ExplainCommand, [[Error occurred during 
query planning: ], [Permission denied: user [someone] does not have [select] 
privilege on [default/table1/id]]]
       +- ExplainCommand 'Project ['id], SimpleMode
    ```
    
    In this pr, we skip the plan under same execution id of the explain command
    
    ### _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 #5693 from AngersZhuuuu/KYUUBI-5692.
    
    Closes #5692
    
    93e6eaa71 [Angerszhuuuu] update
    75a608719 [Angerszhuuuu] ODne
    c9cc8dc10 [Angerszhuuuu] fix ut
    0579bd3bf [Angerszhuuuu] follow comment
    127c28db1 [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    1353020eb [Angerszhuuuu] update
    c7c0c1424 [Angerszhuuuu] Merge branch 'master' into KYUUBI-5692
    b376964e6 [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    697173471 [Angerszhuuuu] [KYUUBI #5692][Bug] Authz not skip explain command
    
    Authored-by: Angerszhuuuu <[email protected]>
    Signed-off-by: Kent Yao <[email protected]>
---
 .../plugin/spark/authz/PrivilegesBuilder.scala     |  9 ++++++++-
 .../plugin/spark/authz/rule/Authorization.scala    | 21 +++++++++++++++++++++
 .../plugin/spark/authz/util/ReservedKeys.scala     |  1 +
 .../authz/ranger/RangerSparkExtensionSuite.scala   | 22 ++++++++++++++++++++++
 4 files changed, 52 insertions(+), 1 deletion(-)

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 df1738006..81dfa6e4e 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
@@ -22,11 +22,12 @@ import scala.collection.mutable.ArrayBuffer
 import org.apache.spark.sql.SparkSession
 import org.apache.spark.sql.catalyst.expressions.{Expression, NamedExpression}
 import org.apache.spark.sql.catalyst.plans.logical._
+import org.apache.spark.sql.execution.command.ExplainCommand
 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.Authorization._
 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._
@@ -302,6 +303,12 @@ object PrivilegesBuilder {
     val inputObjs = new ArrayBuffer[PrivilegeObject]
     val outputObjs = new ArrayBuffer[PrivilegeObject]
     val opType = plan match {
+      // ExplainCommand run will execute the plan, should avoid check 
privilege for the plan.
+      case _: ExplainCommand =>
+        setExplainCommandExecutionId(spark)
+        OperationType.EXPLAIN
+      case _ if isExplainCommandChild(spark) =>
+        OperationType.EXPLAIN
       // RunnableCommand
       case cmd: Command => buildCommand(cmd, inputObjs, outputObjs, spark)
       // Queries
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 6c7d0afa6..d83541825 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
@@ -21,9 +21,11 @@ import org.apache.spark.sql.SparkSession
 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
+import org.apache.spark.sql.execution.SQLExecution.EXECUTION_ID_KEY
 
 import org.apache.kyuubi.plugin.spark.authz.rule.Authorization._
 import 
org.apache.kyuubi.plugin.spark.authz.rule.permanentview.PermanentViewMarker
+import org.apache.kyuubi.plugin.spark.authz.util.ReservedKeys._
 
 abstract class Authorization(spark: SparkSession) extends Rule[LogicalPlan] {
   override def apply(plan: LogicalPlan): LogicalPlan = {
@@ -65,4 +67,23 @@ object Authorization {
       case p => p.getTagValue(KYUUBI_AUTHZ_TAG).nonEmpty
     }
   }
+
+  def setExplainCommandExecutionId(sparkSession: SparkSession): Unit = {
+    sparkSession.sparkContext.setLocalProperty(
+      KYUUBI_EXPLAIN_COMMAND_EXECUTION_ID,
+      executionId(sparkSession))
+  }
+
+  def isExplainCommandChild(sparkSession: SparkSession): Boolean = {
+    if (null == executionId(sparkSession)) {
+      false
+    } else {
+      executionId(sparkSession).equals(
+        
sparkSession.sparkContext.getLocalProperty(KYUUBI_EXPLAIN_COMMAND_EXECUTION_ID))
+    }
+  }
+
+  private def executionId(sparkSession: SparkSession): String = {
+    sparkSession.sparkContext.getLocalProperty(EXECUTION_ID_KEY)
+  }
 }
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/util/ReservedKeys.scala
 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/util/ReservedKeys.scala
index 60d989845..81259be2a 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/util/ReservedKeys.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/util/ReservedKeys.scala
@@ -22,4 +22,5 @@ object ReservedKeys {
   final val KYUUBI_SESSION_USER = "kyuubi.session.user"
   final val KYUUBI_SESSION_SIGN_PUBLICKEY = "kyuubi.session.sign.publickey"
   final val KYUUBI_SESSION_USER_SIGN = "kyuubi.session.user.sign"
+  final var KYUUBI_EXPLAIN_COMMAND_EXECUTION_ID = 
"kyuubi.authz.command.explain.executionid"
 }
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 d3a10cf9a..a48b35a50 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
@@ -1340,4 +1340,26 @@ class HiveCatalogRangerSparkExtensionSuite extends 
RangerSparkExtensionSuite {
       }
     }
   }
+
+  test("[KYUUBI #5692][Bug] Authz not skip explain command") {
+    val db1 = defaultDb
+    val table1 = "table1"
+    withSingleCallEnabled {
+      withCleanTmpResources(Seq((s"$db1.$table1", "table"))) {
+        doAs(admin, sql(s"CREATE TABLE IF NOT EXISTS $db1.$table1 (id int, 
scope int)"))
+        val explainSql =
+          s"""
+             |EXPLAIN
+             |SELECT id FROM $db1.$table1
+             |""".stripMargin
+        doAs(admin, sql(explainSql))
+        val result = doAs(someone, sql(explainSql).collect()).head.getString(0)
+        assert(!result.contains("Error occurred during query planning"))
+        assert(!result.contains(s"does not have [select] privilege on 
[$db1/$table1/id]"))
+        interceptContains[AccessControlException](
+          doAs(someone, sql(s"SELECT id FROM $db1.$table1").collect()))(
+          s"does not have [select] privilege on [$db1/$table1/id]")
+      }
+    }
+  }
 }

Reply via email to