This is an automated email from the ASF dual-hosted git repository. morrysnow 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 57ee5c4a65 [feature](nereids) Support authentication (#13434) 57ee5c4a65 is described below commit 57ee5c4a657043f1d46f281ff1bb7510215cc6bf Author: Adonis Ling <adonis0...@gmail.com> AuthorDate: Thu Nov 3 11:58:14 2022 +0800 [feature](nereids) Support authentication (#13434) Add a rule to check the permission of a user who are executing a query. Forbid users who don't have SELECT_PRIV on some tables from executing queries on these tables. --- .../doris/nereids/jobs/batch/AnalyzeRulesJob.java | 2 + .../org/apache/doris/nereids/rules/RuleType.java | 4 ++ .../nereids/rules/analysis/UserAuthentication.java | 52 ++++++++++++++ .../account_p0/test_nereids_authentication.groovy | 83 ++++++++++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AnalyzeRulesJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AnalyzeRulesJob.java index bb3f107066..d5bb56e8e7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AnalyzeRulesJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/AnalyzeRulesJob.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.rules.analysis.ProjectToGlobalAggregate; import org.apache.doris.nereids.rules.analysis.RegisterCTE; import org.apache.doris.nereids.rules.analysis.ResolveHaving; import org.apache.doris.nereids.rules.analysis.Scope; +import org.apache.doris.nereids.rules.analysis.UserAuthentication; import com.google.common.collect.ImmutableList; @@ -48,6 +49,7 @@ public class AnalyzeRulesJob extends BatchRulesJob { )), bottomUpBatch(ImmutableList.of( new BindRelation(), + new UserAuthentication(), new BindSlotReference(scope), new BindFunction(), new ResolveHaving(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index b81695bfef..a6f4641bb6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -52,6 +52,8 @@ public enum RuleType { PROJECT_TO_GLOBAL_AGGREGATE(RuleTypeClass.REWRITE), REGISTER_CTE(RuleTypeClass.REWRITE), + RELATION_AUTHENTICATION(RuleTypeClass.VALIDATION), + // check analysis rule CHECK_ANALYSIS(RuleTypeClass.CHECK), @@ -185,8 +187,10 @@ public enum RuleType { enum RuleTypeClass { REWRITE, EXPLORATION, + // This type is used for unit test only. CHECK, IMPLEMENTATION, + VALIDATION, SENTINEL, ; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/UserAuthentication.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/UserAuthentication.java new file mode 100644 index 0000000000..e9b4c6d412 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/UserAuthentication.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.rules.analysis; + +import org.apache.doris.common.ErrorCode; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; +import org.apache.doris.qe.ConnectContext; + +/** + * Check whether a user is permitted to scan specific tables. + */ +public class UserAuthentication extends OneAnalysisRuleFactory { + + @Override + public Rule build() { + return logicalRelation().thenApply(ctx -> checkPermission(ctx.root, ctx.connectContext)) + .toRule(RuleType.RELATION_AUTHENTICATION); + } + + private Plan checkPermission(LogicalRelation relation, ConnectContext connectContext) { + String dbName = !relation.getQualifier().isEmpty() ? relation.getQualifier().get(0) : null; + String tableName = relation.getTable().getName(); + if (!connectContext.getEnv().getAuth().checkTblPriv(connectContext, dbName, tableName, PrivPredicate.SELECT)) { + String message = ErrorCode.ERR_TABLEACCESS_DENIED_ERROR.formatErrorMsg("SELECT", + ConnectContext.get().getQualifiedUser(), ConnectContext.get().getRemoteIP(), + dbName + ": " + tableName); + throw new AnalysisException(message); + + } + return relation; + } +} diff --git a/regression-test/suites/account_p0/test_nereids_authentication.groovy b/regression-test/suites/account_p0/test_nereids_authentication.groovy new file mode 100644 index 0000000000..6a2a980401 --- /dev/null +++ b/regression-test/suites/account_p0/test_nereids_authentication.groovy @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_nereids_authentication", "query") { + def create_table = { tableName -> + sql "DROP TABLE IF EXISTS ${tableName}" + sql """ + CREATE TABLE ${tableName} ( + `key` INT, + value INT + ) DUPLICATE KEY (`key`) DISTRIBUTED BY HASH (`key`) BUCKETS 1 + PROPERTIES ('replication_num' = '1') + """ + } + + sql "set enable_nereids_planner = true" + + def dbName = "nereids_authentication" + sql "DROP DATABASE IF EXISTS ${dbName}" + sql "CREATE DATABASE ${dbName}" + sql "USE ${dbName}" + + def tableName1 = "accessible_table"; + def tableName2 = "inaccessible_table"; + create_table.call(tableName1); + create_table.call(tableName2); + + def user='nereids_user' + try_sql "DROP USER ${user}" + sql "CREATE USER ${user} IDENTIFIED BY '123456'" + sql "GRANT SELECT_PRIV ON internal.${dbName}.${tableName1} TO ${user}" + + def tokens = context.config.jdbcUrl.split('/') + def url=tokens[0] + "//" + tokens[2] + "/" + dbName + "?" + def result = connect(user=user, password='123456', url=url) { + sql "SELECT * FROM ${tableName1}" + } + assertEquals(result.size(), 0) + + connect(user=user, password='123456', url=url) { + try { + sql "SELECT * FROM ${tableName2}" + fail() + } catch (Exception e) { + log.info(e.getMessage()) + assertTrue(e.getMessage().contains('SELECT command denied to user')) + } + } + + connect(user=user, password='123456', url=url) { + try { + sql "SELECT * FROM ${tableName1}, ${tableName2} WHERE ${tableName1}.`key` = ${tableName2}.`key`" + fail() + } catch (Exception e) { + log.info(e.getMessage()) + assertTrue(e.getMessage().contains('SELECT command denied to user')) + } + } + + sql "GRANT SELECT_PRIV ON internal.${dbName}.${tableName2} TO ${user}" + connect(user=user, password='123456', url=url) { + sql "SELECT * FROM ${tableName2}" + } + assertEquals(result.size(), 0) + connect(user=user, password='123456', url=url) { + sql "SELECT * FROM ${tableName1}, ${tableName2} WHERE ${tableName1}.`key` = ${tableName2}.`key`" + } + assertEquals(result.size(), 0) +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org