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]

Reply via email to