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

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

commit ebdd79b8f5bcb85dd5fb77d0d635855c47f6b256
Author: zhangdong <493738...@qq.com>
AuthorDate: Sat Oct 14 22:37:51 2023 +0800

    [improvement](auth) support show view priv (#25370)
    
    Issue Number: close #xxx
    
    current ,if user has select_priv or load_priv,he can show create table 
view_name,
    but this is not safe,so add show_view_priv for show create table view_name
    
    mysql SHOW VIEW description: 
https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_show-view
---
 .../Account-Management-Statements/GRANT.md         |  7 ++
 .../Account-Management-Statements/GRANT.md         |  7 ++
 .../apache/doris/analysis/ShowCreateTableStmt.java | 15 +++-
 .../org/apache/doris/catalog/AccessPrivilege.java  |  7 +-
 .../doris/mysql/privilege/PrivPredicate.java       |  8 ++
 .../apache/doris/mysql/privilege/Privilege.java    | 13 +++-
 .../org/apache/doris/mysql/privilege/AuthTest.java | 85 ++++++++++++++++++++++
 .../suites/account_p0/test_auth_show.groovy        | 62 ++++++++++++++++
 8 files changed, 197 insertions(+), 7 deletions(-)

diff --git 
a/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md 
b/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
index 4e29c85d2c7..cc85bacd9cb 100644
--- 
a/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
+++ 
b/docs/en/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
@@ -62,6 +62,7 @@ privilege_list is a list of privileges to be granted, 
separated by commas. Curre
     CREATE_PRIV: Create permission on the specified database or table
     DROP_PRIV: drop privilege on the specified database or table
     USAGE_PRIV: access to the specified resource
+    SHOW_VIEW_PRIV: View permission to `view` creation statements (starting 
from version 2.0.3, 'SELECT_PRIV' and 'LOAD_PRIV' permissions cannot be 'SHOW 
CREATE TABLE view_name', has one of 
`CREATE_PRIV`,`ALTER_PRIV`,`DROP_PRIV`,`SHOW_VIEW_PRIV` can `SHOW CREATE TABLE 
view_name`) 
     
     ALL and READ_WRITE in legacy permissions will be converted to: 
SELECT_PRIV,LOAD_PRIV,ALTER_PRIV,CREATE_PRIV,DROP_PRIV;
     READ_ONLY is converted to SELECT_PRIV.
@@ -164,6 +165,12 @@ role_list is the list of roles to be assigned, separated 
by commas,the specified
     GRANT USAGE_PRIV ON WORKLOAD GROUP 'g1' TO ROLE 'my_role'.
     ````
 
+11. Allow jack to view the creation statement of view1 under db1
+
+    ```sql
+    GRANT SHOW_VIEW_PRIV ON db1.view1 TO 'jack'@'%';
+    ````
+
 ### Keywords
 
     GRANT
diff --git 
a/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
 
b/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
index 30839d0531d..2e2ea7aa485 100644
--- 
a/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
+++ 
b/docs/zh-CN/docs/sql-manual/sql-reference/Account-Management-Statements/GRANT.md
@@ -62,6 +62,7 @@ privilege_list 是需要赋予的权限列表,以逗号分隔。当前 Doris 
     CREATE_PRIV:对指定的库或表的创建权限
     DROP_PRIV:对指定的库或表的删除权限
     USAGE_PRIV: 对指定资源的使用权限<version since="dev" type="inline" >和workload 
group权限</version>
+    SHOW_VIEW_PRIV: 
查看`view`创建语句的权限(从2.0.3版本开始,`SELECT_PRIV`和`LOAD_PRIV`权限不能`SHOW CREATE TABLE 
view_name`,拥有`CREATE_PRIV`,`ALTER_PRIV`,`DROP_PRIV`,`SHOW_VIEW_PRIV`权限项中的任何一个,有权`SHOW
 CREATE TABLE view_name`)
     
     旧版权限中的 ALL 和 READ_WRITE 
会被转换成:SELECT_PRIV,LOAD_PRIV,ALTER_PRIV,CREATE_PRIV,DROP_PRIV;
     READ_ONLY 会被转换为 SELECT_PRIV。
@@ -164,6 +165,12 @@ role_list 是需要赋予的角色列表,以逗号分隔,指定的角色必
     GRANT USAGE_PRIV ON WORKLOAD GROUP 'g1' TO ROLE 'my_role';
     ````
 
+11. 允许jack查看db1下view1的创建语句
+
+    ```sql
+    GRANT SHOW_VIEW_PRIV ON db1.view1 TO 'jack'@'%';
+    ````
+
 ### Keywords
 
 ```
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateTableStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateTableStmt.java
index 9527a061d31..ea3b442fbc7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateTableStmt.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateTableStmt.java
@@ -20,6 +20,8 @@ package org.apache.doris.analysis;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.View;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
@@ -103,8 +105,19 @@ public class ShowCreateTableStmt extends ShowStmt {
         }
         tbl.analyze(analyzer);
 
+        TableIf tableIf = Env.getCurrentEnv().getCatalogMgr()
+                .getCatalogOrAnalysisException(tbl.getCtl())
+                
.getDbOrAnalysisException(tbl.getDb()).getTableOrAnalysisException(tbl.getTbl());
+
+        PrivPredicate wanted;
+        if (tableIf instanceof View) {
+            wanted = PrivPredicate.SHOW_VIEW;
+        } else {
+            wanted = PrivPredicate.SHOW;
+        }
+
         if 
(!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), 
tbl.getCtl(), tbl.getDb(),
-                tbl.getTbl(), PrivPredicate.SHOW)) {
+                tbl.getTbl(), wanted)) {
             
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, 
"SHOW CREATE TABLE",
                                                 
ConnectContext.get().getQualifiedUser(),
                                                 
ConnectContext.get().getRemoteIP(),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/AccessPrivilege.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/AccessPrivilege.java
index 88c6c9649ba..becbdfd7fe1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/AccessPrivilege.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/AccessPrivilege.java
@@ -38,7 +38,8 @@ public enum AccessPrivilege {
     CREATE_PRIV(9, "Privilege for creating database or table"),
     DROP_PRIV(10, "Privilege for dropping database or table"),
     ADMIN_PRIV(11, "All privileges except NODE_PRIV"),
-    USAGE_PRIV(12, "Privilege for use resource");
+    USAGE_PRIV(12, "Privilege for use resource"),
+    SHOW_VIEW_PRIV(13, "Privilege for show view");
 
     private int flag;
     private String desc;
@@ -49,7 +50,7 @@ public enum AccessPrivilege {
     }
 
     public List<Privilege> toDorisPrivilege() {
-        Preconditions.checkState(flag > 0 && flag < 13);
+        Preconditions.checkState(flag > 0 && flag < 14);
         switch (flag) {
             case 1:
             case 6:
@@ -75,6 +76,8 @@ public enum AccessPrivilege {
                 return Lists.newArrayList(Privilege.ADMIN_PRIV);
             case 12:
                 return Lists.newArrayList(Privilege.USAGE_PRIV);
+            case 13:
+                return Lists.newArrayList(Privilege.SHOW_VIEW_PRIV);
             default:
                 return null;
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivPredicate.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivPredicate.java
index 61f820f6745..6aae0e1c9c9 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivPredicate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivPredicate.java
@@ -29,8 +29,16 @@ public class PrivPredicate {
             Privilege.LOAD_PRIV,
             Privilege.ALTER_PRIV,
             Privilege.CREATE_PRIV,
+            Privilege.SHOW_VIEW_PRIV,
             Privilege.DROP_PRIV),
             Operator.OR);
+    // show create table 'view'
+    public static final PrivPredicate SHOW_VIEW = 
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
+            Privilege.CREATE_PRIV,
+            Privilege.ALTER_PRIV,
+            Privilege.DROP_PRIV,
+            Privilege.SHOW_VIEW_PRIV),
+            Operator.OR);
     // show resources
     public static final PrivPredicate SHOW_RESOURCES = 
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
             Privilege.USAGE_PRIV),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
index 680bc1dcaef..54130a5d450 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Privilege.java
@@ -30,7 +30,8 @@ public enum Privilege {
     ALTER_PRIV("Alter_priv", 5, "Privilege for alter database or table"),
     CREATE_PRIV("Create_priv", 6, "Privilege for creating database or table"),
     DROP_PRIV("Drop_priv", 7, "Privilege for dropping database or table"),
-    USAGE_PRIV("Usage_priv", 8, "Privilege for using resource or 
workloadGroup");
+    USAGE_PRIV("Usage_priv", 8, "Privilege for using resource or 
workloadGroup"),
+    SHOW_VIEW_PRIV("Show_view_priv", 9, "Privilege for show create view");
 
     public static Privilege[] privileges = {
             NODE_PRIV,
@@ -41,7 +42,8 @@ public enum Privilege {
             ALTER_PRIV,
             CREATE_PRIV,
             DROP_PRIV,
-            USAGE_PRIV
+            USAGE_PRIV,
+            SHOW_VIEW_PRIV
     };
 
     // only GRANT_PRIV and USAGE_PRIV can grant on resource
@@ -52,7 +54,8 @@ public enum Privilege {
             LOAD_PRIV,
             ALTER_PRIV,
             CREATE_PRIV,
-            DROP_PRIV
+            DROP_PRIV,
+            SHOW_VIEW_PRIV
     };
 
     // only GRANT_PRIV and USAGE_PRIV can grant on workloadGroup
@@ -63,7 +66,8 @@ public enum Privilege {
             LOAD_PRIV,
             ALTER_PRIV,
             CREATE_PRIV,
-            DROP_PRIV
+            DROP_PRIV,
+            SHOW_VIEW_PRIV
     };
 
     public static Map<Privilege, String> privInDorisToMysql =
@@ -74,6 +78,7 @@ public enum Privilege {
                     .put(CREATE_PRIV, "CREATE")
                     .put(DROP_PRIV, "DROP")
                     .put(USAGE_PRIV, "USAGE")
+                    .put(SHOW_VIEW_PRIV, "SHOW VIEW")
                     .build();
 
     private String name;
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 b0afc8055d3..5ebfb97e0b1 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
@@ -2218,4 +2218,89 @@ public class AuthTest {
         ExceptionChecker.expectThrowsWithMsg(AnalysisException.class,
                 "Can not grant/revoke USAGE_PRIV to/from database or table", 
() -> grantStmt3.analyze(analyzer));
     }
+
+    private void createUser(UserIdentity userIdentity) throws UserException {
+        UserDesc userDesc = new UserDesc(userIdentity, "12345", true);
+        CreateUserStmt createUserStmt = new CreateUserStmt(false, userDesc, 
null);
+        createUserStmt.analyze(analyzer);
+        auth.createUser(createUserStmt);
+    }
+
+    private void grant(GrantStmt grantStmt) throws UserException {
+        grantStmt.analyze(analyzer);
+        auth.grant(grantStmt);
+    }
+
+    private void revoke(RevokeStmt revokeStmt) throws UserException {
+        revokeStmt.analyze(analyzer);
+        auth.revoke(revokeStmt);
+    }
+
+    @Test
+    public void testShowViewPriv() throws UserException {
+        UserIdentity userIdentity = new UserIdentity("viewUser", "%");
+        createUser(userIdentity);
+        // `load_priv` and `select_priv` can not `show create view`
+        GrantStmt grantStmt = new GrantStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.SELECT_PRIV),
+                        new 
AccessPrivilegeWithCols(AccessPrivilege.LOAD_PRIV)));
+        grant(grantStmt);
+        Assert.assertFalse(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        // `SHOW_VIEW_PRIV` can `show create view`
+        grantStmt = new GrantStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.SHOW_VIEW_PRIV)));
+        grant(grantStmt);
+        Assert.assertTrue(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        RevokeStmt revokeStmt = new RevokeStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.SHOW_VIEW_PRIV)));
+        revoke(revokeStmt);
+
+        // 'admin_priv' can `show create view`
+        grantStmt = new GrantStmt(userIdentity, null, new TablePattern("*", 
"*", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.ADMIN_PRIV)));
+        grant(grantStmt);
+        Assert.assertTrue(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        revokeStmt = new RevokeStmt(userIdentity, null, new TablePattern("*", 
"*", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.ADMIN_PRIV)));
+        revoke(revokeStmt);
+
+        // 'create_priv' can `show create view`
+        grantStmt = new GrantStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.CREATE_PRIV)));
+        grant(grantStmt);
+        Assert.assertTrue(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        revokeStmt = new RevokeStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.CREATE_PRIV)));
+        revoke(revokeStmt);
+
+        // 'alter_priv' can `show create view`
+        grantStmt = new GrantStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.ALTER_PRIV)));
+        grant(grantStmt);
+        Assert.assertTrue(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        revokeStmt = new RevokeStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.ALTER_PRIV)));
+        revoke(revokeStmt);
+
+        // 'drop_priv' can `show create view`
+        grantStmt = new GrantStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.DROP_PRIV)));
+        grant(grantStmt);
+        Assert.assertTrue(accessManager
+                .checkDbPriv(userIdentity, SystemInfoService.DEFAULT_CLUSTER + 
":viewdb", PrivPredicate.SHOW_VIEW));
+
+        revokeStmt = new RevokeStmt(userIdentity, null, new 
TablePattern("viewdb", "*"),
+                Lists.newArrayList(new 
AccessPrivilegeWithCols(AccessPrivilege.DROP_PRIV)));
+        revoke(revokeStmt);
+    }
 }
diff --git a/regression-test/suites/account_p0/test_auth_show.groovy 
b/regression-test/suites/account_p0/test_auth_show.groovy
new file mode 100644
index 00000000000..c847fd1715a
--- /dev/null
+++ b/regression-test/suites/account_p0/test_auth_show.groovy
@@ -0,0 +1,62 @@
+// 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.
+
+suite("test_auth_show", "account") {
+
+     def create_table = { tableName ->
+            sql "DROP TABLE IF EXISTS ${tableName}"
+            sql """
+                CREATE TABLE ${tableName} (
+                    `key` INT,
+                    value INT
+                ) DUPLICATE KEY (`key`) DISTRIBUTED BY HASH (`key`) BUCKETS 1
+                PROPERTIES ('replication_num' = '1')
+            """
+        }
+
+    def user = 'acount_auth_show_user'
+    def pwd = 'C123_567p'
+    def dbName = 'account_auth_show_db'
+    def tableName = 'account_auth_show_table'
+
+    try_sql("DROP USER ${user}")
+    sql """DROP DATABASE IF EXISTS ${dbName}"""
+    sql """CREATE DATABASE ${dbName}"""
+    sql """USE ${dbName}"""
+    create_table.call(tableName);
+    sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'"""
+
+    def tokens = context.config.jdbcUrl.split('/')
+    def url=tokens[0] + "//" + tokens[2] + "/" + dbName + "?"
+
+    // With select priv for table, should be able to see db
+    sql """GRANT SELECT_PRIV ON ${dbName}.${tableName} TO ${user}"""
+    def result1 = connect(user=user, password="${pwd}", url=url) {
+        sql """show databases like '${dbName}'"""
+    }
+    assertEquals(result1.size(), 1)
+    sql """REVOKE SELECT_PRIV ON ${dbName}.${tableName} FROM ${user}"""
+
+    // With show_view priv for table, should be able to see db
+    sql """GRANT SHOW_VIEW_PRIV ON ${dbName}.${tableName} TO ${user}"""
+    def result2 = connect(user=user, password="${pwd}", url=url) {
+        sql """show databases like '${dbName}'"""
+    }
+    assertEquals(result2.size(), 1)
+    sql """REVOKE SHOW_VIEW_PRIV ON ${dbName}.${tableName} FROM ${user}"""
+}
+


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

Reply via email to