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

liyang-kylin pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git

commit 02be60a135261de2c2e827102a91d67bd4ad5ebf
Author: Li Yang <[email protected]>
AuthorDate: Fri Oct 2 15:10:53 2026 +0800

    KYLIN-6109 improve table metadata authorization
---
 .../kylin/rest/service/SparkSourceService.java      | 18 +++++++++---------
 .../kylin/rest/service/SparkSourceServiceTest.java  | 19 +++++++++++++++++++
 .../engine/spark/source/NSparkMetadataExplorer.java | 11 +++++------
 .../spark/source/NSparkMetadataExplorerTest.java    | 21 +++++++++++++++++++++
 4 files changed, 54 insertions(+), 15 deletions(-)

diff --git 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/SparkSourceService.java
 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/SparkSourceService.java
index d5287aa2cf..be842c89e4 100644
--- 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/SparkSourceService.java
+++ 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/SparkSourceService.java
@@ -44,6 +44,7 @@ import org.apache.kylin.rest.request.DDLRequest;
 import org.apache.kylin.rest.response.DDLResponse;
 import org.apache.kylin.rest.response.ExportTablesResponse;
 import org.apache.kylin.rest.response.TableNameResponse;
+import org.apache.kylin.rest.source.DataSourceState;
 import org.apache.kylin.rest.util.AclEvaluate;
 import org.apache.kylin.source.ISourceMetadataExplorer;
 import org.apache.kylin.source.SourceFactory;
@@ -55,7 +56,6 @@ import org.apache.spark.sql.SaveMode;
 import org.apache.spark.sql.SparderEnv;
 import org.apache.spark.sql.SparkSession;
 import org.apache.spark.sql.catalog.Database;
-import org.apache.spark.sql.catalog.Table;
 import org.apache.spark.sql.catalyst.TableIdentifier;
 import org.apache.spark.sql.catalyst.catalog.CatalogTable;
 import org.apache.spark.sql.delta.DeltaTableUtils;
@@ -146,15 +146,15 @@ public class SparkSourceService extends BasicService {
     }
 
     public List<TableNameResponse> listTables(String db, String project) 
throws Exception {
-        if (Strings.isNullOrEmpty(project)) {
-            SparkSession sparkSession = SparderEnv.getSparkSession();
-            Dataset<Table> tableDataset = 
sparkSession.catalog().listTables(db);
-            List<Table> sparkTables = tableDataset.collectAsList();
-            return sparkTables.stream()
-                    .map(table -> new 
TableNameResponse(table.name().toUpperCase(Locale.ROOT), false))
-                    .collect(Collectors.toList());
+        aclEvaluate.checkProjectReadPermission(project);
+        val projectInstance = 
getManager(NProjectManager.class).getProject(project);
+        List<String> hiveDatabases = 
DataSourceState.getInstance().getHiveFilterList(projectInstance);
+        if (!hiveDatabases.isEmpty()
+                && (Strings.isNullOrEmpty(db) || 
!hiveDatabases.contains(db.toUpperCase(Locale.ROOT)))) {
+            throw new KylinException(ServerErrorCode.PERMISSION_DENIED,
+                    MsgPicker.getMsg().getAclPermissionRequired());
         }
-        ISourceMetadataExplorer explr = 
SourceFactory.getSource(getManager(NProjectManager.class).getProject(project))
+        ISourceMetadataExplorer explr = 
SourceFactory.getSource(projectInstance)
                 .getSourceMetadataExplorer();
         List<String> tables = explr.listTables(db).stream().map(str -> 
str.toUpperCase(Locale.ROOT))
                 .collect(Collectors.toList());
diff --git 
a/src/datasource-service/src/test/java/org/apache/kylin/rest/service/SparkSourceServiceTest.java
 
b/src/datasource-service/src/test/java/org/apache/kylin/rest/service/SparkSourceServiceTest.java
index e31dc52f17..1ebbed8c3b 100644
--- 
a/src/datasource-service/src/test/java/org/apache/kylin/rest/service/SparkSourceServiceTest.java
+++ 
b/src/datasource-service/src/test/java/org/apache/kylin/rest/service/SparkSourceServiceTest.java
@@ -195,6 +195,25 @@ public class SparkSourceServiceTest extends 
NLocalFileMetadataTestCase {
     @Test
     public void testListTables() throws Exception {
         Assert.assertEquals(11, sparkSourceService.listTables("DEFAULT", 
"default").size());
+        Mockito.verify(aclEvaluate).checkProjectReadPermission("default");
+    }
+
+    @Test
+    public void testListTablesWithProjectReadPermissionDenied() {
+        Mockito.doThrow(new AccessDeniedException("Access is 
denied")).when(aclEvaluate)
+                .checkProjectReadPermission("default");
+        Assert.assertThrows(AccessDeniedException.class, () -> 
sparkSourceService.listTables("DEFAULT", "default"));
+    }
+
+    @Test
+    public void testListTablesOutsideProjectScope() {
+        ProjectInstance projectInstance = projectManager.getProject("default");
+        LinkedHashMap<String, String> overrideKylinProps = 
projectInstance.getOverrideKylinProps();
+        overrideKylinProps.put("kylin.source.hive.databases", "SSB");
+        projectManager.updateProject(projectInstance, 
projectInstance.getName(), projectInstance.getDescription(),
+                overrideKylinProps);
+
+        Assert.assertThrows(KylinException.class, () -> 
sparkSourceService.listTables("DEFAULT", "default"));
     }
 
     @Test
diff --git 
a/src/spark-project/engine-spark/src/main/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorer.java
 
b/src/spark-project/engine-spark/src/main/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorer.java
index 25271a3a61..69207d6874 100644
--- 
a/src/spark-project/engine-spark/src/main/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorer.java
+++ 
b/src/spark-project/engine-spark/src/main/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorer.java
@@ -60,6 +60,7 @@ import org.apache.spark.sql.Row;
 import org.apache.spark.sql.SparderEnv;
 import org.apache.spark.sql.SparkSession;
 import org.apache.spark.sql.catalog.Database;
+import org.apache.spark.sql.catalog.Table;
 import org.apache.spark.sql.catalyst.catalog.CatalogTableType;
 import org.apache.spark.sql.internal.SQLConf;
 import org.slf4j.Logger;
@@ -131,12 +132,10 @@ public class NSparkMetadataExplorer implements 
ISourceMetadataExplorer, ISampleD
 
         List<String> tables = Lists.newArrayList();
         try {
-            String sql = "show tables";
-            if (StringUtils.isNotBlank(database)) {
-                sql = String.format(Locale.ROOT, sql + " in %s", database);
-            }
-            Dataset<Row> dataset = 
SparderEnv.getSparkSession().sql(sql).select("tableName");
-            tables = dataset.collectAsList().stream().map(row -> 
row.getString(0)).collect(Collectors.toList());
+            SparkSession sparkSession = SparderEnv.getSparkSession();
+            Dataset<Table> dataset = StringUtils.isNotBlank(database) ? 
sparkSession.catalog().listTables(database)
+                    : sparkSession.catalog().listTables();
+            tables = 
dataset.collectAsList().stream().map(Table::name).collect(Collectors.toList());
 
             if (config.getTableAccessFilterEnable() && 
config.getKerberosProjectLevelEnable()
                     && UserGroupInformation.isSecurityEnabled()) {
diff --git 
a/src/spark-project/engine-spark/src/test/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorerTest.java
 
b/src/spark-project/engine-spark/src/test/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorerTest.java
index f822324a6e..09d632bed7 100644
--- 
a/src/spark-project/engine-spark/src/test/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorerTest.java
+++ 
b/src/spark-project/engine-spark/src/test/java/org/apache/kylin/engine/spark/source/NSparkMetadataExplorerTest.java
@@ -17,6 +17,7 @@
  */
 package org.apache.kylin.engine.spark.source;
 
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.kylin.common.KylinConfig;
@@ -26,9 +27,11 @@ import 
org.apache.kylin.engine.spark.NLocalWithSparkSessionTestBase;
 import org.apache.kylin.metadata.model.NTableMetadataManager;
 import org.apache.kylin.metadata.model.TableDesc;
 import org.apache.kylin.metadata.model.TableExtDesc;
+import org.apache.spark.sql.Dataset;
 import org.apache.spark.sql.Row;
 import org.apache.spark.sql.SparderEnv;
 import org.apache.spark.sql.SparkSession;
+import org.apache.spark.sql.catalog.Table;
 import org.apache.spark.sql.internal.SQLConf;
 import org.junit.Assert;
 import org.junit.Test;
@@ -81,6 +84,24 @@ public class NSparkMetadataExplorerTest extends 
NLocalWithSparkSessionTestBase {
         Assert.assertEquals(tables.get(0), "part");
     }
 
+    @Test
+    public void testListTablesUsesCatalogApi() throws Exception {
+        SparkSession sparkSession = Mockito.mock(SparkSession.class, 
Mockito.RETURNS_DEEP_STUBS);
+        Dataset<Table> dataset = Mockito.mock(Dataset.class);
+        Table table = Mockito.mock(Table.class);
+        
Mockito.when(sparkSession.catalog().listTables("default")).thenReturn(dataset);
+        
Mockito.when(dataset.collectAsList()).thenReturn(Collections.singletonList(table));
+        Mockito.when(table.name()).thenReturn("safe_table");
+        SparderEnv.setSparkSession(sparkSession);
+        try {
+            NSparkMetadataExplorer sparkMetadataExplorer = new 
NSparkMetadataExplorer();
+            Assert.assertEquals(Collections.singletonList("safe_table"), 
sparkMetadataExplorer.listTables("default"));
+            Mockito.verify(sparkSession, 
Mockito.never()).sql(Mockito.anyString());
+        } finally {
+            SparderEnv.setSparkSession(ss);
+        }
+    }
+
     @Test
     public void testGetTableDesc() throws Exception {
         populateSSWithCSVData(getTestConfig(), "ssb", ss);

Reply via email to