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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]