Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions src/meta/app/src/principal/user_privilege.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,36 +97,6 @@ pub enum UserPrivilegeType {
CreateDataMask = 1 << 16,
}

const ALL_PRIVILEGES: BitFlags<UserPrivilegeType> = make_bitflags!(
UserPrivilegeType::{
Create
| Select
| Insert
| Update
| Delete
| Drop
| Alter
| Super
| CreateUser
| DropUser
| CreateRole
| DropRole
| Grant
| CreateStage
| Set
| CreateDataMask
| CreateMaskingPolicy
| ApplyMaskingPolicy
| Ownership
| Read
| Write
| CreateDatabase
| CreateWarehouse
| CreateConnection
| AccessConnection
}
);

impl Display for UserPrivilegeType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match self {
Expand Down Expand Up @@ -345,26 +315,13 @@ impl UserPrivilegeSet {
}
}

// TODO: remove this, as ALL has different meanings on different objects
pub fn all_privileges() -> Self {
ALL_PRIVILEGES.into()
}

pub fn set_privilege(&mut self, privilege: UserPrivilegeType) {
self.privileges |= privilege;
}

pub fn has_privilege(&self, privilege: UserPrivilegeType) -> bool {
self.privileges.contains(privilege)
}

pub fn set_all_privileges(&mut self) {
self.privileges |= ALL_PRIVILEGES;
}

pub fn is_all_privileges(&self) -> bool {
self.privileges == ALL_PRIVILEGES
}
}

impl Display for UserPrivilegeSet {
Expand Down
2 changes: 1 addition & 1 deletion src/meta/app/tests/it/user_privilege.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn test_user_privilege() -> Result<()> {
let r = privileges.has_privilege(UserPrivilegeType::Insert);
assert!(r);

privileges.set_all_privileges();
privileges |= UserPrivilegeSet::available_privileges_on_global();
let r = privileges.has_privilege(UserPrivilegeType::Create);
assert!(r);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ impl AccessChecker for PrivilegeAccess {
.validate_access(
&GrantObject::Global,
UserPrivilegeType::CreateMaskingPolicy,
false,
true,
false,
)
.await?;
Expand Down
30 changes: 28 additions & 2 deletions src/query/service/src/interpreters/interpreter_privilege_grant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use databend_common_meta_app::principal::GrantObject;
use databend_common_meta_app::principal::OwnershipObject;
use databend_common_meta_app::principal::PrincipalIdentity;
use databend_common_meta_app::principal::UserPrivilegeSet;
use databend_common_meta_app::principal::UserPrivilegeType;
use databend_common_meta_app::principal::UserPrivilegeType::Ownership;
use databend_common_meta_app::tenant::Tenant;
use databend_common_sql::plans::GrantPrivilegePlan;
Expand Down Expand Up @@ -216,7 +217,7 @@ impl Interpreter for GrantPrivilegeInterpreter {

let plan = self.plan.clone();

validate_grant_privileges(&plan.on, plan.priv_types)?;
validate_grant_privileges(&plan.principal, &plan.on, plan.priv_types)?;
validate_grant_object_exists(&self.ctx, &plan.on).await?;

// TODO: check user existence
Expand Down Expand Up @@ -273,7 +274,11 @@ impl Interpreter for GrantPrivilegeInterpreter {
/// Check if there's any privilege which can not be granted to this GrantObject.
/// Some global privileges can not be granted to a database or table, for example,
/// a KILL statement is meaningless for a table.
pub fn validate_grant_privileges(object: &GrantObject, privileges: UserPrivilegeSet) -> Result<()> {
pub fn validate_grant_privileges(
principal: &PrincipalIdentity,
object: &GrantObject,
privileges: UserPrivilegeSet,
) -> Result<()> {
let available_privileges = object.available_privileges(true);
let ok = privileges
.iter()
Expand All @@ -283,5 +288,26 @@ pub fn validate_grant_privileges(object: &GrantObject, privileges: UserPrivilege
"Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used",
));
}
if matches!(principal, PrincipalIdentity::User(_))
&& privileges.iter().any(is_create_ownership_object_privilege)
{
return Err(ErrorCode::IllegalGrant(
"CREATE-like privileges cannot be granted directly to USER; please grant them to a role"
));
}
Ok(())
}

fn is_create_ownership_object_privilege(privilege: UserPrivilegeType) -> bool {
matches!(
privilege,
UserPrivilegeType::Create
| UserPrivilegeType::CreateStage
| UserPrivilegeType::CreateDatabase
| UserPrivilegeType::CreateWarehouse
| UserPrivilegeType::CreateConnection
| UserPrivilegeType::CreateSequence
| UserPrivilegeType::CreateProcedure
| UserPrivilegeType::CreateMaskingPolicy
)
}
4 changes: 2 additions & 2 deletions src/query/users/tests/it/role_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async fn test_role_manager() -> Result<()> {
&tenant,
&role_name,
GrantObject::Global,
UserPrivilegeSet::all_privileges(),
UserPrivilegeSet::available_privileges_on_global(),
)
.await?;
let role = role_mgr.get_role(&tenant, role_name.clone()).await?;
Expand All @@ -118,7 +118,7 @@ async fn test_role_manager() -> Result<()> {
&tenant,
&role_name,
GrantObject::Global,
UserPrivilegeSet::all_privileges(),
UserPrivilegeSet::available_privileges_on_global(),
)
.await?;

Expand Down
4 changes: 2 additions & 2 deletions src/query/users/tests/it/user_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ async fn test_user_manager() -> Result<()> {
&tenant,
user_info.identity(),
GrantObject::Global,
UserPrivilegeSet::all_privileges(),
UserPrivilegeSet::available_privileges_on_global(),
)
.await?;
let user_info = user_mgr.get_user(&tenant, user_info.identity()).await?;
Expand All @@ -173,7 +173,7 @@ async fn test_user_manager() -> Result<()> {
&tenant,
user_info.identity(),
GrantObject::Global,
UserPrivilegeSet::all_privileges(),
UserPrivilegeSet::available_privileges_on_global(),
)
.await?;
let user_info = user_mgr.get_user(&tenant, user_info.identity()).await?;
Expand Down
50 changes: 46 additions & 4 deletions tests/nox/java_client/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
import requests
from requests.auth import HTTPBasicAuth
import time


def main():
Expand Down Expand Up @@ -29,21 +30,62 @@ def download_jdbc(version):
resp.raise_for_status()
target.write_bytes(resp.content)


def create_user():
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "CREATE USER IF NOT EXISTS databend IDENTIFIED BY 'databend'"},
json={"sql": "DROP USER IF EXISTS databend"},
).raise_for_status()
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "GRANT ALL ON *.* TO databend"},
json={"sql": "DROP ROLE IF EXISTS test_jdbc"},
).raise_for_status()
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "CREATE USER databend IDENTIFIED BY 'databend' with default_role='test_jdbc'"},
).raise_for_status()
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "CREATE ROLE test_jdbc"},
).raise_for_status()
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "GRANT ALL ON *.* TO ROLE test_jdbc"},
).raise_for_status()
requests.post(
"http://localhost:8000/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "GRANT ROLE test_jdbc TO USER databend"},
).raise_for_status()
time.sleep(16)
requests.post(
"http://localhost:8001/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "SHOW GRANTS FOR USER databend"},
).raise_for_status()
requests.post(
"http://localhost:8002/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "SHOW GRANTS FOR USER databend"},
).raise_for_status()
requests.post(
"http://localhost:8003/v1/query/",
auth=HTTPBasicAuth("root", ""),
headers={"Content-Type": "application/json"},
json={"sql": "SHOW GRANTS FOR USER databend"},
).raise_for_status()


def download_testng():
urls = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ grant role b to role a;
statement ok
grant role a to a;

statement ok
grant create database on *.* to a;

statement ok
set enable_expand_roles=1;

Expand All @@ -87,7 +84,7 @@ select grants from show_grants('user', 'a') order by object_id;
GRANT SELECT ON 'default'.'default'.'t' TO 'a'@'%'
GRANT OWNERSHIP ON 'default'.'default'.'t' TO 'a'@'%'
GRANT OWNERSHIP ON 'default'.'default'.'t1' TO 'a'@'%'
GRANT SELECT,INSERT,CREATE DATABASE ON *.* TO 'a'@'%'
GRANT SELECT,INSERT ON *.* TO 'a'@'%'

statement ok
set enable_expand_roles=0;
Expand All @@ -114,7 +111,6 @@ select grants from show_grants('user', 'a') order by object_id;
GRANT ROLE a to 'a'@'%'
GRANT ROLE b to 'a'@'%'
GRANT ROLE public to 'a'@'%'
GRANT CREATE DATABASE ON *.* TO 'a'@'%'

statement ok
unset enable_expand_roles;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ echo "create role drop_role;" | $BENDSQL_CLIENT_CONNECT
echo "create role drop_role1;" | $BENDSQL_CLIENT_CONNECT
echo "create user u1 identified by '123' with DEFAULT_ROLE='drop_role'" | $BENDSQL_CLIENT_CONNECT
echo "grant role drop_role to u1;" | $BENDSQL_CLIENT_CONNECT
echo "grant create database on *.* to u1;" | $BENDSQL_CLIENT_CONNECT
echo "grant create database on *.* to role drop_role;" | $BENDSQL_CLIENT_CONNECT
export USER_U1_CONNECT="bendsql --user=u1 --password=123 --host=${QUERY_MYSQL_HANDLER_HOST} --port ${QUERY_HTTP_HANDLER_PORT}"

echo "create database a" | $USER_U1_CONNECT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
1
>>>> revoke create on default.* from role role1
need failed: with 1063
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1,role2]
need failed: with 1063
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'owner'@'%' with roles [public,role1,role2]
>>>> grant ownership on default.v_t_owner to role role1
>>>> create view v_t as select * from t
>>>> create view v_t_union as select * from t union all select * from t_owner
'select * from v_t order by id' failed.
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1,role2]
>>>> grant select on default.v_t to owner
>>>> grant select on default.v_t_union to owner
1
Expand All @@ -43,7 +43,7 @@ Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is req
=== create view as select view ===
>>>> revoke select on default.v_t from owner
>>>> grant select on default.t to owner
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'v_t' for user 'owner'@'%' with roles [public,role1,role2]
>>>> grant select on default.v_t to owner
>>>> grant select on default.t to owner
>>>> grant select on default.v_t1 to owner
Expand Down
8 changes: 8 additions & 0 deletions tests/suites/0_stateless/18_rbac/18_0004_view_privilege.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ echo 'create table t_owner(c1 int)' | $TEST_USER_CONNECT
echo 'insert into t_owner values(2)' | $TEST_USER_CONNECT
stmt 'revoke create on default.* from role role1'

echo 'drop role if exists role2' | $BENDSQL_CLIENT_CONNECT
echo 'create role role2' | $BENDSQL_CLIENT_CONNECT
echo 'grant create on default.* to role role2' | $BENDSQL_CLIENT_CONNECT
echo 'grant role role2 to owner' | $BENDSQL_CLIENT_CONNECT
echo 'alter user owner with default_role=role2' | $BENDSQL_CLIENT_CONNECT

echo 'need failed: with 1063'
echo 'create view v_t as select * from t' | $TEST_USER_CONNECT

echo 'need failed: with 1063'
echo 'create view v_t_union as select * from t union all select * from t_owner' | $TEST_USER_CONNECT
echo 'create view v_t_owner as select * from t_owner' | $TEST_USER_CONNECT
Expand Down Expand Up @@ -67,3 +74,4 @@ stmt 'drop view if exists v_t_union'
stmt 'drop view if exists v_t1'
stmt 'drop user if exists owner'
stmt 'drop role if exists role1'
echo 'drop role if exists role2' | $BENDSQL_CLIENT_CONNECT
18 changes: 9 additions & 9 deletions tests/suites/0_stateless/18_rbac/18_0007_privilege_access.result
Original file line number Diff line number Diff line change
Expand Up @@ -113,28 +113,28 @@ Error: APIError: QueryFailed: [1063]Permission denied: No privilege on database
Error: APIError: QueryFailed: [1063]Permission denied: No privilege on table root_table for user b.
Error: APIError: QueryFailed: [1063]Permission denied: No privilege on table root_table for user b.
1 1
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t1' for user 'b'@'%' with roles [public]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'b'@'%' with roles [public]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t1' for user 'b'@'%' with roles [public]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t1' for user 'b'@'%' with roles [public,role_test_b]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public,role_test_b]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t' for user 'b'@'%' with roles [public,role_test_b]
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public,role_test_b]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Read] is required on STAGE s3 for user 'b'@'%' with roles [public,role_test_b]. Note: Please ensure that your current role have the appropriate permissions to create a new Object
Error: APIError: QueryFailed: [1063]Permission denied: privilege [Select] is required on 'default'.'default'.'t1' for user 'b'@'%' with roles [public,role_test_b]
0
1
a b/data_UUID_0000_00000000.parquet 1 0 NULL NULL
=== check db/table_id ===
Read s3 USER b GRANT Read ON STAGE s3 TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT system USER b GRANT SELECT ON 'default'.'system'.* TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT,INSERT,DELETE default.default.t USER b GRANT SELECT,INSERT,DELETE ON 'default'.'default'.'t' TO 'b'@'%'
SELECT default.default.t1 USER b GRANT SELECT ON 'default'.'default'.'t1' TO 'b'@'%'
SELECT,INSERT default.c.t USER b GRANT SELECT,INSERT ON 'default'.'c'.'t' TO 'b'@'%'
OWNERSHIP default.default.t2 USER b GRANT OWNERSHIP ON 'default'.'default'.'t2' TO 'b'@'%'
1
1
Read s3 USER b GRANT Read ON STAGE s3 TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT system USER b GRANT SELECT ON 'default'.'system'.* TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT,INSERT,DELETE default.default.t USER b GRANT SELECT,INSERT,DELETE ON 'default'.'default'.'t' TO 'b'@'%'
SELECT default.default.t1 USER b GRANT SELECT ON 'default'.'default'.'t1' TO 'b'@'%'
SELECT,INSERT default.c.t1 USER b GRANT SELECT,INSERT ON 'default'.'c'.'t1' TO 'b'@'%'
Expand All @@ -143,8 +143,8 @@ OWNERSHIP default.default.t2 USER b GRANT OWNERSHIP ON 'default'.'default'.'t2'
1
2
Read s3 USER b GRANT Read ON STAGE s3 TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT system USER b GRANT SELECT ON 'default'.'system'.* TO 'b'@'%'
CREATE default USER b GRANT CREATE ON 'default'.'default'.* TO 'b'@'%'
SELECT,INSERT,DELETE default.default.t USER b GRANT SELECT,INSERT,DELETE ON 'default'.'default'.'t' TO 'b'@'%'
SELECT default.default.t1 USER b GRANT SELECT ON 'default'.'default'.'t1' TO 'b'@'%'
SELECT,INSERT default.d.t1 USER b GRANT SELECT,INSERT ON 'default'.'d'.'t1' TO 'b'@'%'
Expand Down
7 changes: 6 additions & 1 deletion tests/suites/0_stateless/18_rbac/18_0007_privilege_access.sh
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ echo "drop stage if exists s3;" | $BENDSQL_CLIENT_CONNECT

echo "create table t(id int)" | $BENDSQL_CLIENT_CONNECT
echo "create table t1(id int)" | $BENDSQL_CLIENT_CONNECT
echo "grant create on default.* to b" | $BENDSQL_CLIENT_CONNECT
echo "drop role if exists role_test_b" | $BENDSQL_CLIENT_CONNECT
echo "create role role_test_b" | $BENDSQL_CLIENT_CONNECT
echo "grant role role_test_b to b" | $BENDSQL_CLIENT_CONNECT
echo "grant create on default.* to role role_test_b" | $BENDSQL_CLIENT_CONNECT
echo "alter user b with default_role=role_test_b" | $BENDSQL_CLIENT_CONNECT
echo "grant insert, delete on default.t to b" | $BENDSQL_CLIENT_CONNECT
echo "grant select on system.* to b" | $BENDSQL_CLIENT_CONNECT

Expand Down Expand Up @@ -328,4 +332,5 @@ echo "SET variable a = 'a';" | $USER_C_CONNECT
echo "set global max_threads=1000;" | $USER_C_CONNECT 2>&1 | grep "Super" | wc -l
echo "unset global max_threads;" | $USER_C_CONNECT 2>&1 | grep "Super" | wc -l
echo "drop user if exists c" | $BENDSQL_CLIENT_CONNECT
echo "drop role if exists role_test_b" | $BENDSQL_CLIENT_CONNECT
echo "=== set privilege check succ ==="
Loading