You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/06/07 08:57:28 UTC

[incubator-doris] 06/06: [feature](priv) Support grant node_priv to other user. (#9951)

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

morningman pushed a commit to branch dev-1.0.1
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git

commit c975be38b2d6fe2371f02a9077197289925cca9b
Author: Mingyu Chen <mo...@gmail.com>
AuthorDate: Mon Jun 6 11:04:20 2022 +0800

    [feature](priv) Support grant node_priv to other user. (#9951)
    
    Currently, only the root user has node_priv privileges.
    That is, only the root user can operate the addition and deletion of nodes.
    
    In the original design of Doris, there is an Operator role. This role can have node_priv for node operations.
    
    This PR supports assigning node_priv to users other than root.
    However, only users who have both grant_priv and node_priv can assign node_priv to other users.
    This ensures that only the root user has this permission, and users who are given node_priv
    cannot continue to expand this permission outward.
---
 docs/en/administrator-guide/privilege.md           |  10 +-
 .../java/org/apache/doris/analysis/GrantStmt.java  |  22 ++--
 .../org/apache/doris/mysql/privilege/AuthTest.java | 124 ++++++++++++++++++++-
 3 files changed, 147 insertions(+), 9 deletions(-)

diff --git a/docs/en/administrator-guide/privilege.md b/docs/en/administrator-guide/privilege.md
index f20316b1f7..d7e004a7b3 100644
--- a/docs/en/administrator-guide/privilege.md
+++ b/docs/en/administrator-guide/privilege.md
@@ -73,10 +73,18 @@ Doris currently supports the following permissions
 
 	Nodes change permissions. Including FE, BE, BROKER node addition, deletion, offline operations. Currently, this permission can only be granted to Root users.
 
+    The root user has this permission by default.
+
+    Users who have both Grant_priv and Node_priv can grant this privilege to other users.
+
+    This permission can only be granted to the Global level.
+
 2. Grant_priv
 
 	Permissions change permissions. Allow the execution of operations including authorization, revocation, add/delete/change user/role, etc.
 
+    However, a user with this permission can not grant node_priv permission to other users, unless the user itself has node_priv permission.
+
 3. Select_priv
 
 	Read-only access to databases and tables.
@@ -149,7 +157,7 @@ ADMIN\_PRIV and GRANT\_PRIV have the authority of **"grant authority"** at the s
 
 2. It is not supported to delete or change the permissions of default created roles or users.
 
-3. The user of the operator role has one and only one user. Users of admin roles can create multiple.
+3. The user of the operator role has one and only one user, that is, root. Users of admin roles can create multiple.
 
 4. Operational instructions for possible conflicts
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
index be915b9d27..0c18564962 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/GrantStmt.java
@@ -126,26 +126,34 @@ public class GrantStmt extends DdlStmt {
         }
     }
 
-    /*
+    /**
      * Rules:
-     * 1. Can not grant/revoke NODE_PRIV to/from any other user.
-     * 2. ADMIN_PRIV can only be granted/revoked on GLOBAL level
+     * 1. ADMIN_PRIV and NODE_PRIV can only be granted/revoked on GLOBAL level
+     * 2. Only the user with NODE_PRIV can grant NODE_PRIV to other user
      * 3. Privileges can not be granted/revoked to/from ADMIN and OPERATOR role
      * 4. Only user with GLOBAL level's GRANT_PRIV can grant/revoke privileges to/from roles.
      * 5.1 User should has GLOBAL level GRANT_PRIV
      * 5.2 or user has DATABASE/TABLE level GRANT_PRIV if grant/revoke to/from certain database or table.
      * 5.3 or user should has 'resource' GRANT_PRIV if grant/revoke to/from certain 'resource'
+     *
+     * @param analyzer
+     * @param privileges
+     * @param role
+     * @param tblPattern
+     * @throws AnalysisException
      */
     public static void checkPrivileges(Analyzer analyzer, List<PaloPrivilege> privileges,
                                        String role, TablePattern tblPattern) throws AnalysisException {
         // Rule 1
-        if (privileges.contains(PaloPrivilege.NODE_PRIV)) {
-            throw new AnalysisException("Can not grant NODE_PRIV to any other users or roles");
+        if (tblPattern.getPrivLevel() != PrivLevel.GLOBAL && (privileges.contains(PaloPrivilege.ADMIN_PRIV)
+                || privileges.contains(PaloPrivilege.NODE_PRIV))) {
+            throw new AnalysisException("ADMIN_PRIV and NODE_PRIV can only be granted on *.*");
         }
 
         // Rule 2
-        if (tblPattern.getPrivLevel() != PrivLevel.GLOBAL && privileges.contains(PaloPrivilege.ADMIN_PRIV)) {
-            throw new AnalysisException("ADMIN_PRIV privilege can only be granted on *.*");
+        if (privileges.contains(PaloPrivilege.NODE_PRIV) && !Catalog.getCurrentCatalog().getAuth()
+                .checkGlobalPriv(ConnectContext.get(), PrivPredicate.OPERATOR)) {
+            throw new AnalysisException("Only the user with NODE_PRIV can grant NODE_PRIV to other user");
         }
 
         if (role != null) {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
index 91182dc4cf..1d06a5b276 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java
@@ -143,7 +143,8 @@ public class AuthTest {
     }
 
     @Test
-    public void test() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+    public void test()
+            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, UserException {
         // 1. create cmy@%
         UserIdentity userIdentity = new UserIdentity("cmy", "%");
         UserDesc userDesc = new UserDesc(userIdentity, "12345", true);
@@ -1207,6 +1208,127 @@ public class AuthTest {
         } catch (UserException e) {
             e.printStackTrace();
         }
+
+        // 40. create new user and grant node_priv to it
+        final UserIdentity opUser = new UserIdentity("op_user", "%");
+        userDesc = new UserDesc(opUser, "12345", true);
+        createUserStmt = new CreateUserStmt(false, userDesc, null);
+        createUserStmt.analyze(analyzer);
+        auth.createUser(createUserStmt);
+
+        privileges = Lists.newArrayList(AccessPrivilege.NODE_PRIV);
+        // 40.1 grant to non-global level, which is not allowed
+        grantStmt = new GrantStmt(opUser, null, new TablePattern("db1", "*"), privileges);
+        try {
+            grantStmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            e.printStackTrace();
+        }
+
+        grantStmt = new GrantStmt(opUser, null, new TablePattern("db1", "tbl"), privileges);
+        try {
+            grantStmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            e.printStackTrace();
+        }
+        // 40.2 grant to global level
+        new Expectations() {
+            {
+                ctx.getCurrentUserIdentity();
+                minTimes = 1;
+                result = opUser;
+            }
+        };
+        Assert.assertFalse(auth.checkGlobalPriv(ctx, PrivPredicate.OPERATOR));
+        grantStmt = new GrantStmt(opUser, null, new TablePattern("*", "*"), privileges);
+        // first, use op_user itself to grant node_priv, which is not allowed
+        try {
+            new Expectations() {
+                {
+                    ctx.getCurrentUserIdentity();
+                    minTimes = 1;
+                    result = opUser;
+                }
+            };
+            grantStmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            e.printStackTrace();
+        }
+        // second, use root to grant node_priv
+        try {
+            new Expectations() {
+                {
+                    ctx.getCurrentUserIdentity();
+                    minTimes = 1;
+                    result = UserIdentity.ROOT;
+                }
+            };
+            grantStmt.analyze(analyzer);
+            auth.grant(grantStmt);
+        } catch (UserException e) {
+            e.printStackTrace();
+            Assert.fail();
+        }
+        // switch to op_user to check it has node_priv
+        new Expectations() {
+            {
+                ctx.getCurrentUserIdentity();
+                minTimes = 2;
+                result = opUser;
+            }
+        };
+        Assert.assertTrue(auth.checkGlobalPriv(ctx, PrivPredicate.OPERATOR));
+        // Now, op_user only has node_priv, it can not grant node_priv to other user.
+        // create otherOpUser first
+        UserIdentity otherOpUser = new UserIdentity("other_op_user", "%");
+        userDesc = new UserDesc(otherOpUser, "12345", true);
+        createUserStmt = new CreateUserStmt(false, userDesc, null);
+        createUserStmt.analyze(analyzer);
+        auth.createUser(createUserStmt);
+        // try grant, it should fail
+        grantStmt = new GrantStmt(otherOpUser, null, new TablePattern("*", "*"), privileges);
+        try {
+            grantStmt.analyze(analyzer);
+            Assert.fail();
+        } catch (UserException e) {
+            e.printStackTrace();
+        }
+        // Now, we grant grant_priv to opUser, and check if it can than grant node_priv to other user
+        privileges = Lists.newArrayList(AccessPrivilege.GRANT_PRIV);
+        grantStmt = new GrantStmt(opUser, null, new TablePattern("*", "*"), privileges);
+        try {
+            new Expectations() {
+                {
+                    ctx.getCurrentUserIdentity();
+                    minTimes = 2;
+                    result = UserIdentity.ROOT;
+                }
+            };
+            grantStmt.analyze(analyzer);
+            auth.grant(grantStmt);
+        } catch (UserException e) {
+            e.printStackTrace();
+            Assert.fail();
+        }
+        // grant node_priv to other_op_user
+        grantStmt = new GrantStmt(otherOpUser, null, new TablePattern("*", "*"), privileges);
+        try {
+            new Expectations() {
+                {
+                    ctx.getCurrentUserIdentity();
+                    minTimes = 1;
+                    result = opUser;
+                }
+            };
+            grantStmt.analyze(analyzer);
+            auth.grant(grantStmt);
+        } catch (UserException e) {
+            e.printStackTrace();
+            Assert.fail();
+        }
     }
 
     @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org