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 f23b6de6b [KYUUBI #5579][AUTHZ] Support LogicalRelation don't have 
CatalogTable but have  HadoopFsRelation
f23b6de6b is described below

commit f23b6de6b3751fc2592eb834107b7381cf7ce130
Author: Angerszhuuuu <[email protected]>
AuthorDate: Mon Nov 6 14:40:16 2023 +0800

    [KYUUBI #5579][AUTHZ] Support LogicalRelation don't have CatalogTable but 
have  HadoopFsRelation
    
    ### _Why are the changes needed?_
    To close #5579
    Support LogicalRelation don't have CatalogTable but have  HadoopFsRelation
    
    ### _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 #5581 from AngersZhuuuu/KYUUBI-5579.
    
    Closes #5579
    
    0298db505 [Angerszhuuuu] Update uriExtractors.scala
    05a9480bf [Angerszhuuuu] update
    5acc91928 [Angerszhuuuu] Update PrivilegesBuilder.scala
    77cc7f914 [Angerszhuuuu] update
    47b79c7be [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    96f2006d4 [Angerszhuuuu] Merge branch 'master' into KYUUBI-5579
    651f3f6f3 [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    8b5a650d5 [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    c37d655d2 [Angerszhuuuu] Merge branch 'master' into KYUUBI-5579
    a71f3a6c7 [Angerszhuuuu] update
    d4bb5b43d [Angerszhuuuu] Update RangerSparkExtensionSuite.scala
    6f634f404 [Angerszhuuuu] Merge branch 'master' into KYUUBI-5579
    33282e21d [Angerszhuuuu] [KYUUBI #5579][AUTHZ] Support LogicalRelation 
don't have CatalogTable but have  HadoopFsRelation
    
    Authored-by: Angerszhuuuu <[email protected]>
    Signed-off-by: Cheng Pan <[email protected]>
---
 ...he.kyuubi.plugin.spark.authz.serde.URIExtractor |  1 +
 .../src/main/resources/scan_command_spec.json      | 29 ++++++++++++-----
 .../plugin/spark/authz/PrivilegesBuilder.scala     | 10 +++++-
 .../plugin/spark/authz/serde/CommandSpec.scala     | 15 ++++++++-
 .../plugin/spark/authz/serde/uriExtractors.scala   | 10 ++++++
 .../kyuubi/plugin/spark/authz/gen/Scans.scala      |  3 +-
 .../authz/ranger/RangerSparkExtensionSuite.scala   | 36 ++++++++++++++++++++++
 7 files changed, 93 insertions(+), 11 deletions(-)

diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/resources/META-INF/services/org.apache.kyuubi.plugin.spark.authz.serde.URIExtractor
 
b/extensions/spark/kyuubi-spark-authz/src/main/resources/META-INF/services/org.apache.kyuubi.plugin.spark.authz.serde.URIExtractor
index f0038e75b..f5b1c6e6d 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/resources/META-INF/services/org.apache.kyuubi.plugin.spark.authz.serde.URIExtractor
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/resources/META-INF/services/org.apache.kyuubi.plugin.spark.authz.serde.URIExtractor
@@ -16,5 +16,6 @@
 #
 
 org.apache.kyuubi.plugin.spark.authz.serde.CatalogStorageFormatURIExtractor
+org.apache.kyuubi.plugin.spark.authz.serde.BaseRelationFileIndexURIExtractor
 org.apache.kyuubi.plugin.spark.authz.serde.OptionsUriExtractor
 org.apache.kyuubi.plugin.spark.authz.serde.StringURIExtractor
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/resources/scan_command_spec.json 
b/extensions/spark/kyuubi-spark-authz/src/main/resources/scan_command_spec.json
index 40a0d81c2..1fbcc9612 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/resources/scan_command_spec.json
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/resources/scan_command_spec.json
@@ -5,7 +5,8 @@
     "fieldExtractor" : "CatalogTableTableExtractor",
     "catalogDesc" : null
   } ],
-  "functionDescs" : [ ]
+  "functionDescs" : [ ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.catalyst.catalog.HiveTableRelation",
   "scanDescs" : [ {
@@ -13,7 +14,8 @@
     "fieldExtractor" : "CatalogTableTableExtractor",
     "catalogDesc" : null
   } ],
-  "functionDescs" : [ ]
+  "functionDescs" : [ ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.execution.datasources.LogicalRelation",
   "scanDescs" : [ {
@@ -21,7 +23,13 @@
     "fieldExtractor" : "CatalogTableOptionTableExtractor",
     "catalogDesc" : null
   } ],
-  "functionDescs" : [ ]
+  "functionDescs" : [ ],
+  "uriDescs" : [ {
+    "fieldName" : "relation",
+    "fieldExtractor" : "BaseRelationFileIndexURIExtractor",
+    "actionTypeDesc" : null,
+    "isInput" : false
+  } ]
 }, {
   "classname" : 
"org.apache.spark.sql.execution.datasources.v2.DataSourceV2Relation",
   "scanDescs" : [ {
@@ -29,7 +37,8 @@
     "fieldExtractor" : "DataSourceV2RelationTableExtractor",
     "catalogDesc" : null
   } ],
-  "functionDescs" : [ ]
+  "functionDescs" : [ ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.hive.HiveGenericUDF",
   "scanDescs" : [ ],
@@ -43,7 +52,8 @@
       "skipTypes" : [ "TEMP", "SYSTEM" ]
     },
     "isInput" : true
-  } ]
+  } ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.hive.HiveGenericUDTF",
   "scanDescs" : [ ],
@@ -57,7 +67,8 @@
       "skipTypes" : [ "TEMP", "SYSTEM" ]
     },
     "isInput" : true
-  } ]
+  } ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.hive.HiveSimpleUDF",
   "scanDescs" : [ ],
@@ -71,7 +82,8 @@
       "skipTypes" : [ "TEMP", "SYSTEM" ]
     },
     "isInput" : true
-  } ]
+  } ],
+  "uriDescs" : [ ]
 }, {
   "classname" : "org.apache.spark.sql.hive.HiveUDAFFunction",
   "scanDescs" : [ ],
@@ -85,5 +97,6 @@
       "skipTypes" : [ "TEMP", "SYSTEM" ]
     },
     "isInput" : true
-  } ]
+  } ],
+  "uriDescs" : [ ]
 } ]
\ No newline at end of file
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 3d872690f..b708b7f8b 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
@@ -113,7 +113,15 @@ object PrivilegesBuilder {
         buildQuery(a.child, privilegeObjects, projectionList, cols, spark)
 
       case scan if isKnownScan(scan) && scan.resolved =>
-        getScanSpec(scan).tables(scan, spark).foreach(mergeProjection(_, scan))
+        val tables = getScanSpec(scan).tables(scan, spark)
+        // If the the scan is table-based, we check privileges on the table we 
found
+        // otherwise, we check privileges on the uri we found
+        if (tables.nonEmpty) {
+          tables.foreach(mergeProjection(_, scan))
+        } else {
+          getScanSpec(scan).uris(scan).foreach(
+            privilegeObjects += PrivilegeObject(_, 
PrivilegeObjectActionType.OTHER))
+        }
 
       case u if u.nodeName == "UnresolvedRelation" =>
         val parts = invokeAs[String](u, "tableName").split("\\.")
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/CommandSpec.scala
 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/CommandSpec.scala
index 7b306551c..14f3719b8 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/CommandSpec.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/CommandSpec.scala
@@ -101,7 +101,8 @@ case class TableCommandSpec(
 case class ScanSpec(
     classname: String,
     scanDescs: Seq[ScanDesc],
-    functionDescs: Seq[FunctionDesc] = Seq.empty) extends CommandSpec {
+    functionDescs: Seq[FunctionDesc] = Seq.empty,
+    uriDescs: Seq[UriDesc] = Seq.empty) extends CommandSpec {
   override def opType: String = OperationType.QUERY.toString
   def tables: (LogicalPlan, SparkSession) => Seq[Table] = (plan, spark) => {
     scanDescs.flatMap { td =>
@@ -115,6 +116,18 @@ case class ScanSpec(
     }
   }
 
+  def uris: LogicalPlan => Seq[Uri] = plan => {
+    uriDescs.flatMap { ud =>
+      try {
+        ud.extract(plan)
+      } catch {
+        case e: Exception =>
+          LOG.debug(ud.error(plan, e))
+          None
+      }
+    }
+  }
+
   def functions: (Expression) => Seq[Function] = (expr) => {
     functionDescs.flatMap { fd =>
       try {
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala
 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala
index 418c5a0a0..3283c5019 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/main/scala/org/apache/kyuubi/plugin/spark/authz/serde/uriExtractors.scala
@@ -18,6 +18,7 @@
 package org.apache.kyuubi.plugin.spark.authz.serde
 
 import org.apache.spark.sql.catalyst.catalog.CatalogStorageFormat
+import org.apache.spark.sql.execution.datasources.HadoopFsRelation
 
 trait URIExtractor extends (AnyRef => Seq[Uri]) with Extractor
 
@@ -47,3 +48,12 @@ class OptionsUriExtractor extends URIExtractor {
     v1.asInstanceOf[Map[String, String]].get("path").map(Uri).toSeq
   }
 }
+
+class BaseRelationFileIndexURIExtractor extends URIExtractor {
+  override def apply(v1: AnyRef): Seq[Uri] = {
+    v1 match {
+      case h: HadoopFsRelation => h.location.rootPaths.map(_.toString).map(Uri)
+      case _ => Nil
+    }
+  }
+}
diff --git 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/Scans.scala
 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/Scans.scala
index 7771a2dd2..ed17dc5dc 100644
--- 
a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/Scans.scala
+++ 
b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/Scans.scala
@@ -37,7 +37,8 @@ object Scans extends CommandSpecs[ScanSpec] {
       ScanDesc(
         "catalogTable",
         classOf[CatalogTableOptionTableExtractor])
-    ScanSpec(r, Seq(tableDesc))
+    val uriDesc = UriDesc("relation", 
classOf[BaseRelationFileIndexURIExtractor])
+    ScanSpec(r, Seq(tableDesc), uriDescs = Seq(uriDesc))
   }
 
   val DataSourceV2Relation = {
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 3bb8379bc..e8e4486ac 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
@@ -1097,4 +1097,40 @@ class HiveCatalogRangerSparkExtensionSuite extends 
RangerSparkExtensionSuite {
       }
     }
   }
+
+  test("HadoopFsRelation") {
+    val db1 = defaultDb
+    val table1 = "table1"
+    withTempDir { path =>
+      withSingleCallEnabled {
+        withCleanTmpResources(Seq((s"$db1.$table1", "table"))) {
+          doAs(admin, sql(s"CREATE TABLE IF NOT EXISTS $db1.$table1 (id int, 
scope int)"))
+          doAs(
+            admin,
+            sql(
+              s"""
+                 |INSERT OVERWRITE DIRECTORY '$path'
+                 |USING parquet
+                 |SELECT * FROM $db1.$table1""".stripMargin))
+
+          interceptContains[AccessControlException](
+            doAs(
+              someone,
+              sql(
+                s"""
+                   |INSERT OVERWRITE DIRECTORY '$path'
+                   |USING parquet
+                   |SELECT * FROM $db1.$table1""".stripMargin)))(
+            s"does not have [select] privilege on 
[$db1/$table1/id,$db1/$table1/scope], " +
+              s"[update] privilege on [[$path, $path/]]")
+
+          doAs(admin, sql(s"SELECT * FROM 
parquet.`$path`".stripMargin).explain(true))
+          interceptContains[AccessControlException](
+            doAs(someone, sql(s"SELECT * FROM 
parquet.`$path`".stripMargin).explain(true)))(
+            s"does not have [select] privilege on " +
+              s"[[file:$path, file:$path/]]")
+        }
+      }
+    }
+  }
 }

Reply via email to