Skip to content

Commit 6f47727

Browse files
authored
fix(query): account_admin should support grant ownership to new role after drop an created role (#14597)
* fix(query): after drop role account_admin should support grant ownership to new role 1. if has ownership but owner role not exists, the owner role will be set to account_admin 2. has_ownership should get ownership and role from meta * modify api get_ownership if has ownership but role not exists this object's owner set to account_admin * fix err * refactor has_ownership * fix build err * find_object_owner driectly return role_name * refactor find_object_owner, not get role again * fix build err * add table test and add some comment about why not modify get_ownerships
1 parent 71acbc1 commit 6f47727

File tree

5 files changed

+63
-16
lines changed

5 files changed

+63
-16
lines changed

src/query/service/src/sessions/session_privilege_mgr.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,10 @@ impl SessionPrivilegeManager for SessionPrivilegeManagerImpl {
269269
async fn has_ownership(&self, object: &OwnershipObject) -> Result<bool> {
270270
let role_mgr = RoleCacheManager::instance();
271271
let tenant = self.session_ctx.get_current_tenant();
272-
273-
// if the object is not owned by any role, then considered as ACCOUNT_ADMIN, the normal users
274-
// can not access it unless ACCOUNT_ADMIN grant relevant privileges to them.
275-
let owner_role_name = match role_mgr.find_object_owner(&tenant, object).await? {
276-
Some(owner_role) => owner_role.name,
277-
None => BUILTIN_ROLE_ACCOUNT_ADMIN.to_string(),
278-
};
272+
let owner_role_name = role_mgr
273+
.find_object_owner(&tenant, object)
274+
.await?
275+
.unwrap_or_else(|| BUILTIN_ROLE_ACCOUNT_ADMIN.to_string());
279276

280277
let effective_roles = self.get_all_effective_roles().await?;
281278
let exists = effective_roles.iter().any(|r| r.name == owner_role_name);

src/query/users/src/role_cache_mgr.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,11 @@ impl RoleCacheManager {
116116
&self,
117117
tenant: &str,
118118
object: &OwnershipObject,
119-
) -> Result<Option<RoleInfo>> {
120-
let owner = match self.user_manager.get_ownership(tenant, object).await? {
119+
) -> Result<Option<String>> {
120+
match self.user_manager.get_ownership(tenant, object).await? {
121121
None => return Ok(None),
122-
Some(owner) => owner,
123-
};
124-
125-
// cache manager would not look into built-in roles.
126-
let role = self.user_manager.get_role(tenant, owner.role).await?;
127-
Ok(Some(role))
122+
Some(owner) => Ok(Some(owner.role)),
123+
}
128124
}
129125

130126
// find_related_roles is called on validating an user's privileges.

src/query/users/src/role_mgr.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,24 @@ impl UserApiProvider {
165165
.get_ownership(object)
166166
.await
167167
.map_err(|e| e.add_message_back("(while get ownership)"))?;
168-
Ok(ownership)
168+
if let Some(owner) = ownership {
169+
// if object has ownership, but the owner role is not exists, set owner role to ACCOUNT_ADMIN,
170+
// only account_admin can access this object.
171+
// Note: get_ownerships no need to do this check.
172+
// Because this can cause system.table queries to slow down
173+
// The intention is that the account admin can grant ownership.
174+
// So system.tables will display dropped role. It's by design.
175+
if !self.exists_role(tenant, owner.role.clone()).await? {
176+
Ok(Some(OwnershipInfo {
177+
role: BUILTIN_ROLE_ACCOUNT_ADMIN.to_string(),
178+
object: object.clone(),
179+
}))
180+
} else {
181+
Ok(Some(owner))
182+
}
183+
} else {
184+
Ok(None)
185+
}
169186
}
170187

171188
#[async_backtrace::framed]

tests/suites/0_stateless/18_rbac/18_0002_ownership_cover.result

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@ t1
3737
Error: APIError: ResponseError with 1063: Permission denied: User 'a'@'%' does not have the required privileges for database 'db_a'
3838
t
3939
t1
40+
=== fix_issue_14572: test drop role; grant ownership ===
41+
a drop_role
42+
t drop_role
43+
a account_admin
44+
t drop_role
45+
a drop_role1
46+
t drop_role1
47+
GRANT OWNERSHIP ON 'default'.'a'.* TO ROLE `drop_role1`
48+
GRANT OWNERSHIP ON 'default'.'a'.'t' TO ROLE `drop_role1`

tests/suites/0_stateless/18_rbac/18_0002_ownership_cover.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,31 @@ echo "drop database db_a;" | $BENDSQL_CLIENT_CONNECT
126126
echo "drop role if exists role1;" | $BENDSQL_CLIENT_CONNECT
127127
echo "drop user if exists a;" | $BENDSQL_CLIENT_CONNECT
128128
echo "drop user if exists b;" | $BENDSQL_CLIENT_CONNECT
129+
130+
echo "=== fix_issue_14572: test drop role; grant ownership ==="
131+
echo "drop role if exists drop_role;" | $BENDSQL_CLIENT_CONNECT
132+
echo "drop role if exists drop_role1;" | $BENDSQL_CLIENT_CONNECT
133+
echo "drop user if exists u1;" | $BENDSQL_CLIENT_CONNECT
134+
echo "drop database if exists a;" | $BENDSQL_CLIENT_CONNECT
135+
echo "create role drop_role;" | $BENDSQL_CLIENT_CONNECT
136+
echo "create role drop_role1;" | $BENDSQL_CLIENT_CONNECT
137+
echo "create user u1 identified by '123' with DEFAULT_ROLE='drop_role'" | $BENDSQL_CLIENT_CONNECT
138+
echo "grant role drop_role to u1;" | $BENDSQL_CLIENT_CONNECT
139+
echo "grant create on *.* to u1;" | $BENDSQL_CLIENT_CONNECT
140+
export USER_U1_CONNECT="bendsql --user=u1 --password=123 --host=${QUERY_MYSQL_HANDLER_HOST} --port ${QUERY_HTTP_HANDLER_PORT}"
141+
142+
echo "create database a" | $USER_U1_CONNECT
143+
echo "create table a.t(id int)" | $USER_U1_CONNECT
144+
echo "select name, owner from system.databases where name='a'" | $USER_U1_CONNECT
145+
echo "select name, owner from system.tables where database='a'" | $USER_U1_CONNECT
146+
echo "drop role drop_role;" | $BENDSQL_CLIENT_CONNECT
147+
echo "select name, owner from system.databases where name='a'" | $BENDSQL_CLIENT_CONNECT
148+
echo "select name, owner from system.tables where database='a'" | $USER_U1_CONNECT
149+
echo "grant ownership on a.* to role drop_role1;" | $BENDSQL_CLIENT_CONNECT
150+
echo "grant ownership on a.t to role drop_role1;" | $BENDSQL_CLIENT_CONNECT
151+
echo "select name, owner from system.databases where name='a'" | $BENDSQL_CLIENT_CONNECT
152+
echo "select name, owner from system.tables where database='a'" | $USER_U1_CONNECT
153+
echo "show grants for role drop_role1" | $BENDSQL_CLIENT_CONNECT
154+
echo "drop role drop_role1" | $BENDSQL_CLIENT_CONNECT
155+
echo "drop user u1" | $BENDSQL_CLIENT_CONNECT
156+
echo "drop database a" | $BENDSQL_CLIENT_CONNECT

0 commit comments

Comments
 (0)