From 1a46b07a93bdec4989e36555ed2a3c044d951eb6 Mon Sep 17 00:00:00 2001 From: BohuTANG Date: Sun, 7 Nov 2021 21:39:02 +0800 Subject: [PATCH 1/2] USER-2678: Add user privileges --- Cargo.lock | 22 +++++++ common/management/src/user/user_api.rs | 7 +- common/meta/types/Cargo.toml | 2 +- common/meta/types/src/lib.rs | 9 ++- .../meta/types/src/{user.rs => user_auth.rs} | 0 common/meta/types/src/user_privilege.rs | 65 +++++++++++++++++++ common/meta/types/src/user_privilege_test.rs | 35 ++++++++++ .../interpreters/interpreter_user_create.rs | 2 + query/src/users/user.rs | 3 + 9 files changed, 141 insertions(+), 4 deletions(-) rename common/meta/types/src/{user.rs => user_auth.rs} (100%) create mode 100644 common/meta/types/src/user_privilege.rs create mode 100644 common/meta/types/src/user_privilege_test.rs diff --git a/Cargo.lock b/Cargo.lock index 0de3ba6b9289a..5ae2a67ded1c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1491,6 +1491,7 @@ dependencies = [ "common-datavalues", "common-exception", "derive_more", + "enumflags2", "pretty_assertions", "serde", "serde_json", @@ -2378,6 +2379,27 @@ dependencies = [ "syn", ] +[[package]] +name = "enumflags2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8672257d642ffdd235f6e9c723c2326ac1253c8f3c022e7cfd2e57da55b1131" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33526f770a27828ce7c2792fdb7cb240220237e0ff12933ed6c23957fc5dd7cf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.8.4" diff --git a/common/management/src/user/user_api.rs b/common/management/src/user/user_api.rs index 1275b6f060522..cf550ff3e8092 100644 --- a/common/management/src/user/user_api.rs +++ b/common/management/src/user/user_api.rs @@ -19,13 +19,15 @@ use common_exception::ErrorCode; use common_exception::Result; use common_meta_types::AuthType; use common_meta_types::SeqV; +use common_meta_types::UserPrivilege; -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq)] pub struct UserInfo { pub name: String, pub host_name: String, pub password: Vec, pub auth_type: AuthType, + pub privileges: UserPrivilege, } impl UserInfo { @@ -35,11 +37,14 @@ impl UserInfo { password: Vec, auth_type: AuthType, ) -> Self { + // Default is no privileges. + let privileges = UserPrivilege::empty(); UserInfo { name, host_name, password, auth_type, + privileges, } } } diff --git a/common/meta/types/Cargo.toml b/common/meta/types/Cargo.toml index 1b9abc86a96fa..a2c3c66f5bd1e 100644 --- a/common/meta/types/Cargo.toml +++ b/common/meta/types/Cargo.toml @@ -12,9 +12,9 @@ common-exception = {path = "../../exception"} async-raft = { git = "https://github.com/datafuse-extras/async-raft", tag = "v0.6.2-alpha.14" } derive_more = "0.99.16" +enumflags2 = {version = "0.7.1", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" - [dev-dependencies] pretty_assertions = "1.0" diff --git a/common/meta/types/src/lib.rs b/common/meta/types/src/lib.rs index 409ef7ac41607..2951b2ca516bc 100644 --- a/common/meta/types/src/lib.rs +++ b/common/meta/types/src/lib.rs @@ -18,6 +18,8 @@ mod cluster_test; #[cfg(test)] mod match_seq_test; +#[cfg(test)] +mod user_privilege_test; pub use change::AddResult; pub use change::Change; @@ -52,7 +54,9 @@ pub use table_info::TableIdent; pub use table_info::TableInfo; pub use table_info::TableMeta; pub use table_reply::CreateTableReply; -pub use user::AuthType; +pub use user_auth::AuthType; +pub use user_privilege::UserPrivilege; +pub use user_privilege::UserPrivilegeType; mod change; mod cluster; @@ -71,4 +75,5 @@ mod seq_num; mod seq_value; mod table_info; mod table_reply; -mod user; +mod user_auth; +mod user_privilege; diff --git a/common/meta/types/src/user.rs b/common/meta/types/src/user_auth.rs similarity index 100% rename from common/meta/types/src/user.rs rename to common/meta/types/src/user_auth.rs diff --git a/common/meta/types/src/user_privilege.rs b/common/meta/types/src/user_privilege.rs new file mode 100644 index 0000000000000..ad34d43d64eb6 --- /dev/null +++ b/common/meta/types/src/user_privilege.rs @@ -0,0 +1,65 @@ +// Copyright 2021 Datafuse Labs. +// +// Licensed 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. + +use enumflags2::bitflags; +use enumflags2::make_bitflags; +use enumflags2::BitFlags; + +#[bitflags] +#[repr(u64)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Eq, PartialEq)] +pub enum UserPrivilegeType { + // UsagePrivilege is a synonym for “no privileges” + Usage = 1 << 0, + // Privilege to create databases and tables. + Create = 1 << 1, + // Privilege to select rows from tables in a database. + Select = 1 << 2, + // Privilege to insert into tables in a database. + Insert = 1 << 3, + // Privilege to SET variables. + Set = 1 << 4, +} + +const ALL_PRIVILEGES: BitFlags = make_bitflags!( + UserPrivilegeType::{Create + | Select + | Insert + | Set} +); + +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, Eq, PartialEq)] +pub struct UserPrivilege { + privileges: BitFlags, +} + +impl UserPrivilege { + pub fn empty() -> Self { + UserPrivilege { + privileges: BitFlags::empty(), + } + } + + pub fn set_privilege(&mut self, privilege: UserPrivilegeType) { + self.privileges |= privilege; + } + + pub fn has_privilege(&mut self, privilege: UserPrivilegeType) -> bool { + self.privileges.contains(privilege) + } + + pub fn set_all_privileges(&mut self) { + self.privileges |= ALL_PRIVILEGES; + } +} diff --git a/common/meta/types/src/user_privilege_test.rs b/common/meta/types/src/user_privilege_test.rs new file mode 100644 index 0000000000000..430f6c65898ea --- /dev/null +++ b/common/meta/types/src/user_privilege_test.rs @@ -0,0 +1,35 @@ +// Copyright 2021 Datafuse Labs. +// +// Licensed 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. + +use common_exception::exception::Result; + +use crate::UserPrivilege; +use crate::UserPrivilegeType; + +#[test] +fn test_user_privilege() -> Result<()> { + let mut privileges = UserPrivilege::empty(); + let r = privileges.has_privilege(UserPrivilegeType::Set); + assert!(!r); + + privileges.set_privilege(UserPrivilegeType::Set); + let r = privileges.has_privilege(UserPrivilegeType::Set); + assert!(r); + + privileges.set_all_privileges(); + let r = privileges.has_privilege(UserPrivilegeType::Create); + assert!(r); + + Ok(()) +} diff --git a/query/src/interpreters/interpreter_user_create.rs b/query/src/interpreters/interpreter_user_create.rs index f20b6db909ddc..2cc4a14ddc0f9 100644 --- a/query/src/interpreters/interpreter_user_create.rs +++ b/query/src/interpreters/interpreter_user_create.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use common_exception::Result; use common_management::UserInfo; +use common_meta_types::UserPrivilege; use common_planners::CreateUserPlan; use common_streams::DataBlockStream; use common_streams::SendableDataBlockStream; @@ -55,6 +56,7 @@ impl Interpreter for CreatUserInterpreter { host_name: plan.host_name, password: plan.password, auth_type: plan.auth_type, + privileges: UserPrivilege::empty(), }; user_mgr.add_user(user_info).await?; diff --git a/query/src/users/user.rs b/query/src/users/user.rs index fcbe5d801421f..5f67023559e83 100644 --- a/query/src/users/user.rs +++ b/query/src/users/user.rs @@ -15,6 +15,7 @@ use common_management::UserInfo; use common_meta_types::AuthType; +use common_meta_types::UserPrivilege; #[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct User { @@ -42,11 +43,13 @@ impl User { impl From<&User> for UserInfo { fn from(user: &User) -> Self { + let privileges = UserPrivilege::empty(); UserInfo { name: user.name.clone(), host_name: user.host_name.clone(), password: Vec::from(user.password.clone()), auth_type: user.auth_type.clone(), + privileges, } } } From 157ef1fb573044c32f0bdaf1ec2b12a3fc38370e Mon Sep 17 00:00:00 2001 From: BohuTANG Date: Mon, 8 Nov 2021 19:02:25 +0800 Subject: [PATCH 2/2] USER-2678: Fix the user tables test --- query/src/datasources/database/system/users_table_test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/query/src/datasources/database/system/users_table_test.rs b/query/src/datasources/database/system/users_table_test.rs index 2b0cac95dab72..a48643f039fae 100644 --- a/query/src/datasources/database/system/users_table_test.rs +++ b/query/src/datasources/database/system/users_table_test.rs @@ -18,6 +18,7 @@ use common_base::tokio; use common_exception::Result; use common_management::UserInfo; use common_meta_types::AuthType; +use common_meta_types::UserPrivilege; use futures::TryStreamExt; use pretty_assertions::assert_eq; @@ -36,6 +37,7 @@ async fn test_users_table() -> Result<()> { hostname: "localhost".to_string(), password: Vec::from(""), auth_type: AuthType::None, + privileges: UserPrivilege::empty(), }) .await?; ctx.get_sessions_manager() @@ -45,6 +47,7 @@ async fn test_users_table() -> Result<()> { hostname: "%".to_string(), password: Vec::from("123456789"), auth_type: AuthType::PlainText, + privileges: UserPrivilege::empty(), }) .await?;