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