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

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


The following commit(s) were added to refs/heads/master by this push:
     new af3122244ef [fix](auth)support check priv when tvf use resource 
(#36928)
af3122244ef is described below

commit af3122244ef3ad99f24069a00805e90a7f488b13
Author: zhangdong <493738...@qq.com>
AuthorDate: Tue Jul 2 14:25:21 2024 +0800

    [fix](auth)support check priv when tvf use resource (#36928)
    
    current, follow sql not check priv, we need check `usage priv` of
    `test_resource`
    ```
    SELECT * FROM S3 (
        "uri" = "xxx",
        "format" = "orc",
        "resource" = "test_resource",
        "use_path_style" = "true"
    );
    ````
---
 .../org/apache/doris/analysis/AlterPolicyStmt.java |  1 +
 .../apache/doris/analysis/CreatePolicyStmt.java    |  1 +
 .../java/org/apache/doris/common/ErrorCode.java    |  4 ++
 .../nereids/rules/rewrite/CheckPrivileges.java     |  9 ++++
 .../functions/table/TableValuedFunction.java       |  5 +++
 .../ExternalFileTableValuedFunction.java           | 17 ++++++++
 .../doris/tablefunction/TableValuedFunctionIf.java |  5 +++
 .../tvf/test_s3_tvf_with_resource.groovy           | 48 ++++++++++++++++++++++
 8 files changed, 90 insertions(+)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterPolicyStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterPolicyStmt.java
index c8128e2bcbd..db9c10f34f2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterPolicyStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterPolicyStmt.java
@@ -53,6 +53,7 @@ public class AlterPolicyStmt extends DdlStmt {
         super.analyze(analyzer);
 
         // check auth
+        // check if can alter policy and use storage_resource
         if (!Env.getCurrentEnv().getAccessManager()
                 .checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) {
             
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreatePolicyStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreatePolicyStmt.java
index 8aedccb6e75..0c3e760e576 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreatePolicyStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreatePolicyStmt.java
@@ -102,6 +102,7 @@ public class CreatePolicyStmt extends DdlStmt {
                             + "Enable it by setting 
'enable_storage_policy=true' in fe.conf");
                 }
                 // check auth
+                // check if can create policy and use storage_resource
                 if (!Env.getCurrentEnv().getAccessManager()
                         .checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)) {
                     
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
index e66bdef133c..c3864b45aa2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java
@@ -83,6 +83,10 @@ public enum ErrorCode {
 
     ERR_SPECIFIC_ALL_ACCESS_DENIED_ERROR(1223, new byte[] {'4', '2', '0', '0', 
'0'}, "Access denied; you need all "
             + " %s privilege(s) for this operation"),
+
+    ERR_RESOURCE_ACCESS_DENIED_ERROR(1222, new byte[]{'4', '2', '0', '0', 
'0'}, "Access denied; you need (at least "
+            + "one of) the (%s) privilege(s) on resource %s for this 
operation"),
+
     ERR_LOCAL_VARIABLE(1228, new byte[]{'H', 'Y', '0', '0', '0'}, "Variable 
'%s' is a SESSION variable and can't be "
             + "used with SET GLOBAL"),
     ERR_GLOBAL_VARIABLE(1229, new byte[]{'H', 'Y', '0', '0', '0'}, "Variable 
'%s' is a GLOBAL variable and should be "
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckPrivileges.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckPrivileges.java
index 5c82dfac651..74609694431 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckPrivileges.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckPrivileges.java
@@ -27,9 +27,11 @@ import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.rules.analysis.UserAuthentication;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
+import 
org.apache.doris.nereids.trees.expressions.functions.table.TableValuedFunction;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
 import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalTVFRelation;
 import org.apache.doris.nereids.trees.plans.logical.LogicalView;
 import org.apache.doris.qe.ConnectContext;
 
@@ -62,6 +64,13 @@ public class CheckPrivileges extends ColumnPruning {
         return view;
     }
 
+    @Override
+    public Plan visitLogicalTVFRelation(LogicalTVFRelation tvfRelation, 
PruneContext context) {
+        TableValuedFunction tvf = tvfRelation.getFunction();
+        tvf.checkAuth(jobContext.getCascadesContext().getConnectContext());
+        return super.visitLogicalTVFRelation(tvfRelation, context);
+    }
+
     @Override
     public Plan visitLogicalRelation(LogicalRelation relation, PruneContext 
context) {
         if (relation instanceof LogicalCatalogRelation) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/table/TableValuedFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/table/TableValuedFunction.java
index fda53020598..bdefb2c75eb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/table/TableValuedFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/table/TableValuedFunction.java
@@ -31,6 +31,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.Nondeterministic;
 import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.SessionVariable;
 import org.apache.doris.statistics.ColumnStatistic;
 import org.apache.doris.statistics.Statistics;
@@ -103,6 +104,10 @@ public abstract class TableValuedFunction extends 
BoundFunction
         return tableCache.get();
     }
 
+    public final void checkAuth(ConnectContext ctx) {
+        getCatalogFunction().checkAuth(ctx);
+    }
+
     @Override
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitTableValuedFunction(this, context);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
index 518552bff4a..4c2866eb2b4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java
@@ -33,6 +33,7 @@ import org.apache.doris.catalog.StructType;
 import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.Pair;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.BrokerUtil;
@@ -41,6 +42,7 @@ import org.apache.doris.common.util.FileFormatUtils;
 import org.apache.doris.common.util.NetUtils;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.datasource.tvf.source.TVFScanNode;
+import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.planner.PlanNodeId;
 import org.apache.doris.planner.ScanNode;
 import org.apache.doris.proto.InternalService;
@@ -125,6 +127,9 @@ public abstract class ExternalFileTableValuedFunction 
extends TableValuedFunctio
     protected String filePath;
 
     protected TFileFormatType fileFormatType;
+
+    protected Optional<String> resourceName = Optional.empty();
+
     private TFileCompressType compressionType;
     private String headerType = "";
 
@@ -181,6 +186,7 @@ public abstract class ExternalFileTableValuedFunction 
extends TableValuedFunctio
             if (resource == null) {
                 throw new AnalysisException("Can not find resource: " + 
properties.get("resource"));
             }
+            this.resourceName = Optional.of(properties.get("resource"));
             mergedProperties = resource.getCopiedProperties();
         }
         mergedProperties.putAll(properties);
@@ -564,5 +570,16 @@ public abstract class ExternalFileTableValuedFunction 
extends TableValuedFunctio
         }
         return false;
     }
+
+    public void checkAuth(ConnectContext ctx) {
+        if (resourceName.isPresent()) {
+            if (!Env.getCurrentEnv().getAccessManager()
+                    .checkResourcePriv(ctx, resourceName.get(), 
PrivPredicate.USAGE)) {
+                String message = 
ErrorCode.ERR_RESOURCE_ACCESS_DENIED_ERROR.formatErrorMsg(
+                        PrivPredicate.USAGE.getPrivs().toString(), 
resourceName.get());
+                throw new 
org.apache.doris.nereids.exceptions.AnalysisException(message);
+            }
+        }
+    }
 }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/TableValuedFunctionIf.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/TableValuedFunctionIf.java
index 5d9e807c11f..6b6fda088a8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/TableValuedFunctionIf.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/TableValuedFunctionIf.java
@@ -24,6 +24,7 @@ import org.apache.doris.catalog.TableIf;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.planner.PlanNodeId;
 import org.apache.doris.planner.ScanNode;
+import org.apache.doris.qe.ConnectContext;
 
 import java.util.List;
 import java.util.Map;
@@ -86,4 +87,8 @@ public abstract class TableValuedFunctionIf {
     public abstract List<Column> getTableColumns() throws AnalysisException;
 
     public abstract ScanNode getScanNode(PlanNodeId id, TupleDescriptor desc);
+
+    public void checkAuth(ConnectContext ctx) {
+
+    }
 }
diff --git 
a/regression-test/suites/external_table_p0/tvf/test_s3_tvf_with_resource.groovy 
b/regression-test/suites/external_table_p0/tvf/test_s3_tvf_with_resource.groovy
index da7327adbf2..318cf092339 100644
--- 
a/regression-test/suites/external_table_p0/tvf/test_s3_tvf_with_resource.groovy
+++ 
b/regression-test/suites/external_table_p0/tvf/test_s3_tvf_with_resource.groovy
@@ -176,4 +176,52 @@ suite("test_s3_tvf_with_resource", "p0") {
     } finally {
     }
 
+    // test auth
+    String user = 'test_s3_tvf_with_resource_user'
+    String pwd = 'C123_567p'
+    String viewName = "test_s3_tvf_with_resource_view"
+    try_sql("DROP USER ${user}")
+    sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'"""
+    String dbName = context.config.getDbNameByFile(context.file)
+    sql """grant select_priv on ${dbName}.${viewName} to ${user}"""
+    sql "drop view if exists ${viewName}"
+    sql """
+        create view ${viewName} as
+        SELECT * FROM S3 (
+                           "uri" = 
"https://${bucket}.${s3_endpoint}/regression/tvf/test_hive_text.text";,
+                           "format" = "hive_text",
+                           "csv_schema"="k1:int;k2:string;k3:double",
+                           "resource" = "${resource_name}"
+                       )  where k1 > 100  order by k3,k2,k1;
+        """
+
+    //cloud-mode
+    if (isCloudMode()) {
+        def clusters = sql " SHOW CLUSTERS; "
+        assertTrue(!clusters.isEmpty())
+        def validCluster = clusters[0][0]
+        sql """GRANT USAGE_PRIV ON CLUSTER ${validCluster} TO ${user}""";
+    }
+    // not have usage priv, can not select tvf with resource
+    connect(user=user, password="${pwd}", url=context.config.jdbcUrl) {
+        test {
+                sql """
+                    SELECT * FROM S3 (
+                                        "uri" = 
"https://${bucket}.${s3_endpoint}/regression/tvf/test_hive_text.text";,
+                                        "format" = "hive_text",
+                                        
"csv_schema"="k1:int;k2:string;k3:double",
+                                        "resource" = "${resource_name}"
+                                    )  where k1 > 100  order by k3,k2,k1;
+                    """
+                exception "Access denied"
+            }
+    }
+
+    // only have select_priv of view,can select view with resource
+    connect(user=user, password="${pwd}", url=context.config.jdbcUrl) {
+            sql """SELECT * FROM ${viewName};"""
+    }
+
+    try_sql("DROP USER ${user}")
+    sql "drop view if exists ${viewName}"
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to