[improvement](auth)Not allowed to operate internal_schema database (#29790)

Only root user can operate __internal_schema database
The scope of impact includes:
create database
drop database
alter database
create table
drop table
alter table
truncate table
insert overwrite
insert
delete
update
load(root also not allowed)

delete support check auth
This commit is contained in:
zhangdong
2024-01-12 16:37:08 +08:00
committed by yiguolei
parent 8b4ffcc8f7
commit e1a12cf222
16 changed files with 206 additions and 9 deletions

View File

@ -21,6 +21,7 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.PrintableMap;
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.mysql.privilege.PrivPredicate;
@ -51,7 +52,7 @@ public class AlterDatabasePropertyStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
analyzer.getQualifiedUser(), dbName);

View File

@ -21,6 +21,7 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.ParseUtil;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -61,7 +62,7 @@ public class AlterDatabaseQuotaStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
analyzer.getQualifiedUser(), dbName);

View File

@ -24,6 +24,7 @@ import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.mysql.privilege.PrivBitSet;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.Privilege;
@ -54,7 +55,7 @@ public class AlterDatabaseRename extends DdlStmt {
if (Strings.isNullOrEmpty(dbName)) {
throw new AnalysisException("Database name is not set");
}
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), dbName,
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV, Privilege.ALTER_PRIV), Operator.OR))) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,

View File

@ -27,6 +27,7 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.common.util.Util;
import org.apache.doris.mysql.privilege.PrivPredicate;
@ -67,6 +68,7 @@ public class AlterTableStmt extends DdlStmt {
tbl.analyze(analyzer);
// disallow external catalog
Util.prohibitExternalCatalog(tbl.getCtl(), this.getClass().getSimpleName());
InternalDatabaseUtil.checkDatabase(tbl.getDb(), ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), tbl.getDb(), tbl.getTbl(),
PrivPredicate.ALTER)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "ALTER TABLE",

View File

@ -22,6 +22,7 @@ import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.PrintableMap;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -56,7 +57,7 @@ public class CreateDbStmt extends DdlStmt {
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
FeNameFormat.checkDbName(dbName);
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), dbName, PrivPredicate.CREATE)) {
ErrorReport.reportAnalysisException(
ErrorCode.ERR_DBACCESS_DENIED_ERROR, analyzer.getQualifiedUser(), dbName);

View File

@ -35,6 +35,7 @@ import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.Pair;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.AutoBucketUtils;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.ParseUtil;
import org.apache.doris.common.util.PrintableMap;
import org.apache.doris.common.util.PropertyAnalyzer;
@ -285,7 +286,7 @@ public class CreateTableStmt extends DdlStmt {
FeNameFormat.checkTableName(tableName.getTbl());
// disallow external catalog
Util.prohibitExternalCatalog(tableName.getCtl(), this.getClass().getSimpleName());
InternalDatabaseUtil.checkDatabase(tableName.getDb(), ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager()
.checkTblPriv(ConnectContext.get(), tableName.getDb(), tableName.getTbl(), PrivPredicate.CREATE)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "CREATE");

View File

@ -23,6 +23,7 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -58,7 +59,7 @@ public class DropDbStmt extends DdlStmt {
if (Strings.isNullOrEmpty(dbName)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_DB_NAME, dbName);
}
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
// Don't allow to drop mysql compatible databases
DatabaseIf db = Env.getCurrentInternalCatalog().getDbNullable(dbName);
if (db != null && (db instanceof Database) && ((Database) db).isMysqlCompatibleDatabase()) {

View File

@ -21,6 +21,7 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.Util;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -85,7 +86,7 @@ public class DropTableStmt extends DdlStmt {
tableName.analyze(analyzer);
// disallow external catalog
Util.prohibitExternalCatalog(tableName.getCtl(), this.getClass().getSimpleName());
InternalDatabaseUtil.checkDatabase(tableName.getDb(), ConnectContext.get());
// check access
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), tableName.getDb(),
tableName.getTbl(), PrivPredicate.DROP)) {

View File

@ -21,6 +21,7 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -74,6 +75,8 @@ public class InsertOverwriteTableStmt extends DdlStmt {
@Override
public void analyze(Analyzer analyzer) throws UserException {
target.getTblName().analyze(analyzer);
InternalDatabaseUtil.checkDatabase(getDb(), ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager()
.checkTblPriv(ConnectContext.get(), getDb(), getTbl(), PrivPredicate.LOAD)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "LOAD",

View File

@ -22,6 +22,7 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.Util;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -49,7 +50,7 @@ public class TruncateTableStmt extends DdlStmt {
if (tblRef.hasExplicitAlias()) {
throw new AnalysisException("Not support truncate table with alias");
}
InternalDatabaseUtil.checkDatabase(tblRef.getName().getDb(), ConnectContext.get());
// check access
// it requires LOAD privilege, because we consider this operation as 'delete data', which is also a
// 'load' operation.

View File

@ -0,0 +1,37 @@
// 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.common.util;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.FeConstants;
import org.apache.doris.qe.ConnectContext;
import com.google.common.base.Preconditions;
public class InternalDatabaseUtil {
public static void checkDatabase(String dbName, ConnectContext ctx) throws AnalysisException {
Preconditions.checkNotNull(dbName, "require dbName object");
if (!FeConstants.INTERNAL_DB_NAME.equals(dbName)) {
return;
}
if (ctx == null || ctx.getCurrentUserIdentity() == null || !ctx.getCurrentUserIdentity().isRootUser()) {
throw new AnalysisException("Not allowed to operate database: " + dbName);
}
}
}

View File

@ -26,6 +26,8 @@ import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.KeysType;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.NereidsPlanner;
import org.apache.doris.nereids.analyzer.UnboundRelation;
import org.apache.doris.nereids.exceptions.AnalysisException;
@ -115,6 +117,14 @@ public class DeleteFromCommand extends Command implements ForwardWithSync {
UnboundRelation relation = optRelation.get();
PhysicalFilter<?> filter = optFilter.get();
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), scan.getDatabase().getFullName(),
scan.getTable().getName(), PrivPredicate.LOAD)) {
String message = ErrorCode.ERR_TABLEACCESS_DENIED_ERROR.formatErrorMsg("LOAD",
ConnectContext.get().getQualifiedUser(), ConnectContext.get().getRemoteIP(),
scan.getDatabase().getFullName() + ": " + scan.getTable().getName());
throw new AnalysisException(message);
}
// predicate check
OlapTable olapTable = scan.getTable();
Set<String> columns = olapTable.getFullSchema().stream().map(Column::getName).collect(Collectors.toSet());

View File

@ -23,6 +23,7 @@ import org.apache.doris.catalog.TableIf;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.insertoverwrite.InsertOverwriteUtil;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.NereidsPlanner;
@ -111,6 +112,8 @@ public class InsertOverwriteTableCommand extends Command implements ForwardWithS
Preconditions.checkArgument(plan.isPresent(), "insert into command must contain OlapTableSinkNode");
PhysicalOlapTableSink<?> physicalOlapTableSink = ((PhysicalOlapTableSink<?>) plan.get());
OlapTable targetTable = physicalOlapTableSink.getTargetTable();
InternalDatabaseUtil
.checkDatabase(targetTable.getQualifiedDbName(), ConnectContext.get());
// check auth
if (!Env.getCurrentEnv().getAccessManager()
.checkTblPriv(ConnectContext.get(), targetTable.getQualifiedDbName(), targetTable.getName(),

View File

@ -46,6 +46,7 @@ import org.apache.doris.common.FeConstants;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.Pair;
import org.apache.doris.common.util.AutoBucketUtils;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.ParseUtil;
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.common.util.Util;
@ -254,7 +255,11 @@ public class CreateTableInfo {
if (Strings.isNullOrEmpty(dbName)) {
dbName = ctx.getDatabase();
}
try {
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
} catch (org.apache.doris.common.AnalysisException e) {
throw new AnalysisException(e.getMessage(), e.getCause());
}
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), dbName,
tableName, PrivPredicate.CREATE)) {
try {

View File

@ -45,6 +45,7 @@ import org.apache.doris.common.Pair;
import org.apache.doris.common.QuotaExceedException;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.DebugUtil;
import org.apache.doris.common.util.InternalDatabaseUtil;
import org.apache.doris.common.util.MetaLockUtils;
import org.apache.doris.common.util.TimeUtils;
import org.apache.doris.metric.MetricRepo;
@ -314,6 +315,8 @@ public class DatabaseTransactionMgr {
long listenerId, long timeoutSecond)
throws DuplicatedRequestException, LabelAlreadyUsedException, BeginTransactionException,
AnalysisException, QuotaExceedException, MetaNotFoundException {
Database db = env.getInternalCatalog().getDbOrMetaException(dbId);
InternalDatabaseUtil.checkDatabase(db.getFullName(), ConnectContext.get());
checkDatabaseDataQuota();
Preconditions.checkNotNull(coordinator);
Preconditions.checkNotNull(label);