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 6a4976921d [fix](auth)Disable column auth temporarily (#23295)
6a4976921d is described below
commit 6a4976921dc43b810d3f891cb6e27ec3f03e20be
Author: zhangdong <[email protected]>
AuthorDate: Thu Aug 24 23:37:06 2023 +0800
[fix](auth)Disable column auth temporarily (#23295)
- add config `enable_col_auth` to temporarily disable column
permissions(because old/new planner has bug when select from view)
- Restore the old optimizer to the previous authentication method
- Support for new optimizer authentication(Legacy issue: When querying the
view, the permissions of the base table will be authenticated. The view's own
permissions should be authenticated and processed after the new optimizer is
improved)
- fix: show grants for non-existent users
- fix: role:`admin` can not grant/revoke to/from user
---
.../main/java/org/apache/doris/common/Config.java | 5 ++
.../java/org/apache/doris/analysis/GrantStmt.java | 6 +-
.../java/org/apache/doris/analysis/RevokeStmt.java | 2 +-
.../java/org/apache/doris/analysis/SelectStmt.java | 9 +++
.../org/apache/doris/analysis/ShowGrantsStmt.java | 3 +
.../apache/doris/datasource/ExternalCatalog.java | 3 +
.../apache/doris/datasource/InternalCatalog.java | 3 +
.../org/apache/doris/mysql/privilege/Auth.java | 2 +-
.../nereids/rules/analysis/UserAuthentication.java | 29 +++++++--
.../org/apache/doris/planner/OriginalPlanner.java | 73 ----------------------
.../apache/doris/datasource/ColumnPrivTest.java | 3 +
.../org/apache/doris/mysql/privilege/AuthTest.java | 2 +
regression-test/data/account_p0/test_account.out | 4 --
.../suites/account_p0/test_account.groovy | 8 ++-
.../account_p0/test_nereids_authentication.groovy | 5 +-
15 files changed, 67 insertions(+), 90 deletions(-)
diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
index af86454985..9da22b20da 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
@@ -2112,6 +2112,11 @@ public class Config extends ConfigBase {
"Whether to use mysql's bigint type to return Doris's largeint
type"})
public static boolean use_mysql_bigint_for_largeint = false;
+ @ConfField(description = {
+ "是否开启列权限",
+ "Whether to enable col auth"})
+ public static boolean enable_col_auth = false;
+
@ConfField
public static boolean forbid_running_alter_job = false;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
index aa0c21f0f0..53c19add7e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
@@ -21,6 +21,7 @@ import org.apache.doris.catalog.AccessPrivilegeWithCols;
import org.apache.doris.catalog.Env;
import org.apache.doris.cluster.ClusterNamespace;
import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
@@ -149,7 +150,7 @@ public class GrantStmt extends DdlStmt {
} else if (roles != null) {
for (int i = 0; i < roles.size(); i++) {
String originalRoleName = roles.get(i);
- FeNameFormat.checkRoleName(originalRoleName, false /* can not
be admin */, "Can not grant role");
+ FeNameFormat.checkRoleName(originalRoleName, true /* can be
admin */, "Can not grant role");
roles.set(i,
ClusterNamespace.getFullName(analyzer.getClusterName(), originalRoleName));
}
}
@@ -181,7 +182,8 @@ public class GrantStmt extends DdlStmt {
public static void checkAccessPrivileges(
List<AccessPrivilegeWithCols> accessPrivileges) throws
AnalysisException {
for (AccessPrivilegeWithCols access : accessPrivileges) {
- if (!access.getAccessPrivilege().canHasColPriv() &&
!CollectionUtils.isEmpty(access.getCols())) {
+ if ((!access.getAccessPrivilege().canHasColPriv() ||
!Config.enable_col_auth) && !CollectionUtils
+ .isEmpty(access.getCols())) {
throw new AnalysisException(
String.format("%s do not support col auth.",
access.getAccessPrivilege().name()));
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
index 74e9a4de91..8e11c3a7d1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/RevokeStmt.java
@@ -133,7 +133,7 @@ public class RevokeStmt extends DdlStmt {
} else if (roles != null) {
for (int i = 0; i < roles.size(); i++) {
String originalRoleName = roles.get(i);
- FeNameFormat.checkRoleName(originalRoleName, false /* can not
be admin */, "Can not revoke role");
+ FeNameFormat.checkRoleName(originalRoleName, true /* can be
admin */, "Can not revoke role");
roles.set(i,
ClusterNamespace.getFullName(analyzer.getClusterName(), originalRoleName));
}
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
index b69466ab51..0f03afde0a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
@@ -24,6 +24,7 @@ import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.AggregateFunction;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.FunctionSet;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.PrimitiveType;
@@ -44,6 +45,7 @@ import org.apache.doris.common.TreeNode;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.SqlUtils;
import org.apache.doris.common.util.ToSqlContext;
+import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.rewrite.ExprRewriter;
import org.apache.doris.rewrite.mvrewrite.MVSelectFailedException;
@@ -392,6 +394,13 @@ public class SelectStmt extends QueryStmt {
View view = (View) table;
view.getQueryStmt().getTables(analyzer, expandView,
tableMap, parentViewNameSet);
} else {
+ // check auth
+ if (!Env.getCurrentEnv().getAccessManager()
+ .checkTblPriv(ConnectContext.get(),
tblRef.getName(), PrivPredicate.SELECT)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR,
"SELECT",
+ ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
+ dbName + "." + tableName);
+ }
tableMap.put(table.getId(), table);
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowGrantsStmt.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowGrantsStmt.java
index a380b27451..e2c41eed0c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowGrantsStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowGrantsStmt.java
@@ -89,6 +89,9 @@ public class ShowGrantsStmt extends ShowStmt {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
"GRANT");
}
}
+ if (userIdent != null &&
!Env.getCurrentEnv().getAccessManager().getAuth().doesUserExist(userIdent)) {
+ throw new AnalysisException(String.format("User: %s does not
exist", userIdent));
+ }
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index 301e2039ce..9dbc40ff84 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -350,6 +350,9 @@ public abstract class ExternalCatalog
@Nullable
@Override
public ExternalDatabase<? extends ExternalTable> getDbNullable(String
dbName) {
+ if (StringUtils.isEmpty(dbName)) {
+ return null;
+ }
try {
makeSureInitialized();
} catch (Exception e) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
index a28f276af7..2be8e61fdf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -256,6 +256,9 @@ public class InternalCatalog implements CatalogIf<Database>
{
@Nullable
@Override
public Database getDbNullable(String dbName) {
+ if (StringUtils.isEmpty(dbName)) {
+ return null;
+ }
if (fullNameToDb.containsKey(dbName)) {
return fullNameToDb.get(dbName);
} else {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
index 995a016478..636ac50f39 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
@@ -663,7 +663,7 @@ public class Auth implements Writable {
// return true if user ident exist
- private boolean doesUserExist(UserIdentity userIdent) {
+ public boolean doesUserExist(UserIdentity userIdent) {
return userManager.userIdentityExist(userIdent, false);
}
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
index 3c97e90476..86fb64d6e5 100644
---
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
@@ -17,7 +17,10 @@
package org.apache.doris.nereids.rules.analysis;
+import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.TableIf;
import org.apache.doris.common.ErrorCode;
+import org.apache.doris.datasource.CatalogIf;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.rules.Rule;
@@ -44,17 +47,31 @@ public class UserAuthentication extends
OneAnalysisRuleFactory {
if (connectContext.getSessionVariable().isPlayNereidsDump()) {
return null;
}
-
- String dbName = relation.getDatabase().getFullName();
- String tableName = relation.getTable().getName();
- if
(!connectContext.getEnv().getAccessManager().checkTblPriv(connectContext,
dbName,
+ TableIf table = relation.getTable();
+ if (table == null) {
+ return null;
+ }
+ String tableName = table.getName();
+ DatabaseIf db = table.getDatabase();
+ // when table inatanceof FunctionGenTable,db will be null
+ if (db == null) {
+ return null;
+ }
+ String dbName = db.getFullName();
+ CatalogIf catalog = db.getCatalog();
+ if (catalog == null) {
+ return null;
+ }
+ String ctlName = catalog.getName();
+ // TODO: 2023/7/19 checkColumnsPriv
+ if
(!connectContext.getEnv().getAccessManager().checkTblPriv(connectContext,
ctlName, dbName,
tableName, PrivPredicate.SELECT)) {
String message =
ErrorCode.ERR_TABLEACCESS_DENIED_ERROR.formatErrorMsg("SELECT",
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
- dbName + ": " + tableName);
+ ctlName + ": " + dbName + ": " + tableName);
throw new AnalysisException(message);
}
-
return null;
}
+
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
b/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
index 0056619376..f77aba25da 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
@@ -33,23 +33,15 @@ import org.apache.doris.analysis.SlotId;
import org.apache.doris.analysis.SlotRef;
import org.apache.doris.analysis.StatementBase;
import org.apache.doris.analysis.StorageBackend;
-import org.apache.doris.analysis.TableName;
import org.apache.doris.analysis.TupleDescriptor;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.ScalarType;
-import org.apache.doris.catalog.Table;
-import org.apache.doris.catalog.TableIf;
import org.apache.doris.catalog.Type;
-import org.apache.doris.catalog.external.ExternalTable;
-import org.apache.doris.cluster.ClusterNamespace;
-import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
import org.apache.doris.common.UserException;
-import org.apache.doris.datasource.InternalCatalog;
-import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.CommonResultSet;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ResultSet;
@@ -61,10 +53,7 @@ import org.apache.doris.thrift.TQueryOptions;
import org.apache.doris.thrift.TRuntimeFilterMode;
import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -179,8 +168,6 @@ public class OriginalPlanner extends Planner {
insertStmt.prepareExpressions();
}
- checkColumnPrivileges(singleNodePlan);
-
// TODO chenhao16 , no used materialization work
// compute referenced slots before calling computeMemLayout()
//analyzer.markRefdSlots(analyzer, singleNodePlan, resultExprs, null);
@@ -319,66 +306,6 @@ public class OriginalPlanner extends Planner {
}
}
- private void checkColumnPrivileges(PlanNode singleNodePlan) throws
UserException {
- if (ConnectContext.get() == null) {
- return;
- }
- // 1. collect all columns from all scan nodes
- List<ScanNode> scanNodes = Lists.newArrayList();
- singleNodePlan.collect((PlanNode planNode) -> planNode instanceof
ScanNode, scanNodes);
- // catalog : <db.table : column>
- Map<String, HashMultimap<TableName, String>> ctlToTableColumnMap =
Maps.newHashMap();
- for (ScanNode scanNode : scanNodes) {
- if (!scanNode.needToCheckColumnPriv()) {
- continue;
- }
- TupleDescriptor tupleDesc = scanNode.getTupleDesc();
- TableIf table = tupleDesc.getTable();
- if (table == null) {
- continue;
- }
- TableName tableName = getFullQualifiedTableNameFromTable(table);
- for (SlotDescriptor slotDesc : tupleDesc.getSlots()) {
- if (!slotDesc.isMaterialized()) {
- continue;
- }
- Column column = slotDesc.getColumn();
- if (column == null) {
- continue;
- }
- HashMultimap<TableName, String> tableColumnMap =
ctlToTableColumnMap.get(tableName.getCtl());
- if (tableColumnMap == null) {
- tableColumnMap = HashMultimap.create();
- ctlToTableColumnMap.put(tableName.getCtl(),
tableColumnMap);
- }
- tableColumnMap.put(tableName, column.getName());
- LOG.debug("collect column {} in {}", column.getName(),
tableName);
- }
- }
- // 2. check privs
- // TODO: only support SELECT_PRIV now
- PrivPredicate wanted = PrivPredicate.SELECT;
- for (Map.Entry<String, HashMultimap<TableName, String>> entry :
ctlToTableColumnMap.entrySet()) {
-
Env.getCurrentEnv().getAccessManager().checkColumnsPriv(ConnectContext.get().getCurrentUserIdentity(),
- entry.getKey(), entry.getValue(), wanted);
- }
- }
-
- private TableName getFullQualifiedTableNameFromTable(TableIf table) throws
AnalysisException {
- if (table instanceof Table) {
- String dbName = ClusterNamespace.getNameFromFullName(((Table)
table).getQualifiedDbName());
- if (Strings.isNullOrEmpty(dbName)) {
- throw new AnalysisException("failed to get db name from table
" + table.getName());
- }
- return new TableName(InternalCatalog.INTERNAL_CATALOG_NAME,
dbName, table.getName());
- } else if (table instanceof ExternalTable) {
- ExternalTable extTable = (ExternalTable) table;
- return new TableName(extTable.getCatalog().getName(),
extTable.getDbName(), extTable.getName());
- } else {
- throw new AnalysisException("table " + table.getName() + " is not
internal or external table instance");
- }
- }
-
/**
* If there are unassigned conjuncts, returns a SelectNode on top of root
that evaluate those conjuncts; otherwise
* returns root unchanged.
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java
index 151532aee7..b9726cf598 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java
@@ -48,12 +48,15 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.junit.Assert;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import java.util.Set;
+// when `select` suppport `col auth`,will open ColumnPrivTest
+@Disabled
public class ColumnPrivTest extends TestWithFeService {
private static Auth auth;
private static Env env;
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
index 4978304177..b0afc8055d 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
@@ -34,6 +34,7 @@ import org.apache.doris.catalog.AccessPrivilegeWithCols;
import org.apache.doris.catalog.DomainResolver;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.ExceptionChecker;
import org.apache.doris.common.UserException;
@@ -153,6 +154,7 @@ public class AuthTest {
};
resolver = new MockDomainResolver(auth);
+ Config.enable_col_auth = true;
}
@Test
diff --git a/regression-test/data/account_p0/test_account.out
b/regression-test/data/account_p0/test_account.out
deleted file mode 100644
index ad97022a09..0000000000
--- a/regression-test/data/account_p0/test_account.out
+++ /dev/null
@@ -1,4 +0,0 @@
--- This file is automatically generated. You should know what you did if you
want to edit this
--- !show_grants1 --
-'default_cluster:non_existent_user_1'@'%' \N \N \N \N
\N \N \N \N \N
-
diff --git a/regression-test/suites/account_p0/test_account.groovy
b/regression-test/suites/account_p0/test_account.groovy
index b38d72a80d..1eb07e259c 100644
--- a/regression-test/suites/account_p0/test_account.groovy
+++ b/regression-test/suites/account_p0/test_account.groovy
@@ -18,5 +18,11 @@ suite("test_account") {
// todo: test account management, such as role, user, grant, revoke ...
sql "show roles"
- qt_show_grants1 "show grants for 'non_existent_user_1'"
+ try {
+ sql "show grants for 'non_existent_user_1'"
+ fail()
+ } catch (Exception e) {
+ log.info(e.getMessage())
+ assertTrue(e.getMessage().contains('not exist'))
+ }
}
diff --git
a/regression-test/suites/account_p0/test_nereids_authentication.groovy
b/regression-test/suites/account_p0/test_nereids_authentication.groovy
index 2d5d2cbb13..46d60732d6 100644
--- a/regression-test/suites/account_p0/test_nereids_authentication.groovy
+++ b/regression-test/suites/account_p0/test_nereids_authentication.groovy
@@ -28,6 +28,7 @@ suite("test_nereids_authentication", "query") {
}
sql "set enable_nereids_planner = true"
+ sql "set enable_fallback_to_original_planner = false"
def dbName = "nereids_authentication"
sql "DROP DATABASE IF EXISTS ${dbName}"
@@ -57,7 +58,7 @@ suite("test_nereids_authentication", "query") {
fail()
} catch (Exception e) {
log.info(e.getMessage())
- assertTrue(e.getMessage().contains('Permission denied'))
+ assertTrue(e.getMessage().contains('denied to user'))
}
}
@@ -67,7 +68,7 @@ suite("test_nereids_authentication", "query") {
fail()
} catch (Exception e) {
log.info(e.getMessage())
- assertTrue(e.getMessage().contains('Permission denied'))
+ assertTrue(e.getMessage().contains('denied to user'))
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]