Skip to content

Commit 74d540a

Browse files
authored
feat(query): check view's inner table privilege when create or alter view (#14986)
* feat: check view's inner table privilege when create or alter view Note: Select view no need to check the inner table privilege. Because the user only can query view when the admin user grant select on the view to the user. So the admin user needs to know why the user need access this view. This pr is avoid that: User only has create or alter on db. And then the user can query table as create or alter view. Like this: ```sql --root grant create on default.* to a; --user a create view v_t1 as select * from t1; -- If it can be success, the user a can query table t1 according to query view v_t1. It maybe dangerous. ``` * create view only need check the user has select privilege on inner tables * add test: create view as select view
1 parent 0505274 commit 74d540a

File tree

3 files changed

+133
-2
lines changed

3 files changed

+133
-2
lines changed

src/query/service/src/interpreters/access/privilege_access.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use databend_common_sql::optimizer::get_udf_names;
3232
use databend_common_sql::plans::InsertInputSource;
3333
use databend_common_sql::plans::PresignAction;
3434
use databend_common_sql::plans::RewriteKind;
35+
use databend_common_sql::Planner;
3536
use databend_common_users::RoleCacheManager;
3637

3738
use crate::interpreters::access::AccessChecker;
@@ -861,10 +862,15 @@ impl AccessChecker for PrivilegeAccess {
861862
self.validate_table_access(&plan.catalog, &plan.database, &plan.table, vec![UserPrivilegeType::Update], false).await?;
862863
}
863864
Plan::CreateView(plan) => {
864-
self.validate_db_access(&plan.catalog, &plan.database, vec![UserPrivilegeType::Create], false).await?
865+
let mut planner = Planner::new(self.ctx.clone());
866+
let (plan, _) = planner.plan_sql(&plan.subquery).await?;
867+
self.check(ctx, &plan).await?
865868
}
866869
Plan::AlterView(plan) => {
867-
self.validate_db_access(&plan.catalog, &plan.database, vec![UserPrivilegeType::Alter], false).await?
870+
self.validate_db_access(&plan.catalog, &plan.database, vec![UserPrivilegeType::Alter], false).await?;
871+
let mut planner = Planner::new(self.ctx.clone());
872+
let (plan, _) = planner.plan_sql(&plan.subquery).await?;
873+
self.check(ctx, &plan).await?
868874
}
869875
Plan::DropView(plan) => {
870876
self.validate_db_access(&plan.catalog, &plan.database, vec![UserPrivilegeType::Drop], plan.if_exists).await?
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
>>>> drop user if exists 'owner'
2+
>>>> drop role if exists role1
3+
>>>> create user 'owner' IDENTIFIED BY 'password' with DEFAULT_ROLE='role1'
4+
>>>> create role role1
5+
>>>> grant role role1 to owner
6+
>>>> grant create on default.* to role role1
7+
>>>> drop table if exists t
8+
>>>> drop view if exists v_t
9+
>>>> drop table if exists t_owner
10+
>>>> drop view if exists v_t_owner
11+
>>>> drop view if exists v_t_union
12+
>>>> drop view if exists v_t1
13+
>>>> create table t(id int)
14+
>>>> insert into t values(1)
15+
>>>> revoke create on default.* from role role1
16+
need failed: with 1063
17+
Error: APIError: ResponseError with 1063: Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1]
18+
need failed: with 1063
19+
Error: APIError: ResponseError with 1063: Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1]
20+
>>>> grant ownership on default.v_t_owner to role role1
21+
>>>> create view v_t as select * from t
22+
>>>> create view v_t_union as select * from t union all select * from t_owner
23+
'select * from v_t order by id' failed.
24+
Error: APIError: ResponseError with 1063: Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1]
25+
>>>> grant select on default.v_t to owner
26+
>>>> grant select on default.v_t_union to owner
27+
1
28+
2
29+
1
30+
2
31+
>>>> select * from v_t order by id
32+
1
33+
<<<<
34+
>>>> select * from v_t_owner order by c1
35+
2
36+
<<<<
37+
>>>> select * from v_t_union order by id
38+
1
39+
2
40+
<<<<
41+
=== create view as select view ===
42+
>>>> revoke select on default.v_t from owner
43+
>>>> grant select on default.t to owner
44+
Error: APIError: ResponseError with 1063: Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1]
45+
>>>> grant select on default.v_t to owner
46+
>>>> grant select on default.t to owner
47+
>>>> grant select on default.v_t1 to owner
48+
1
49+
>>>> drop table if exists t
50+
>>>> drop view if exists v_t
51+
>>>> drop table if exists t_owner
52+
>>>> drop view if exists v_t_owner
53+
>>>> drop view if exists v_t_union
54+
>>>> drop view if exists v_t1
55+
>>>> drop user if exists owner
56+
>>>> drop role if exists role1
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
3+
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
4+
. "$CURDIR"/../../../shell_env.sh
5+
6+
export TEST_USER_NAME="owner"
7+
export TEST_USER_PASSWORD="password"
8+
export TEST_USER_CONNECT="bendsql --user=owner --password=password --host=${QUERY_MYSQL_HANDLER_HOST} --port ${QUERY_HTTP_HANDLER_PORT}"
9+
10+
stmt "drop user if exists 'owner'"
11+
stmt "drop role if exists role1"
12+
stmt "create user 'owner' IDENTIFIED BY '$TEST_USER_PASSWORD' with DEFAULT_ROLE='role1'"
13+
stmt 'create role role1'
14+
15+
stmt 'grant role role1 to owner'
16+
stmt 'grant create on default.* to role role1'
17+
stmt 'drop table if exists t'
18+
stmt 'drop view if exists v_t'
19+
stmt 'drop table if exists t_owner'
20+
stmt 'drop view if exists v_t_owner'
21+
stmt 'drop view if exists v_t_union'
22+
stmt 'drop view if exists v_t1'
23+
stmt 'create table t(id int)'
24+
stmt 'insert into t values(1)'
25+
echo 'create table t_owner(c1 int)' | $TEST_USER_CONNECT
26+
echo 'insert into t_owner values(2)' | $TEST_USER_CONNECT
27+
stmt 'revoke create on default.* from role role1'
28+
29+
echo 'need failed: with 1063'
30+
echo 'create view v_t as select * from t' | $TEST_USER_CONNECT
31+
echo 'need failed: with 1063'
32+
echo 'create view v_t_union as select * from t union all select * from t_owner' | $TEST_USER_CONNECT
33+
echo 'create view v_t_owner as select * from t_owner' | $TEST_USER_CONNECT
34+
stmt 'grant ownership on default.v_t_owner to role role1'
35+
36+
stmt 'create view v_t as select * from t'
37+
stmt 'create view v_t_union as select * from t union all select * from t_owner'
38+
39+
echo "'select * from v_t order by id' failed."
40+
echo "select * from v_t order by id" | $TEST_USER_CONNECT
41+
stmt 'grant select on default.v_t to owner'
42+
stmt 'grant select on default.v_t_union to owner'
43+
echo "select * from v_t order by id" | $TEST_USER_CONNECT
44+
echo "select * from v_t_owner order by c1" | $TEST_USER_CONNECT
45+
echo "select * from v_t_union order by id" | $TEST_USER_CONNECT
46+
47+
query "select * from v_t order by id"
48+
query "select * from v_t_owner order by c1"
49+
query "select * from v_t_union order by id"
50+
51+
echo "=== create view as select view ==="
52+
53+
stmt 'revoke select on default.v_t from owner'
54+
stmt 'grant select on default.t to owner'
55+
echo 'create view v_t1 as select * from t union select * from v_t' | $TEST_USER_CONNECT
56+
stmt 'grant select on default.v_t to owner'
57+
stmt 'grant select on default.t to owner'
58+
echo 'create view v_t1 as select * from t union select * from v_t' | $TEST_USER_CONNECT
59+
stmt 'grant select on default.v_t1 to owner'
60+
echo "select * from v_t1 order by id" | $TEST_USER_CONNECT
61+
62+
stmt 'drop table if exists t'
63+
stmt 'drop view if exists v_t'
64+
stmt 'drop table if exists t_owner'
65+
stmt 'drop view if exists v_t_owner'
66+
stmt 'drop view if exists v_t_union'
67+
stmt 'drop view if exists v_t1'
68+
stmt 'drop user if exists owner'
69+
stmt 'drop role if exists role1'

0 commit comments

Comments
 (0)