From 36b2589ab4afea3a772904af2464ad85813db269 Mon Sep 17 00:00:00 2001 From: zhaorongsheng Date: Tue, 6 May 2025 11:08:01 +0800 Subject: [PATCH 1/2] [fix](restapi) Unify Permission Requirements for Executing SHOW FRONTENDS/BACKENDS And NODE RestAPI (#50140) Issue Number: close #50138 Problem Summary: Unify Permission Requirements for Executing SHOW FRONTENDS/BACKENDS And NODE RestAPI. Make it as same as the privileges of system default database `information_schema`. --- .../doris/analysis/ShowBackendsStmt.java | 10 +- .../doris/analysis/ShowFrontendsStmt.java | 10 +- .../doris/httpv2/rest/BackendsAction.java | 9 +- .../doris/httpv2/rest/manager/NodeAction.java | 15 +-- .../org/apache/doris/qe/ShowExecutor.java | 14 ++- .../BackendsTableValuedFunction.java | 12 ++ .../FrontendsDisksTableValuedFunction.java | 12 ++ .../FrontendsTableValuedFunction.java | 12 ++ .../doris/analysis/ShowBackendsStmtTest.java | 2 +- .../doris/analysis/ShowFrontendsStmtTest.java | 68 ++++++++++ .../commands/ShowBackendsCommandTest.java | 118 ++++++++++++++++++ .../commands/ShowFrontendsCommandTest.java | 118 ++++++++++++++++++ .../auth_call/test_show_backend_auth.groovy | 14 ++- .../auth_call/test_show_frontend_auth.groovy | 13 +- 14 files changed, 402 insertions(+), 25 deletions(-) create mode 100644 fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFrontendsStmtTest.java create mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java create mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowBackendsStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowBackendsStmt.java index 8e1e589477d2dc..06652d2dada50e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowBackendsStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowBackendsStmt.java @@ -19,11 +19,13 @@ import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.catalog.ScalarType; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.UserException; import org.apache.doris.common.proc.BackendsProcDir; +import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowResultSetMetaData; @@ -37,10 +39,10 @@ public ShowBackendsStmt() { public void analyze(Analyzer analyzer) throws UserException { super.analyze(analyzer); - if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN) - && !Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), - PrivPredicate.OPERATOR)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN/OPERATOR"); + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), + InternalCatalog.INTERNAL_CATALOG_NAME, InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_DB_ACCESS_DENIED_ERROR, + PrivPredicate.SELECT.getPrivs().toString(), InfoSchemaDb.DATABASE_NAME); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFrontendsStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFrontendsStmt.java index d8b5c454ff9d08..4e968843477e14 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFrontendsStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFrontendsStmt.java @@ -19,11 +19,13 @@ import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.catalog.ScalarType; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.proc.FrontendsProcNode; +import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowResultSetMetaData; @@ -46,10 +48,10 @@ public String getDetailType() { @Override public void analyze(Analyzer analyzer) throws AnalysisException { - if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.ADMIN) - && !Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), - PrivPredicate.OPERATOR)) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN/OPERATOR"); + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), + InternalCatalog.INTERNAL_CATALOG_NAME, InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_DB_ACCESS_DENIED_ERROR, + PrivPredicate.SELECT.getPrivs().toString(), InfoSchemaDb.DATABASE_NAME); } if (detail != null && !detail.equalsIgnoreCase("disks")) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/BackendsAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/BackendsAction.java index cef898326b9acf..81e44421500b50 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/BackendsAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/BackendsAction.java @@ -18,7 +18,10 @@ package org.apache.doris.httpv2.rest; import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.httpv2.entity.ResponseEntityBuilder; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.system.Backend; import com.fasterxml.jackson.annotation.JsonProperty; @@ -66,12 +69,8 @@ public class BackendsAction extends RestBaseController { @RequestMapping(path = "/api/backends", method = {RequestMethod.GET}) public Object getBackends(HttpServletRequest request, HttpServletResponse response) { - /** - * As required, the interface should require user have GlobalAuth-PrivPredicate.ADMIN permission. - * However, a user who uses spark-doris-connector/flink-doris-connector does not have corresponding permission. - * To ensure that the connector works properly, we do not verify the permission of the interface. - */ executeCheckPassword(request, response); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); boolean needAlive = false; String isAlive = request.getParameter(IS_ALIVE); diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java index 4658f936db5f1f..36620c36e92159 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java @@ -18,6 +18,7 @@ package org.apache.doris.httpv2.rest.manager; import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.common.Config; import org.apache.doris.common.ConfigBase; import org.apache.doris.common.MarkedCountDownLatch; @@ -108,7 +109,7 @@ public class NodeAction extends RestBaseController { @RequestMapping(path = "/frontends", method = RequestMethod.GET) public Object frontends_info(HttpServletRequest request, HttpServletResponse response) throws Exception { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); return fetchNodeInfo(request, response, "/frontends"); } @@ -117,7 +118,7 @@ public Object frontends_info(HttpServletRequest request, HttpServletResponse res @RequestMapping(path = "/backends", method = RequestMethod.GET) public Object backends_info(HttpServletRequest request, HttpServletResponse response) throws Exception { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); return fetchNodeInfo(request, response, "/backends"); } @@ -126,7 +127,7 @@ public Object backends_info(HttpServletRequest request, HttpServletResponse resp @RequestMapping(path = "/brokers", method = RequestMethod.GET) public Object brokers_info(HttpServletRequest request, HttpServletResponse response) throws Exception { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); return fetchNodeInfo(request, response, "/brokers"); } @@ -181,7 +182,7 @@ public NodeInfo(List columnNames, List> rows) { @RequestMapping(path = "/configuration_name", method = RequestMethod.GET) public Object configurationName(HttpServletRequest request, HttpServletResponse response) { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); Map> result = Maps.newHashMap(); try { @@ -220,7 +221,7 @@ public Object configurationName(HttpServletRequest request, HttpServletResponse @RequestMapping(path = "/node_list", method = RequestMethod.GET) public Object nodeList(HttpServletRequest request, HttpServletResponse response) { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); Map> result = Maps.newHashMap(); result.put("frontend", getFeList()); @@ -247,7 +248,7 @@ private static List getBeList() { @RequestMapping(path = "/config", method = RequestMethod.GET) public Object config(HttpServletRequest request, HttpServletResponse response) { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT); List> configs = ConfigBase.getConfigInfo(null); // Sort all configs by config key. @@ -308,7 +309,7 @@ public Object configurationInfo(HttpServletRequest request, HttpServletResponse @RequestParam(value = "type") String type, @RequestBody(required = false) ConfigInfoRequestBody requestBody) { executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN_OR_NODE); initHttpExecutor(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java index 4be871f7af8d93..57f7f677d02cb1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -2262,8 +2262,13 @@ private void handleShowExport() throws AnalysisException { resultSet = new ShowResultSet(showExportStmt.getMetaData(), infos); } - private void handleShowBackends() { + private void handleShowBackends() throws AnalysisException { final ShowBackendsStmt showStmt = (ShowBackendsStmt) stmt; + try { + showStmt.analyze(null); + } catch (Exception e) { + throw (AnalysisException) e; + } List> backendInfos = BackendsProcDir.getBackendInfos(); backendInfos.sort(new Comparator>() { @@ -2276,8 +2281,13 @@ public int compare(List o1, List o2) { resultSet = new ShowResultSet(showStmt.getMetaData(), backendInfos); } - private void handleShowFrontends() { + private void handleShowFrontends() throws AnalysisException { final ShowFrontendsStmt showStmt = (ShowFrontendsStmt) stmt; + try { + showStmt.analyze(null); + } catch (Exception e) { + throw (AnalysisException) e; + } List> infos = Lists.newArrayList(); FrontendsProcNode.getFrontendsInfo(Env.getCurrentEnv(), showStmt.getDetailType(), infos); diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java index 04ea7d01eae3dd..a40ec67c0dc72d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/BackendsTableValuedFunction.java @@ -18,9 +18,15 @@ package org.apache.doris.tablefunction; import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.thrift.TBackendsMetadataParams; import org.apache.doris.thrift.TMetaScanRange; import org.apache.doris.thrift.TMetadataType; @@ -83,6 +89,12 @@ public BackendsTableValuedFunction(Map params) throws AnalysisEx if (params.size() != 0) { throw new AnalysisException("backends table-valued-function does not support any params"); } + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), + InternalCatalog.INTERNAL_CATALOG_NAME, InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT)) { + String message = ErrorCode.ERR_DB_ACCESS_DENIED_ERROR.formatErrorMsg( + PrivPredicate.SELECT.getPrivs().toString(), InfoSchemaDb.DATABASE_NAME); + throw new AnalysisException(message); + } } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsDisksTableValuedFunction.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsDisksTableValuedFunction.java index cc7ff82b8fb0e1..66ac253e88d00c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsDisksTableValuedFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsDisksTableValuedFunction.java @@ -18,8 +18,14 @@ package org.apache.doris.tablefunction; import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.thrift.TFrontendsMetadataParams; import org.apache.doris.thrift.TMetaScanRange; import org.apache.doris.thrift.TMetadataType; @@ -67,6 +73,12 @@ public FrontendsDisksTableValuedFunction(Map params) throws Anal if (params.size() != 0) { throw new AnalysisException("frontends_disks table-valued-function does not support any params"); } + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), + InternalCatalog.INTERNAL_CATALOG_NAME, InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT)) { + String message = ErrorCode.ERR_DB_ACCESS_DENIED_ERROR.formatErrorMsg( + PrivPredicate.SELECT.getPrivs().toString(), InfoSchemaDb.DATABASE_NAME); + throw new AnalysisException(message); + } } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsTableValuedFunction.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsTableValuedFunction.java index aded1076a83d03..06d323bc66c802 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsTableValuedFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/FrontendsTableValuedFunction.java @@ -18,8 +18,14 @@ package org.apache.doris.tablefunction; import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.thrift.TFrontendsMetadataParams; import org.apache.doris.thrift.TMetaScanRange; import org.apache.doris.thrift.TMetadataType; @@ -76,6 +82,12 @@ public FrontendsTableValuedFunction(Map params) throws AnalysisE if (params.size() != 0) { throw new AnalysisException("frontends table-valued-function does not support any params"); } + if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), + InternalCatalog.INTERNAL_CATALOG_NAME, InfoSchemaDb.DATABASE_NAME, PrivPredicate.SELECT)) { + String message = ErrorCode.ERR_DB_ACCESS_DENIED_ERROR.formatErrorMsg( + PrivPredicate.SELECT.getPrivs().toString(), InfoSchemaDb.DATABASE_NAME); + throw new AnalysisException(message); + } } @Override diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowBackendsStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowBackendsStmtTest.java index aeb19ef73ef171..c46c6428b96be3 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowBackendsStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowBackendsStmtTest.java @@ -55,7 +55,7 @@ public void testAnalyze() throws Exception { AtomicBoolean privilege = new AtomicBoolean(false); new MockUp() { @Mock - public boolean checkGlobalPriv(ConnectContext ctx, PrivPredicate wanted) { + public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { return privilege.get(); } }; diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFrontendsStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFrontendsStmtTest.java new file mode 100644 index 00000000000000..ebbe555d8cb1fe --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFrontendsStmtTest.java @@ -0,0 +1,68 @@ +// 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.analysis; + +import org.apache.doris.common.AnalysisException; +import org.apache.doris.mysql.privilege.AccessControllerManager; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; + +import mockit.Mock; +import mockit.MockUp; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ShowFrontendsStmtTest { + private Analyzer analyzer; + private ConnectContext ctx = new ConnectContext(); + + @Before + public void setUp() { + analyzer = AccessTestUtil.fetchAdminAnalyzer(true); + ctx.setSessionVariable(new SessionVariable()); + ctx.setThreadLocalInfo(); + } + + @After + public void tearDown() { + ConnectContext.remove(); + } + + @Test + public void testAnalyze() throws Exception { + AtomicBoolean privilege = new AtomicBoolean(false); + new MockUp() { + @Mock + public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { + return privilege.get(); + } + }; + + ShowFrontendsStmt stmt = new ShowFrontendsStmt(); + Assertions.assertThrows(AnalysisException.class, () -> stmt.analyze(analyzer)); + + privilege.set(true); + stmt.analyze(analyzer); + } + +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java new file mode 100644 index 00000000000000..6e4b03d2cded23 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java @@ -0,0 +1,118 @@ +// 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.trees.plans.commands; + +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.datasource.CatalogMgr; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.AccessControllerManager; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; + +import mockit.Expectations; +import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ShowBackendsCommandTest { + private static final String internalCtl = InternalCatalog.INTERNAL_CATALOG_NAME; + private static final String infoDB = InfoSchemaDb.DATABASE_NAME; + + @Mocked + private Env env; + @Mocked + private AccessControllerManager accessControllerManager; + @Mocked + private ConnectContext ctx; + @Mocked + private InternalCatalog catalog; + @Mocked + private CatalogMgr catalogMgr; + + private void runBefore() throws Exception { + new Expectations() { + { + Env.getCurrentEnv(); + minTimes = 0; + result = env; + + env.getAccessManager(); + minTimes = 0; + result = accessControllerManager; + + env.getCatalogMgr(); + minTimes = 0; + result = catalogMgr; + + catalogMgr.getCatalog(anyString); + minTimes = 0; + result = catalog; + + ConnectContext.get(); + minTimes = 0; + result = ctx; + + accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); + minTimes = 0; + result = true; + } + }; + } + + @Test + public void testNormal() throws Exception { + runBefore(); + ShowBackendsCommand command = new ShowBackendsCommand(); + Assertions.assertDoesNotThrow(() -> command.doRun(ctx, null)); + } + + @Test + public void testNoPrivilege() throws Exception { + new Expectations() { + { + Env.getCurrentEnv(); + minTimes = 0; + result = env; + + env.getAccessManager(); + minTimes = 0; + result = accessControllerManager; + + env.getCatalogMgr(); + minTimes = 0; + result = catalogMgr; + + catalogMgr.getCatalog(anyString); + minTimes = 0; + result = catalog; + + ConnectContext.get(); + minTimes = 0; + result = ctx; + + accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); + minTimes = 0; + result = false; + } + }; + ShowBackendsCommand command = new ShowBackendsCommand(); + Assertions.assertThrows(AnalysisException.class, () -> command.doRun(ctx, null)); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java new file mode 100644 index 00000000000000..294b43d3960a46 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java @@ -0,0 +1,118 @@ +// 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.trees.plans.commands; + +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.InfoSchemaDb; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.datasource.CatalogMgr; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.AccessControllerManager; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.qe.ConnectContext; + +import mockit.Expectations; +import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ShowFrontendsCommandTest { + private static final String internalCtl = InternalCatalog.INTERNAL_CATALOG_NAME; + private static final String infoDB = InfoSchemaDb.DATABASE_NAME; + + @Mocked + private Env env; + @Mocked + private ConnectContext ctx; + @Mocked + private AccessControllerManager accessControllerManager; + @Mocked + private InternalCatalog catalog; + @Mocked + private CatalogMgr catalogMgr; + + private void runBefore() throws Exception { + new Expectations() { + { + Env.getCurrentEnv(); + minTimes = 0; + result = env; + + env.getAccessManager(); + minTimes = 0; + result = accessControllerManager; + + env.getCatalogMgr(); + minTimes = 0; + result = catalogMgr; + + catalogMgr.getCatalog(anyString); + minTimes = 0; + result = catalog; + + ConnectContext.get(); + minTimes = 0; + result = ctx; + + accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); + minTimes = 0; + result = true; + } + }; + } + + @Test + public void testNormal() throws Exception { + runBefore(); + ShowFrontendsCommand command = new ShowFrontendsCommand(null); + Assertions.assertDoesNotThrow(() -> command.doRun(ctx, null)); + } + + @Test + public void testNoPrivilege() throws Exception { + new Expectations() { + { + Env.getCurrentEnv(); + minTimes = 0; + result = env; + + env.getAccessManager(); + minTimes = 0; + result = accessControllerManager; + + env.getCatalogMgr(); + minTimes = 0; + result = catalogMgr; + + catalogMgr.getCatalog(anyString); + minTimes = 0; + result = catalog; + + ConnectContext.get(); + minTimes = 0; + result = ctx; + + accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); + minTimes = 0; + result = false; + } + }; + ShowFrontendsCommand command = new ShowFrontendsCommand(null); + Assertions.assertThrows(AnalysisException.class, () -> command.doRun(ctx, null)); + } +} diff --git a/regression-test/suites/auth_call/test_show_backend_auth.groovy b/regression-test/suites/auth_call/test_show_backend_auth.groovy index 13e1fa4fbe480c..627e28c57d1bd7 100644 --- a/regression-test/suites/auth_call/test_show_backend_auth.groovy +++ b/regression-test/suites/auth_call/test_show_backend_auth.groovy @@ -32,14 +32,26 @@ suite("test_show_backend_auth","p0,auth_call") { try_sql("DROP USER ${user}") sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'""" sql """grant select_priv on regression_test to ${user}""" + sql """grant select_priv on internal.information_schema.* to ${user}""" + def show_grants_result = sql """show grants for ${user}""" + logger.info("show grants result: " + show_grants_result) + sql """revoke select_priv on internal.information_schema.* from ${user}""" connect(user, "${pwd}", context.config.jdbcUrl) { + + try { + def show_result = sql """SHOW BACKENDS""" + logger.info("show_result: " + show_result) + } catch (Exception e) { + logger.info("show_result: " + e) + e.printStackTrace() + } test { sql """SHOW BACKENDS""" exception "denied" } } - sql """grant node_priv on *.*.* to ${user}""" + sql """grant select_priv on internal.information_schema.* to ${user}""" connect(user, "${pwd}", context.config.jdbcUrl) { def res = sql """SHOW BACKENDS""" assertTrue(res.size() > 0) diff --git a/regression-test/suites/auth_call/test_show_frontend_auth.groovy b/regression-test/suites/auth_call/test_show_frontend_auth.groovy index 87f8e9c7c09a68..120698039705b2 100644 --- a/regression-test/suites/auth_call/test_show_frontend_auth.groovy +++ b/regression-test/suites/auth_call/test_show_frontend_auth.groovy @@ -32,8 +32,19 @@ suite("test_show_frontend_auth","p0,auth_call") { try_sql("DROP USER ${user}") sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'""" sql """grant select_priv on regression_test to ${user}""" + sql """grant select_priv on internal.information_schema.* to ${user}""" + def show_grants_result = sql """show grants for ${user}""" + logger.info("show grants result: " + show_grants_result) + sql """revoke select_priv on internal.information_schema.* from ${user}""" connect(user, "${pwd}", context.config.jdbcUrl) { + try { + def show_result = sql """SHOW frontends""" + logger.info("show_result: " + show_result) + } catch (Exception e) { + logger.info("show_result: " + e) + e.printStackTrace() + } test { sql """SHOW frontends""" exception "denied" @@ -43,7 +54,7 @@ suite("test_show_frontend_auth","p0,auth_call") { exception "denied" } } - sql """grant node_priv on *.*.* to ${user}""" + sql """grant select_priv on internal.information_schema.* to ${user}""" connect(user, "${pwd}", context.config.jdbcUrl) { def res = sql """SHOW frontends""" assertTrue(res.size() > 0) From 262ff662c83681fb10972d53fe15a1c00bf832f6 Mon Sep 17 00:00:00 2001 From: zhangdong Date: Wed, 25 Jun 2025 10:24:58 +0800 Subject: [PATCH 2/2] 1 --- .../commands/ShowBackendsCommandTest.java | 118 ------------------ .../commands/ShowFrontendsCommandTest.java | 118 ------------------ 2 files changed, 236 deletions(-) delete mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java delete mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java deleted file mode 100644 index 6e4b03d2cded23..00000000000000 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowBackendsCommandTest.java +++ /dev/null @@ -1,118 +0,0 @@ -// 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.trees.plans.commands; - -import org.apache.doris.catalog.Env; -import org.apache.doris.catalog.InfoSchemaDb; -import org.apache.doris.common.AnalysisException; -import org.apache.doris.datasource.CatalogMgr; -import org.apache.doris.datasource.InternalCatalog; -import org.apache.doris.mysql.privilege.AccessControllerManager; -import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.qe.ConnectContext; - -import mockit.Expectations; -import mockit.Mocked; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ShowBackendsCommandTest { - private static final String internalCtl = InternalCatalog.INTERNAL_CATALOG_NAME; - private static final String infoDB = InfoSchemaDb.DATABASE_NAME; - - @Mocked - private Env env; - @Mocked - private AccessControllerManager accessControllerManager; - @Mocked - private ConnectContext ctx; - @Mocked - private InternalCatalog catalog; - @Mocked - private CatalogMgr catalogMgr; - - private void runBefore() throws Exception { - new Expectations() { - { - Env.getCurrentEnv(); - minTimes = 0; - result = env; - - env.getAccessManager(); - minTimes = 0; - result = accessControllerManager; - - env.getCatalogMgr(); - minTimes = 0; - result = catalogMgr; - - catalogMgr.getCatalog(anyString); - minTimes = 0; - result = catalog; - - ConnectContext.get(); - minTimes = 0; - result = ctx; - - accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); - minTimes = 0; - result = true; - } - }; - } - - @Test - public void testNormal() throws Exception { - runBefore(); - ShowBackendsCommand command = new ShowBackendsCommand(); - Assertions.assertDoesNotThrow(() -> command.doRun(ctx, null)); - } - - @Test - public void testNoPrivilege() throws Exception { - new Expectations() { - { - Env.getCurrentEnv(); - minTimes = 0; - result = env; - - env.getAccessManager(); - minTimes = 0; - result = accessControllerManager; - - env.getCatalogMgr(); - minTimes = 0; - result = catalogMgr; - - catalogMgr.getCatalog(anyString); - minTimes = 0; - result = catalog; - - ConnectContext.get(); - minTimes = 0; - result = ctx; - - accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); - minTimes = 0; - result = false; - } - }; - ShowBackendsCommand command = new ShowBackendsCommand(); - Assertions.assertThrows(AnalysisException.class, () -> command.doRun(ctx, null)); - } -} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java deleted file mode 100644 index 294b43d3960a46..00000000000000 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFrontendsCommandTest.java +++ /dev/null @@ -1,118 +0,0 @@ -// 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.trees.plans.commands; - -import org.apache.doris.catalog.Env; -import org.apache.doris.catalog.InfoSchemaDb; -import org.apache.doris.common.AnalysisException; -import org.apache.doris.datasource.CatalogMgr; -import org.apache.doris.datasource.InternalCatalog; -import org.apache.doris.mysql.privilege.AccessControllerManager; -import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.qe.ConnectContext; - -import mockit.Expectations; -import mockit.Mocked; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ShowFrontendsCommandTest { - private static final String internalCtl = InternalCatalog.INTERNAL_CATALOG_NAME; - private static final String infoDB = InfoSchemaDb.DATABASE_NAME; - - @Mocked - private Env env; - @Mocked - private ConnectContext ctx; - @Mocked - private AccessControllerManager accessControllerManager; - @Mocked - private InternalCatalog catalog; - @Mocked - private CatalogMgr catalogMgr; - - private void runBefore() throws Exception { - new Expectations() { - { - Env.getCurrentEnv(); - minTimes = 0; - result = env; - - env.getAccessManager(); - minTimes = 0; - result = accessControllerManager; - - env.getCatalogMgr(); - minTimes = 0; - result = catalogMgr; - - catalogMgr.getCatalog(anyString); - minTimes = 0; - result = catalog; - - ConnectContext.get(); - minTimes = 0; - result = ctx; - - accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); - minTimes = 0; - result = true; - } - }; - } - - @Test - public void testNormal() throws Exception { - runBefore(); - ShowFrontendsCommand command = new ShowFrontendsCommand(null); - Assertions.assertDoesNotThrow(() -> command.doRun(ctx, null)); - } - - @Test - public void testNoPrivilege() throws Exception { - new Expectations() { - { - Env.getCurrentEnv(); - minTimes = 0; - result = env; - - env.getAccessManager(); - minTimes = 0; - result = accessControllerManager; - - env.getCatalogMgr(); - minTimes = 0; - result = catalogMgr; - - catalogMgr.getCatalog(anyString); - minTimes = 0; - result = catalog; - - ConnectContext.get(); - minTimes = 0; - result = ctx; - - accessControllerManager.checkDbPriv(ctx, internalCtl, infoDB, PrivPredicate.SELECT); - minTimes = 0; - result = false; - } - }; - ShowFrontendsCommand command = new ShowFrontendsCommand(null); - Assertions.assertThrows(AnalysisException.class, () -> command.doRun(ctx, null)); - } -}