This is an automated email from the ASF dual-hosted git repository.
gavinchou 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 d2854e125d1 [Feat](Snapshot) require root privilege for cluster
snapshot commands (#60239)
d2854e125d1 is described below
commit d2854e125d1abe2a21ea212f11b630f84252addb
Author: Jimmy <[email protected]>
AuthorDate: Wed Jan 28 15:22:54 2026 +0800
[Feat](Snapshot) require root privilege for cluster snapshot commands
(#60239)
Cluster snapshot operations are currently restricted to root user only.
Some customers need to allow ADMIN users to manage cluster snapshots
without granting root access.
Solution
Add a new configuration cluster_snapshot_min_privilege to control the
minimum privilege level:
- root (default): Only root user can execute
- admin: Users with ADMIN privilege can execute
Affects 4 cluster snapshot commands and 2 information_schema tables
(cluster_snapshots, cluster_snapshot_properties).
---
.../main/java/org/apache/doris/common/Config.java | 8 +
.../nereids/rules/analysis/UserAuthentication.java | 32 +-
.../AdminCreateClusterSnapshotCommand.java | 18 +-
.../commands/AdminDropClusterSnapshotCommand.java | 18 +-
.../AdminSetAutoClusterSnapshotCommand.java | 18 +-
...dminSetClusterSnapshotFeatureSwitchCommand.java | 18 +-
.../rules/analysis/UserAuthenticationTest.java | 396 +++++++++++++++++++++
.../AdminCreateClusterSnapshotCommandTest.java | 101 +++++-
.../AdminDropClusterSnapshotCommandTest.java | 99 +++++-
.../AdminSetAutoClusterSnapshotCommandTest.java | 103 +++++-
...SetClusterSnapshotFeatureSwitchCommandTest.java | 99 +++++-
11 files changed, 860 insertions(+), 50 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 448c7747b46..46da88b4dde 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
@@ -3761,6 +3761,14 @@ public class Config extends ConfigBase {
@ConfField(mutable = true)
public static long cloud_auto_snapshot_min_interval_seconds = 3600;
+ @ConfField(mutable = true, description = {
+ "cluster snapshot 相关操作的最低权限要求。可选值:'root'(仅 root 用户可执行)或
'admin'(ADMIN 权限用户可执行)。默认值为 'root'。",
+ "The minimum privilege required for cluster snapshot operations. "
+ + "Valid values: 'root' (only root user can execute)"
+ + " or 'admin' (users with ADMIN privilege can execute). "
+ + "Default is 'root'."})
+ public static String cluster_snapshot_min_privilege = "root";
+
@ConfField(mutable = true)
public static long multi_part_upload_part_size_in_bytes = 256 * 1024 *
1024L; // 256MB
@ConfField(mutable = true)
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 6bfe9efb3d4..9d0fbd39e4a 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,8 +17,13 @@
package org.apache.doris.nereids.rules.analysis;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.InfoSchemaDb;
import org.apache.doris.catalog.TableIf;
+import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
@@ -47,11 +52,34 @@ public class UserAuthentication {
}
String tableName = table.getName();
DatabaseIf db = table.getDatabase();
- // when table instanceof FunctionGenTable,db will be null
+ // when table instanceof FunctionGenTable, db will be null
if (db == null) {
return;
}
- String dbName = db.getFullName();
+ String dbName = ClusterNamespace.getNameFromFullName(db.getFullName());
+
+ // Special handling: cluster snapshot related tables in
information_schema
+ // require privilege based on configuration
+ if (dbName.equalsIgnoreCase(InfoSchemaDb.DATABASE_NAME)
+ && (tableName.equalsIgnoreCase("cluster_snapshots")
+ ||
tableName.equalsIgnoreCase("cluster_snapshot_properties"))) {
+ if
("admin".equalsIgnoreCase(Config.cluster_snapshot_min_privilege)) {
+ // When configured as admin, check ADMIN privilege
+ if
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(connectContext,
PrivPredicate.ADMIN)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ PrivPredicate.ADMIN.getPrivs().toString());
+ }
+ } else {
+ // Default or configured as root, check if user is root
+ UserIdentity currentUser =
connectContext.getCurrentUserIdentity();
+ if (currentUser == null || !currentUser.isRootUser()) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ "root privilege");
+ }
+ }
+ return; // privilege check passed, allow access
+ }
+
CatalogIf catalog = db.getCatalog();
if (catalog == null) {
return;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommand.java
index ebfb94a8768..425b6bb2176 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommand.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.plans.commands;
import org.apache.doris.analysis.StmtType;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.cloud.catalog.CloudEnv;
import org.apache.doris.cloud.snapshot.CloudSnapshotHandler;
@@ -73,9 +74,20 @@ public class AdminCreateClusterSnapshotCommand extends
Command implements Forwar
if (!Config.isCloudMode()) {
throw new AnalysisException("The sql is illegal in disk mode ");
}
- if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
- PrivPredicate.ADMIN.getPrivs().toString());
+ // Check privilege based on configuration
+ if ("admin".equalsIgnoreCase(Config.cluster_snapshot_min_privilege)) {
+ // When configured as admin, check ADMIN privilege
+ if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ PrivPredicate.ADMIN.getPrivs().toString());
+ }
+ } else {
+ // Default or configured as root, check if user is root
+ UserIdentity currentUser = ctx.getCurrentUserIdentity();
+ if (currentUser == null || !currentUser.isRootUser()) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ "root privilege");
+ }
}
for (Map.Entry<String, String> entry : properties.entrySet()) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommand.java
index b131f8a8cc8..a545113321e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommand.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.plans.commands;
import org.apache.doris.analysis.StmtType;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.cloud.proto.Cloud;
import org.apache.doris.cloud.rpc.MetaServiceProxy;
@@ -70,9 +71,20 @@ public class AdminDropClusterSnapshotCommand extends Command
implements ForwardW
if (!Config.isCloudMode()) {
throw new AnalysisException("The sql is illegal in disk mode ");
}
- if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
- PrivPredicate.ADMIN.getPrivs().toString());
+ // Check privilege based on configuration
+ if ("admin".equalsIgnoreCase(Config.cluster_snapshot_min_privilege)) {
+ // When configured as admin, check ADMIN privilege
+ if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ PrivPredicate.ADMIN.getPrivs().toString());
+ }
+ } else {
+ // Default or configured as root, check if user is root
+ UserIdentity currentUser = ctx.getCurrentUserIdentity();
+ if (currentUser == null || !currentUser.isRootUser()) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ "root privilege");
+ }
}
if (key == null || !key.equalsIgnoreCase(SNAPSHOT_ID)) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommand.java
index b450ada674f..2a873c32790 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommand.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.plans.commands;
import org.apache.doris.analysis.StmtType;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.cloud.catalog.CloudEnv;
import org.apache.doris.cloud.proto.Cloud;
@@ -92,9 +93,20 @@ public class AdminSetAutoClusterSnapshotCommand extends
Command implements Forwa
if (!Config.isCloudMode()) {
throw new AnalysisException("The sql is illegal in disk mode ");
}
- if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
- PrivPredicate.ADMIN.getPrivs().toString());
+ // Check privilege based on configuration
+ if ("admin".equalsIgnoreCase(Config.cluster_snapshot_min_privilege)) {
+ // When configured as admin, check ADMIN privilege
+ if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ PrivPredicate.ADMIN.getPrivs().toString());
+ }
+ } else {
+ // Default or configured as root, check if user is root
+ UserIdentity currentUser = ctx.getCurrentUserIdentity();
+ if (currentUser == null || !currentUser.isRootUser()) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ "root privilege");
+ }
}
if (properties.isEmpty()) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommand.java
index 7b873ae65dd..9b2d8612315 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommand.java
@@ -18,6 +18,7 @@
package org.apache.doris.nereids.trees.plans.commands;
import org.apache.doris.analysis.StmtType;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.cloud.catalog.CloudEnv;
import org.apache.doris.cloud.proto.Cloud;
@@ -73,9 +74,20 @@ public class AdminSetClusterSnapshotFeatureSwitchCommand
extends Command impleme
if (!Config.isCloudMode()) {
throw new AnalysisException("The sql is illegal in disk mode ");
}
- if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
- PrivPredicate.ADMIN.getPrivs().toString());
+ // Check privilege based on configuration
+ if ("admin".equalsIgnoreCase(Config.cluster_snapshot_min_privilege)) {
+ // When configured as admin, check ADMIN privilege
+ if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx,
PrivPredicate.ADMIN)) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ PrivPredicate.ADMIN.getPrivs().toString());
+ }
+ } else {
+ // Default or configured as root, check if user is root
+ UserIdentity currentUser = ctx.getCurrentUserIdentity();
+ if (currentUser == null || !currentUser.isRootUser()) {
+
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR,
+ "root privilege");
+ }
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserAuthenticationTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserAuthenticationTest.java
new file mode 100644
index 00000000000..b026dad95d4
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserAuthenticationTest.java
@@ -0,0 +1,396 @@
+// 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.analysis.UserIdentity;
+import org.apache.doris.catalog.DatabaseIf;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.InfoSchemaDb;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
+import org.apache.doris.datasource.CatalogIf;
+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.Expectations;
+import mockit.Mocked;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test for UserAuthentication privilege checks.
+ */
+public class UserAuthenticationTest {
+ @Mocked
+ private Env env;
+ @Mocked
+ private ConnectContext connectContext;
+ @Mocked
+ private AccessControllerManager accessControllerManager;
+ @Mocked
+ private SessionVariable sessionVariable;
+ @Mocked
+ private TableIf table;
+ @Mocked
+ private DatabaseIf db;
+ @Mocked
+ private CatalogIf catalog;
+
+ private String originalMinPrivilege;
+
+ @BeforeEach
+ public void setUp() {
+ originalMinPrivilege = Config.cluster_snapshot_min_privilege;
+ }
+
+ @AfterEach
+ public void tearDown() {
+ Config.cluster_snapshot_min_privilege = originalMinPrivilege;
+ }
+
+ /**
+ * Test that a table named "cluster_snapshots" in a normal database (not
information_schema)
+ * does NOT trigger the special privilege check for cluster snapshot
tables.
+ * This verifies that only information_schema.cluster_snapshots requires
special privileges.
+ */
+ @Test
+ public void testSameNameTableInNormalDbNotTriggerSpecialCheck() throws
Exception {
+ // Set to root mode - if special check is triggered, non-root user
would be denied
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ // Table setup - same name as cluster snapshot table but in a
normal database
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshots"; // Same name as the special
table
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ // Database is NOT information_schema, it's a normal user
database
+ db.getFullName();
+ minTimes = 0;
+ result = "mydb"; // Normal database, not information_schema
+
+ db.getCatalog();
+ minTimes = 0;
+ result = catalog;
+
+ catalog.getName();
+ minTimes = 0;
+ result = "internal";
+
+ // ConnectContext setup
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ connectContext.getEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ // Normal SELECT privilege check should be called (not special
root check)
+ // and should return true to allow access
+ accessControllerManager.checkTblPriv(connectContext,
"internal", "mydb",
+ "cluster_snapshots", PrivPredicate.SELECT);
+ minTimes = 1; // This MUST be called, proving we're using
normal privilege check
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
+ }
+ };
+
+ // Should NOT throw exception - normal user can access
mydb.cluster_snapshots
+ // because it's not the special information_schema table
+ Assertions.assertDoesNotThrow(() ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+
+ /**
+ * Test that a table named "cluster_snapshot_properties" in a normal
database
+ * does NOT trigger the special privilege check.
+ */
+ @Test
+ public void testSameNamePropertiesTableInNormalDbNotTriggerSpecialCheck()
throws Exception {
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshot_properties";
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ db.getFullName();
+ minTimes = 0;
+ result = "user_database";
+
+ db.getCatalog();
+ minTimes = 0;
+ result = catalog;
+
+ catalog.getName();
+ minTimes = 0;
+ result = "internal";
+
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ connectContext.getEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkTblPriv(connectContext,
"internal", "user_database",
+ "cluster_snapshot_properties", PrivPredicate.SELECT);
+ minTimes = 1;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
+ }
+ };
+
+ Assertions.assertDoesNotThrow(() ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+
+ /**
+ * Test that information_schema.cluster_snapshots DOES trigger special
privilege check
+ * and denies non-root user in root mode.
+ */
+ @Test
+ public void testInfoSchemaClusterSnapshotsRequiresRootPrivilege() {
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshots";
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ // This IS information_schema
+ db.getFullName();
+ minTimes = 0;
+ result = InfoSchemaDb.DATABASE_NAME;
+
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
+ }
+ };
+
+ // Should throw AnalysisException because non-root user cannot access
+ // information_schema.cluster_snapshots in root mode
+ Assertions.assertThrows(AnalysisException.class, () ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+
+ /**
+ * Test that information_schema.cluster_snapshots allows root user.
+ */
+ @Test
+ public void testInfoSchemaClusterSnapshotsAllowsRootUser() {
+ Config.cluster_snapshot_min_privilege = "root";
+
+ new Expectations() {
+ {
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshots";
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ db.getFullName();
+ minTimes = 0;
+ result = InfoSchemaDb.DATABASE_NAME;
+
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = UserIdentity.ROOT;
+ }
+ };
+
+ // Root user should be able to access
+ Assertions.assertDoesNotThrow(() ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+
+ /**
+ * Test that cluster:information_schema.cluster_snapshots (with cluster
prefix)
+ * DOES trigger special privilege check.
+ * This verifies ClusterNamespace.getNameFromFullName correctly strips the
cluster prefix.
+ */
+ @Test
+ public void testInfoSchemaWithClusterPrefixTriggersSpecialCheck() {
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshots";
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ // Database name with cluster prefix -
ClusterNamespace.getNameFromFullName
+ // should strip "default_cluster:" and return
"information_schema"
+ db.getFullName();
+ minTimes = 0;
+ result = "default_cluster:information_schema";
+
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
+ }
+ };
+
+ // Should throw AnalysisException because after stripping cluster
prefix,
+ // the db name is "information_schema", which triggers special
privilege check
+ Assertions.assertThrows(AnalysisException.class, () ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+
+ /**
+ * Test that information_schema.cluster_snapshots allows admin user in
admin mode.
+ */
+ @Test
+ public void testInfoSchemaClusterSnapshotsAllowsAdminInAdminMode() {
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity adminUser = new UserIdentity("admin", "%");
+ adminUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ table.getName();
+ minTimes = 0;
+ result = "cluster_snapshots";
+
+ table.getDatabase();
+ minTimes = 0;
+ result = db;
+
+ db.getFullName();
+ minTimes = 0;
+ result = InfoSchemaDb.DATABASE_NAME;
+
+ connectContext.getSessionVariable();
+ minTimes = 0;
+ result = sessionVariable;
+
+ sessionVariable.isPlayNereidsDump();
+ minTimes = 0;
+ result = false;
+
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ minTimes = 0;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = adminUser;
+ }
+ };
+
+ // Admin user should be able to access in admin mode
+ Assertions.assertDoesNotThrow(() ->
+ UserAuthentication.checkPermission(table, connectContext,
null));
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommandTest.java
index e832296dcf8..c0ecf74a763 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommandTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminCreateClusterSnapshotCommandTest.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
@@ -28,7 +29,9 @@ import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableMap;
import mockit.Expectations;
import mockit.Mocked;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -40,9 +43,21 @@ public class AdminCreateClusterSnapshotCommandTest {
@Mocked
private Env env;
@Mocked
- private AccessControllerManager accessControllerManager;
- @Mocked
private ConnectContext connectContext;
+ @Mocked
+ private AccessControllerManager accessControllerManager;
+
+ private String originalMinPrivilege;
+
+ @BeforeEach
+ public void setUp() {
+ originalMinPrivilege = Config.cluster_snapshot_min_privilege;
+ }
+
+ @AfterEach
+ public void tearDown() {
+ Config.cluster_snapshot_min_privilege = originalMinPrivilege;
+ }
private void runBefore() throws Exception {
new Expectations() {
@@ -51,10 +66,6 @@ public class AdminCreateClusterSnapshotCommandTest {
minTimes = 0;
result = env;
- env.getAccessManager();
- minTimes = 0;
- result = accessControllerManager;
-
ConnectContext.get();
minTimes = 0;
result = connectContext;
@@ -63,9 +74,10 @@ public class AdminCreateClusterSnapshotCommandTest {
minTimes = 0;
result = true;
- accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ // Mock root user for privilege check
+ connectContext.getCurrentUserIdentity();
minTimes = 0;
- result = true;
+ result = UserIdentity.ROOT;
}
};
}
@@ -105,7 +117,74 @@ public class AdminCreateClusterSnapshotCommandTest {
}
@Test
- public void testValidateNoPriviledge() {
+ public void testValidateNoPrivilegeRootMode() {
+ // Test root mode (default): admin user should be denied
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity nonRootUser = new UserIdentity("admin", "%");
+ nonRootUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = nonRootUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ Map<String, String> properties = new HashMap<>();
+ AdminCreateClusterSnapshotCommand command = new
AdminCreateClusterSnapshotCommand(properties);
+ Assertions.assertThrows(AnalysisException.class, () ->
command.validate(connectContext),
+ "Access denied; you need (at least one of) the (root
privilege) privilege(s) for this operation");
+ }
+
+ @Test
+ public void testValidateAdminModeWithAdminUser() {
+ // Test admin mode: admin user with ADMIN privilege should be allowed
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity adminUser = new UserIdentity("admin", "%");
+ adminUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ minTimes = 0;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = adminUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ Map<String, String> properties = ImmutableMap.of("ttl", "3600",
"label", "test");
+ AdminCreateClusterSnapshotCommand command = new
AdminCreateClusterSnapshotCommand(properties);
+ Assertions.assertDoesNotThrow(() -> command.validate(connectContext));
+ }
+
+ @Test
+ public void testValidateAdminModeWithNormalUser() {
+ // Test admin mode: normal user without ADMIN privilege should be
denied
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
new Expectations() {
{
Env.getCurrentEnv();
@@ -119,6 +198,10 @@ public class AdminCreateClusterSnapshotCommandTest {
accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
minTimes = 0;
result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
}
};
Config.deploy_mode = "cloud";
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommandTest.java
index f9a289e7e90..49a13623b61 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommandTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminDropClusterSnapshotCommandTest.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
@@ -26,16 +27,30 @@ import org.apache.doris.qe.ConnectContext;
import mockit.Expectations;
import mockit.Mocked;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class AdminDropClusterSnapshotCommandTest {
@Mocked
private Env env;
@Mocked
- private AccessControllerManager accessControllerManager;
- @Mocked
private ConnectContext connectContext;
+ @Mocked
+ private AccessControllerManager accessControllerManager;
+
+ private String originalMinPrivilege;
+
+ @BeforeEach
+ public void setUp() {
+ originalMinPrivilege = Config.cluster_snapshot_min_privilege;
+ }
+
+ @AfterEach
+ public void tearDown() {
+ Config.cluster_snapshot_min_privilege = originalMinPrivilege;
+ }
private void runBefore() throws Exception {
new Expectations() {
@@ -44,10 +59,6 @@ public class AdminDropClusterSnapshotCommandTest {
minTimes = 0;
result = env;
- env.getAccessManager();
- minTimes = 0;
- result = accessControllerManager;
-
ConnectContext.get();
minTimes = 0;
result = connectContext;
@@ -56,9 +67,10 @@ public class AdminDropClusterSnapshotCommandTest {
minTimes = 0;
result = true;
- accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ // Mock root user for privilege check
+ connectContext.getCurrentUserIdentity();
minTimes = 0;
- result = true;
+ result = UserIdentity.ROOT;
}
};
}
@@ -94,7 +106,72 @@ public class AdminDropClusterSnapshotCommandTest {
}
@Test
- public void testValidateNoPriviledge() {
+ public void testValidateNoPrivilegeRootMode() {
+ // Test root mode (default): admin user should be denied
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity nonRootUser = new UserIdentity("admin", "%");
+ nonRootUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = nonRootUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ AdminDropClusterSnapshotCommand command = new
AdminDropClusterSnapshotCommand("snapshot_id", "323741");
+ Assertions.assertThrows(AnalysisException.class, () ->
command.validate(connectContext),
+ "Access denied; you need (at least one of) the (root
privilege) privilege(s) for this operation");
+ }
+
+ @Test
+ public void testValidateAdminModeWithAdminUser() {
+ // Test admin mode: admin user with ADMIN privilege should be allowed
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity adminUser = new UserIdentity("admin", "%");
+ adminUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ minTimes = 0;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = adminUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ AdminDropClusterSnapshotCommand command = new
AdminDropClusterSnapshotCommand("snapshot_id", "323741");
+ Assertions.assertDoesNotThrow(() -> command.validate(connectContext));
+ }
+
+ @Test
+ public void testValidateAdminModeWithNormalUser() {
+ // Test admin mode: normal user without ADMIN privilege should be
denied
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
new Expectations() {
{
Env.getCurrentEnv();
@@ -108,6 +185,10 @@ public class AdminDropClusterSnapshotCommandTest {
accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
minTimes = 0;
result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
}
};
Config.deploy_mode = "cloud";
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommandTest.java
index 6779d42fce7..65c8cd8f8f6 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommandTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetAutoClusterSnapshotCommandTest.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
@@ -26,7 +27,9 @@ import org.apache.doris.qe.ConnectContext;
import mockit.Expectations;
import mockit.Mocked;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
@@ -36,9 +39,21 @@ public class AdminSetAutoClusterSnapshotCommandTest {
@Mocked
private Env env;
@Mocked
- private AccessControllerManager accessControllerManager;
- @Mocked
private ConnectContext connectContext;
+ @Mocked
+ private AccessControllerManager accessControllerManager;
+
+ private String originalMinPrivilege;
+
+ @BeforeEach
+ public void setUp() {
+ originalMinPrivilege = Config.cluster_snapshot_min_privilege;
+ }
+
+ @AfterEach
+ public void tearDown() {
+ Config.cluster_snapshot_min_privilege = originalMinPrivilege;
+ }
private void runBefore() throws Exception {
new Expectations() {
@@ -47,10 +62,6 @@ public class AdminSetAutoClusterSnapshotCommandTest {
minTimes = 0;
result = env;
- env.getAccessManager();
- minTimes = 0;
- result = accessControllerManager;
-
ConnectContext.get();
minTimes = 0;
result = connectContext;
@@ -59,9 +70,10 @@ public class AdminSetAutoClusterSnapshotCommandTest {
minTimes = 0;
result = true;
- accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ // Mock root user for privilege check
+ connectContext.getCurrentUserIdentity();
minTimes = 0;
- result = true;
+ result = UserIdentity.ROOT;
}
};
}
@@ -117,7 +129,76 @@ public class AdminSetAutoClusterSnapshotCommandTest {
}
@Test
- public void testValidateNoPriviledge() {
+ public void testValidateNoPrivilegeRootMode() {
+ // Test root mode (default): admin user should be denied
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity nonRootUser = new UserIdentity("admin", "%");
+ nonRootUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = nonRootUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ Map<String, String> properties = new HashMap<>();
+ AdminSetAutoClusterSnapshotCommand command = new
AdminSetAutoClusterSnapshotCommand(properties);
+ Assertions.assertThrows(AnalysisException.class, () ->
command.validate(connectContext),
+ "Access denied; you need (at least one of) the (root
privilege) privilege(s) for this operation");
+ }
+
+ @Test
+ public void testValidateAdminModeWithAdminUser() {
+ // Test admin mode: admin user with ADMIN privilege should be allowed
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity adminUser = new UserIdentity("admin", "%");
+ adminUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ minTimes = 0;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = adminUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ Map<String, String> properties = new HashMap<>();
+ properties.put("max_reserved_snapshots", "10");
+ properties.put("snapshot_interval_seconds", "3600");
+ AdminSetAutoClusterSnapshotCommand command = new
AdminSetAutoClusterSnapshotCommand(properties);
+ Assertions.assertDoesNotThrow(() -> command.validate(connectContext));
+ }
+
+ @Test
+ public void testValidateAdminModeWithNormalUser() {
+ // Test admin mode: normal user without ADMIN privilege should be
denied
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
new Expectations() {
{
Env.getCurrentEnv();
@@ -131,6 +212,10 @@ public class AdminSetAutoClusterSnapshotCommandTest {
accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
minTimes = 0;
result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
}
};
Config.deploy_mode = "cloud";
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommandTest.java
index 63121ebc01b..a36a3493369 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommandTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetClusterSnapshotFeatureSwitchCommandTest.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.plans.commands;
+import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
@@ -26,16 +27,30 @@ import org.apache.doris.qe.ConnectContext;
import mockit.Expectations;
import mockit.Mocked;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class AdminSetClusterSnapshotFeatureSwitchCommandTest {
@Mocked
private Env env;
@Mocked
- private AccessControllerManager accessControllerManager;
- @Mocked
private ConnectContext connectContext;
+ @Mocked
+ private AccessControllerManager accessControllerManager;
+
+ private String originalMinPrivilege;
+
+ @BeforeEach
+ public void setUp() {
+ originalMinPrivilege = Config.cluster_snapshot_min_privilege;
+ }
+
+ @AfterEach
+ public void tearDown() {
+ Config.cluster_snapshot_min_privilege = originalMinPrivilege;
+ }
private void runBefore() throws Exception {
new Expectations() {
@@ -44,10 +59,6 @@ public class AdminSetClusterSnapshotFeatureSwitchCommandTest
{
minTimes = 0;
result = env;
- env.getAccessManager();
- minTimes = 0;
- result = accessControllerManager;
-
ConnectContext.get();
minTimes = 0;
result = connectContext;
@@ -56,9 +67,10 @@ public class AdminSetClusterSnapshotFeatureSwitchCommandTest
{
minTimes = 0;
result = true;
- accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ // Mock root user for privilege check
+ connectContext.getCurrentUserIdentity();
minTimes = 0;
- result = true;
+ result = UserIdentity.ROOT;
}
};
}
@@ -81,7 +93,72 @@ public class AdminSetClusterSnapshotFeatureSwitchCommandTest
{
}
@Test
- public void testValidateNoPriviledge() {
+ public void testValidateNoPrivilegeRootMode() {
+ // Test root mode (default): admin user should be denied
+ Config.cluster_snapshot_min_privilege = "root";
+
+ UserIdentity nonRootUser = new UserIdentity("admin", "%");
+ nonRootUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = nonRootUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ AdminSetClusterSnapshotFeatureSwitchCommand command = new
AdminSetClusterSnapshotFeatureSwitchCommand(true);
+ Assertions.assertThrows(AnalysisException.class, () ->
command.validate(connectContext),
+ "Access denied; you need (at least one of) the (root
privilege) privilege(s) for this operation");
+ }
+
+ @Test
+ public void testValidateAdminModeWithAdminUser() {
+ // Test admin mode: admin user with ADMIN privilege should be allowed
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity adminUser = new UserIdentity("admin", "%");
+ adminUser.setIsAnalyzed();
+
+ new Expectations() {
+ {
+ Env.getCurrentEnv();
+ minTimes = 0;
+ result = env;
+
+ env.getAccessManager();
+ minTimes = 0;
+ result = accessControllerManager;
+
+ accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
+ minTimes = 0;
+ result = true;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = adminUser;
+ }
+ };
+ Config.deploy_mode = "cloud";
+
+ AdminSetClusterSnapshotFeatureSwitchCommand command = new
AdminSetClusterSnapshotFeatureSwitchCommand(true);
+ Assertions.assertDoesNotThrow(() -> command.validate(connectContext));
+ }
+
+ @Test
+ public void testValidateAdminModeWithNormalUser() {
+ // Test admin mode: normal user without ADMIN privilege should be
denied
+ Config.cluster_snapshot_min_privilege = "admin";
+
+ UserIdentity normalUser = new UserIdentity("normal_user", "%");
+ normalUser.setIsAnalyzed();
+
new Expectations() {
{
Env.getCurrentEnv();
@@ -95,6 +172,10 @@ public class
AdminSetClusterSnapshotFeatureSwitchCommandTest {
accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN);
minTimes = 0;
result = false;
+
+ connectContext.getCurrentUserIdentity();
+ minTimes = 0;
+ result = normalUser;
}
};
Config.deploy_mode = "cloud";
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]