This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new b69fc36110d branch-4.1: [fix](auth) Treat only root@'%' as root in SET 
PASSWORD and ALTER USER (#68634)
b69fc36110d is described below

commit b69fc36110d7c383e09d5b158df67c6e0494a69f
Author: Calvin Kirs <[email protected]>
AuthorDate: Tue Sep 29 23:35:06 2026 +0800

    branch-4.1: [fix](auth) Treat only root@'%' as root in SET PASSWORD and 
ALTER USER (#68634)
    
    https://github.com/apache/doris/pull/68559
---
 .../trees/plans/commands/info/AlterUserInfo.java   |   6 +-
 .../trees/plans/commands/info/SetPassVarOp.java    |   3 +-
 .../doris/mysql/privilege/SystemRootUserTest.java  | 108 +++++++++++++++++++++
 .../suites/account_p0/test_system_user.groovy      |  31 ++++++
 4 files changed, 141 insertions(+), 7 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java
index bf0a1aa060b..34544f5fe53 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java
@@ -23,12 +23,10 @@ import org.apache.doris.analysis.TlsOptions;
 import org.apache.doris.analysis.UserDesc;
 import org.apache.doris.analysis.UserIdentity;
 import org.apache.doris.catalog.Env;
-import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.UserException;
-import org.apache.doris.mysql.privilege.Auth;
 import org.apache.doris.mysql.privilege.PasswordPolicy;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
@@ -132,9 +130,7 @@ public class AlterUserInfo {
                 + "actual number of type is " + ops.size());
         }
 
-        if (userDesc.getUserIdent().getQualifiedUser().equals(Auth.ROOT_USER)
-                && 
!ClusterNamespace.getNameFromFullName(ConnectContext.get().getQualifiedUser())
-                .equals(Auth.ROOT_USER)) {
+        if (userDesc.getUserIdent().isRootUser() && 
!ConnectContext.get().getCurrentUserIdentity().isRootUser()) {
             throw new AnalysisException("Only root user can modify root user");
         }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/SetPassVarOp.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/SetPassVarOp.java
index f142b9679a2..0453ffeb52c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/SetPassVarOp.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/SetPassVarOp.java
@@ -25,7 +25,6 @@ import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.UserException;
-import org.apache.doris.mysql.privilege.Auth;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
 
@@ -69,7 +68,7 @@ public class SetPassVarOp extends SetVarOp {
         }
 
         // 2. No user can set password for root expect for root user itself
-        if (userIdent.getQualifiedUser().equals(Auth.ROOT_USER)) {
+        if (userIdent.isRootUser()) {
             throw new AnalysisException("Can not set password for root user, 
except root itself");
         }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/SystemRootUserTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/SystemRootUserTest.java
new file mode 100644
index 00000000000..d60df7107d2
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/SystemRootUserTest.java
@@ -0,0 +1,108 @@
+// 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.mysql.privilege;
+
+import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.nereids.parser.NereidsParser;
+import org.apache.doris.nereids.trees.plans.commands.Command;
+import org.apache.doris.utframe.TestWithFeService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Only the full identity root@'%' is the system root user. An account created 
as root@'<host>' is an
+ * ordinary account: a user with GRANT privilege manages it like any other 
account, and it has no more
+ * say over root@'%' than any other non-root user.
+ */
+public class SystemRootUserTest extends TestWithFeService {
+
+    private static final String HOST = "8.8.20.39";
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        run("CREATE USER 'root'@'" + HOST + "' IDENTIFIED BY 'Pwd_a1'");
+        run("GRANT GRANT_PRIV ON *.*.* TO 'root'@'" + HOST + "'");
+        run("CREATE USER 'grant_admin'@'%'");
+        run("GRANT GRANT_PRIV ON *.*.* TO 'grant_admin'@'%'");
+    }
+
+    @Override
+    protected void runBeforeEach() throws Exception {
+        useUser(Auth.ROOT_USER);
+    }
+
+    private void run(String sql) throws Exception {
+        ((Command) new NereidsParser().parseSingle(sql)).run(connectContext, 
null);
+    }
+
+    private void assertRejected(String sql, String expectedMessage) {
+        Exception e = Assertions.assertThrows(Exception.class, () -> run(sql));
+        Assertions.assertTrue(e.getMessage().contains(expectedMessage), 
e.getMessage());
+    }
+
+    private void assertPassword(UserIdentity user, String password) {
+        Assertions.assertDoesNotThrow(
+                () -> 
Env.getCurrentEnv().getAuth().checkPlainPasswordForUserIdentity(user, password, 
null));
+    }
+
+    private UserIdentity rootAtHost() {
+        UserIdentity user = new UserIdentity(Auth.ROOT_USER, HOST);
+        user.setIsAnalyzed();
+        return user;
+    }
+
+    @Test
+    public void testRootCanSetPasswordForRootAtSpecificHost() throws Exception 
{
+        run("SET PASSWORD FOR 'root'@'" + HOST + "' = PASSWORD('Pwd_f6')");
+        assertPassword(rootAtHost(), "Pwd_f6");
+    }
+
+    @Test
+    public void testGrantUserCanSetPasswordForRootAtSpecificHost() throws 
Exception {
+        useUser("grant_admin");
+        run("SET PASSWORD FOR 'root'@'" + HOST + "' = PASSWORD('Pwd_b2')");
+        assertPassword(rootAtHost(), "Pwd_b2");
+    }
+
+    @Test
+    public void testGrantUserCanAlterRootAtSpecificHost() throws Exception {
+        useUser("grant_admin");
+        run("ALTER USER 'root'@'" + HOST + "' IDENTIFIED BY 'Pwd_c3'");
+        assertPassword(rootAtHost(), "Pwd_c3");
+    }
+
+    @Test
+    public void testGrantUserStillCannotModifySystemRoot() throws Exception {
+        useUser("grant_admin");
+        assertRejected("SET PASSWORD FOR 'root'@'%' = PASSWORD('Pwd_d4')",
+                "Can not set password for root user, except root itself");
+        assertRejected("ALTER USER 'root'@'%' IDENTIFIED BY 'Pwd_d4'", "Only 
root user can modify root user");
+        assertPassword(UserIdentity.ROOT, "");
+    }
+
+    @Test
+    public void testRootAtSpecificHostCannotModifySystemRoot() throws 
Exception {
+        useUser(Auth.ROOT_USER, HOST);
+        assertRejected("SET PASSWORD FOR 'root'@'%' = PASSWORD('Pwd_e5')",
+                "Can not set password for root user, except root itself");
+        assertRejected("ALTER USER 'root'@'%' IDENTIFIED BY 'Pwd_e5'", "Only 
root user can modify root user");
+        assertPassword(UserIdentity.ROOT, "");
+    }
+}
diff --git a/regression-test/suites/account_p0/test_system_user.groovy 
b/regression-test/suites/account_p0/test_system_user.groovy
index d7b3ad213fb..829115680b4 100644
--- a/regression-test/suites/account_p0/test_system_user.groovy
+++ b/regression-test/suites/account_p0/test_system_user.groovy
@@ -100,4 +100,35 @@ suite("test_system_user","p0,auth") {
     sql """
             drop user `admin`@'8.8.8.8';
         """
+
+    // only root@'%' is the system root: root@'<host>' is managed like any 
other account, and a GRANT
+    // user that may manage it still can not modify root@'%'
+    String grantUser = "test_system_user_grant"
+    String pwd = 'C123_567p'
+    try_sql("DROP USER 'root'@'8.8.20.39'")
+    try_sql("DROP USER '${grantUser}'")
+    sql """CREATE USER 'root'@'8.8.20.39' IDENTIFIED BY 'Pwd_a1'"""
+    sql """SET PASSWORD FOR 'root'@'8.8.20.39' = PASSWORD('Pwd_b2')"""
+    sql """ALTER USER 'root'@'8.8.20.39' ACCOUNT_UNLOCK"""
+    sql """CREATE USER '${grantUser}' IDENTIFIED BY '${pwd}'"""
+    sql """GRANT GRANT_PRIV ON *.*.* TO ${grantUser}"""
+    if (isCloudMode()) {
+        def clusters = sql "SHOW CLUSTERS"
+        assertTrue(!clusters.isEmpty())
+        sql """GRANT USAGE_PRIV ON CLUSTER `${clusters[0][0]}` TO 
${grantUser}"""
+    }
+    def tokens = context.config.jdbcUrl.split('/')
+    def url = tokens[0] + "//" + tokens[2] + "/" + "information_schema" + "?"
+    connect(grantUser, "${pwd}", url) {
+        sql """SET PASSWORD FOR 'root'@'8.8.20.39' = PASSWORD('Pwd_c3')"""
+        sql """ALTER USER 'root'@'8.8.20.39' IDENTIFIED BY 'Pwd_d4'"""
+        test {
+            sql """SET PASSWORD FOR 'root'@'%' = PASSWORD('Pwd_e5')"""
+            exception "Can not set password for root user"
+        }
+        test {
+            sql """ALTER USER 'root'@'%' IDENTIFIED BY 'Pwd_e5'"""
+            exception "Only root user can modify root user"
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to