diff --git a/src/storage.rs b/src/storage.rs index a140b28ffc9b40f7dee20da0eef1d0898568c6c9..26491364837d38bd6f33deb956f4dd9197dc9ceb 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -2307,14 +2307,14 @@ impl SchemaDef for UserDef { #[inline(always)] fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_create_user_on_master(self)?; + acl::on_master_create_user(self)?; Ok(()) } #[inline(always)] fn on_delete(user_id: &UserId, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_drop_user_on_master(*user_id)?; + acl::on_master_drop_user(*user_id)?; Ok(()) } } @@ -2335,14 +2335,14 @@ impl SchemaDef for RoleDef { #[inline(always)] fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_create_role_on_master(self)?; + acl::on_master_create_role(self)?; Ok(()) } #[inline(always)] fn on_delete(user_id: &UserId, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_drop_role_on_master(*user_id)?; + acl::on_master_drop_role(*user_id)?; Ok(()) } } @@ -2363,236 +2363,244 @@ impl SchemaDef for PrivilegeDef { #[inline(always)] fn on_insert(&self, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_grant_privilege_on_master(self)?; + acl::on_master_grant_privilege(self)?; Ok(()) } #[inline(always)] fn on_delete(this: &Self, storage: &Clusterwide) -> traft::Result<()> { _ = storage; - acl_revoke_privilege_on_master(this)?; + acl::on_master_revoke_privilege(this)?; Ok(()) } } //////////////////////////////////////////////////////////////////////////////// -// acl global +// acl //////////////////////////////////////////////////////////////////////////////// -/// Persist a user definition in the internal clusterwide storage. -pub fn acl_global_create_user(storage: &Clusterwide, user_def: &UserDef) -> tarantool::Result<()> { - storage.users.insert(user_def)?; - Ok(()) -} +pub mod acl { + use super::*; -/// Remove a user definition and any entities owned by it from the internal -/// clusterwide storage. -pub fn acl_global_change_user_auth( - storage: &Clusterwide, - user_id: UserId, - auth: &AuthDef, -) -> tarantool::Result<()> { - storage.users.update_auth(user_id, auth)?; - Ok(()) -} + //////////////////////////////////////////////////////////////////////////// + // acl in global storage + //////////////////////////////////////////////////////////////////////////// -/// Remove a user definition and any entities owned by it from the internal -/// clusterwide storage. -pub fn acl_global_drop_user(storage: &Clusterwide, user_id: UserId) -> tarantool::Result<()> { - storage.privileges.delete_all_by_grantee_id(user_id)?; - storage.users.delete(user_id)?; - Ok(()) -} + /// Persist a user definition in the internal clusterwide storage. + pub fn global_create_user(storage: &Clusterwide, user_def: &UserDef) -> tarantool::Result<()> { + storage.users.insert(user_def)?; + Ok(()) + } -/// Persist a role definition in the internal clusterwide storage. -pub fn acl_global_create_role(storage: &Clusterwide, role_def: &RoleDef) -> tarantool::Result<()> { - storage.roles.insert(role_def)?; - Ok(()) -} + /// Remove a user definition and any entities owned by it from the internal + /// clusterwide storage. + pub fn global_change_user_auth( + storage: &Clusterwide, + user_id: UserId, + auth: &AuthDef, + ) -> tarantool::Result<()> { + storage.users.update_auth(user_id, auth)?; + Ok(()) + } -/// Remove a role definition and any entities owned by it from the internal -/// clusterwide storage. -pub fn acl_global_drop_role(storage: &Clusterwide, role_id: UserId) -> Result<()> { - storage.privileges.delete_all_by_grantee_id(role_id)?; - if let Some(role_def) = storage.roles.by_id(role_id)? { - // Revoke the role from any grantees. - storage - .privileges - .delete_all_by_granted_role(&role_def.name)?; - storage.roles.delete(role_id)?; + /// Remove a user definition and any entities owned by it from the internal + /// clusterwide storage. + pub fn global_drop_user(storage: &Clusterwide, user_id: UserId) -> tarantool::Result<()> { + storage.privileges.delete_all_by_grantee_id(user_id)?; + storage.users.delete(user_id)?; + Ok(()) } - Ok(()) -} -/// Persist a privilege definition in the internal clusterwide storage. -pub fn acl_global_grant_privilege( - storage: &Clusterwide, - priv_def: &PrivilegeDef, -) -> tarantool::Result<()> { - storage.privileges.insert(priv_def)?; - Ok(()) -} + /// Persist a role definition in the internal clusterwide storage. + pub fn global_create_role(storage: &Clusterwide, role_def: &RoleDef) -> tarantool::Result<()> { + storage.roles.insert(role_def)?; + Ok(()) + } -/// Remove a privilege definition from the internal clusterwide storage. -pub fn acl_global_revoke_privilege( - storage: &Clusterwide, - priv_def: &PrivilegeDef, -) -> tarantool::Result<()> { - // FIXME: currently there's no way to revoke a default privilege - storage.privileges.delete( - priv_def.grantee_id, - &priv_def.object_type, - &priv_def.object_name, - &priv_def.privilege, - )?; + /// Remove a role definition and any entities owned by it from the internal + /// clusterwide storage. + pub fn global_drop_role(storage: &Clusterwide, role_id: UserId) -> Result<()> { + storage.privileges.delete_all_by_grantee_id(role_id)?; + if let Some(role_def) = storage.roles.by_id(role_id)? { + // Revoke the role from any grantees. + storage + .privileges + .delete_all_by_granted_role(&role_def.name)?; + storage.roles.delete(role_id)?; + } + Ok(()) + } - Ok(()) -} + /// Persist a privilege definition in the internal clusterwide storage. + pub fn global_grant_privilege( + storage: &Clusterwide, + priv_def: &PrivilegeDef, + ) -> tarantool::Result<()> { + storage.privileges.insert(priv_def)?; + Ok(()) + } -//////////////////////////////////////////////////////////////////////////////// -// acl -//////////////////////////////////////////////////////////////////////////////// + /// Remove a privilege definition from the internal clusterwide storage. + pub fn global_revoke_privilege( + storage: &Clusterwide, + priv_def: &PrivilegeDef, + ) -> tarantool::Result<()> { + // FIXME: currently there's no way to revoke a default privilege + storage.privileges.delete( + priv_def.grantee_id, + &priv_def.object_type, + &priv_def.object_name, + &priv_def.privilege, + )?; -/// Create a tarantool user. Grant it default privileges. -pub fn acl_create_user_on_master(user_def: &UserDef) -> tarantool::Result<()> { - let sys_user = Space::from(SystemSpace::User); + Ok(()) + } + + //////////////////////////////////////////////////////////////////////////// + // acl in local storage on replicaset leader + //////////////////////////////////////////////////////////////////////////// - // This impelemtation was copied from box.schema.user.create excluding the - // password hashing. - let user_id = user_def.id; - let euid = ::tarantool::session::euid()?; + /// Create a tarantool user. Grant it default privileges. + pub fn on_master_create_user(user_def: &UserDef) -> tarantool::Result<()> { + let sys_user = Space::from(SystemSpace::User); - // Tarantool expects auth info to be a map of form `{ method: data }`, - // and currently the simplest way to achieve this is to use a HashMap. - let auth_map = HashMap::from([(user_def.auth.method, &user_def.auth.data)]); - sys_user.insert(&(user_id, euid, &user_def.name, "user", auth_map, &[(); 0], 0))?; + // This impelemtation was copied from box.schema.user.create excluding the + // password hashing. + let user_id = user_def.id; + let euid = ::tarantool::session::euid()?; - let lua = ::tarantool::lua_state(); - lua.exec_with("box.schema.user.grant(...)", (user_id, "public")) + // Tarantool expects auth info to be a map of form `{ method: data }`, + // and currently the simplest way to achieve this is to use a HashMap. + let auth_map = HashMap::from([(user_def.auth.method, &user_def.auth.data)]); + sys_user.insert(&(user_id, euid, &user_def.name, "user", auth_map, &[(); 0], 0))?; + + let lua = ::tarantool::lua_state(); + lua.exec_with("box.schema.user.grant(...)", (user_id, "public")) + .map_err(LuaError::from)?; + lua.exec_with( + "box.schema.user.grant(...)", + (user_id, "alter", "user", user_id), + ) + .map_err(LuaError::from)?; + lua.exec_with( + "box.session.su('admin', box.schema.user.grant, ...)", + ( + user_id, + "session,usage", + "universe", + tlua::Nil, + tlua::AsTable((("if_not_exists", true),)), + ), + ) .map_err(LuaError::from)?; - lua.exec_with( - "box.schema.user.grant(...)", - (user_id, "alter", "user", user_id), - ) - .map_err(LuaError::from)?; - lua.exec_with( - "box.session.su('admin', box.schema.user.grant, ...)", - ( - user_id, - "session,usage", - "universe", - tlua::Nil, - tlua::AsTable((("if_not_exists", true),)), - ), - ) - .map_err(LuaError::from)?; - Ok(()) -} + Ok(()) + } -/// Update a tarantool user's authentication details. -pub fn acl_change_user_auth_on_master(user_id: UserId, auth: &AuthDef) -> tarantool::Result<()> { - const USER_FIELD_AUTH: i32 = 4; - const USER_FIELD_LAST_MODIFIED: i32 = 6; - let sys_user = Space::from(SystemSpace::User); + /// Update a tarantool user's authentication details. + pub fn on_master_change_user_auth(user_id: UserId, auth: &AuthDef) -> tarantool::Result<()> { + const USER_FIELD_AUTH: i32 = 4; + const USER_FIELD_LAST_MODIFIED: i32 = 6; + let sys_user = Space::from(SystemSpace::User); - // Tarantool expects auth info to be a map of form `{ method: data }`, - // and currently the simplest way to achieve this is to use a HashMap. - let auth_map = HashMap::from([(auth.method, &auth.data)]); - let mut ops = UpdateOps::with_capacity(2); - ops.assign(USER_FIELD_AUTH, auth_map)?; - ops.assign(USER_FIELD_LAST_MODIFIED, fiber::time() as u64)?; - sys_user.update(&[user_id], ops)?; - Ok(()) -} + // Tarantool expects auth info to be a map of form `{ method: data }`, + // and currently the simplest way to achieve this is to use a HashMap. + let auth_map = HashMap::from([(auth.method, &auth.data)]); + let mut ops = UpdateOps::with_capacity(2); + ops.assign(USER_FIELD_AUTH, auth_map)?; + ops.assign(USER_FIELD_LAST_MODIFIED, fiber::time() as u64)?; + sys_user.update(&[user_id], ops)?; + Ok(()) + } -/// Drop a tarantool user and any entities (spaces, etc.) owned by it. -pub fn acl_drop_user_on_master(user_id: UserId) -> tarantool::Result<()> { - let lua = ::tarantool::lua_state(); - lua.exec_with("box.schema.user.drop(...)", user_id) - .map_err(LuaError::from)?; + /// Drop a tarantool user and any entities (spaces, etc.) owned by it. + pub fn on_master_drop_user(user_id: UserId) -> tarantool::Result<()> { + let lua = ::tarantool::lua_state(); + lua.exec_with("box.schema.user.drop(...)", user_id) + .map_err(LuaError::from)?; - Ok(()) -} + Ok(()) + } -/// Create a tarantool role. -pub fn acl_create_role_on_master(role_def: &RoleDef) -> tarantool::Result<()> { - let sys_user = Space::from(SystemSpace::User); + /// Create a tarantool role. + pub fn on_master_create_role(role_def: &RoleDef) -> tarantool::Result<()> { + let sys_user = Space::from(SystemSpace::User); - // This impelemtation was copied from box.schema.role.create. + // This impelemtation was copied from box.schema.role.create. - // Tarantool expects auth info to be a map `{}`, and currently the simplest - // way to achieve this is to use a HashMap. - sys_user.insert(&( - role_def.id, - ::tarantool::session::euid()?, - &role_def.name, - "role", - HashMap::<(), ()>::new(), - &[(); 0], - 0, - ))?; + // Tarantool expects auth info to be a map `{}`, and currently the simplest + // way to achieve this is to use a HashMap. + sys_user.insert(&( + role_def.id, + ::tarantool::session::euid()?, + &role_def.name, + "role", + HashMap::<(), ()>::new(), + &[(); 0], + 0, + ))?; - Ok(()) -} + Ok(()) + } -/// Drop a tarantool role and revoke it from anybody it was assigned to. -pub fn acl_drop_role_on_master(role_id: UserId) -> tarantool::Result<()> { - let lua = ::tarantool::lua_state(); - lua.exec_with("box.schema.role.drop(...)", role_id) - .map_err(LuaError::from)?; + /// Drop a tarantool role and revoke it from anybody it was assigned to. + pub fn on_master_drop_role(role_id: UserId) -> tarantool::Result<()> { + let lua = ::tarantool::lua_state(); + lua.exec_with("box.schema.role.drop(...)", role_id) + .map_err(LuaError::from)?; - Ok(()) -} + Ok(()) + } -/// Grant a tarantool user some privilege defined by `priv_def`. -pub fn acl_grant_privilege_on_master(priv_def: &PrivilegeDef) -> tarantool::Result<()> { - let lua = ::tarantool::lua_state(); - lua.exec_with( - "local grantee_id, privilege, object_type, object_name = ... - local grantee_def = box.space._user:get(grantee_id) - if grantee_def.type == 'user' then - box.schema.user.grant(grantee_id, privilege, object_type, object_name) - else - box.schema.role.grant(grantee_id, privilege, object_type, object_name) - end", - ( - priv_def.grantee_id, - &priv_def.privilege, - &priv_def.object_type, - &priv_def.object_name, - ), - ) - .map_err(LuaError::from)?; + /// Grant a tarantool user some privilege defined by `priv_def`. + pub fn on_master_grant_privilege(priv_def: &PrivilegeDef) -> tarantool::Result<()> { + let lua = ::tarantool::lua_state(); + lua.exec_with( + "local grantee_id, privilege, object_type, object_name = ... + local grantee_def = box.space._user:get(grantee_id) + if grantee_def.type == 'user' then + box.schema.user.grant(grantee_id, privilege, object_type, object_name) + else + box.schema.role.grant(grantee_id, privilege, object_type, object_name) + end", + ( + priv_def.grantee_id, + &priv_def.privilege, + &priv_def.object_type, + &priv_def.object_name, + ), + ) + .map_err(LuaError::from)?; - Ok(()) -} + Ok(()) + } -/// Revoke a privilege from a tarantool user. -pub fn acl_revoke_privilege_on_master(priv_def: &PrivilegeDef) -> tarantool::Result<()> { - let lua = ::tarantool::lua_state(); - lua.exec_with( - "local grantee_id, privilege, object_type, object_name = ... - local grantee_def = box.space._user:get(grantee_id) - if not grantee_def then - -- Grantee already dropped -> privileges already revoked - return - end - if grantee_def.type == 'user' then - box.schema.user.revoke(grantee_id, privilege, object_type, object_name) - else - box.schema.role.revoke(grantee_id, privilege, object_type, object_name) - end", - ( - priv_def.grantee_id, - &priv_def.privilege, - &priv_def.object_type, - &priv_def.object_name, - ), - ) - .map_err(LuaError::from)?; + /// Revoke a privilege from a tarantool user. + pub fn on_master_revoke_privilege(priv_def: &PrivilegeDef) -> tarantool::Result<()> { + let lua = ::tarantool::lua_state(); + lua.exec_with( + "local grantee_id, privilege, object_type, object_name = ... + local grantee_def = box.space._user:get(grantee_id) + if not grantee_def then + -- Grantee already dropped -> privileges already revoked + return + end + if grantee_def.type == 'user' then + box.schema.user.revoke(grantee_id, privilege, object_type, object_name) + else + box.schema.role.revoke(grantee_id, privilege, object_type, object_name) + end", + ( + priv_def.grantee_id, + &priv_def.privilege, + &priv_def.object_type, + &priv_def.object_name, + ), + ) + .map_err(LuaError::from)?; - Ok(()) + Ok(()) + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/traft/node.rs b/src/traft/node.rs index e392826fff3c19f6d2ef1b5db5c6beae53e84cf4..ab3e8f366380b281d0b5c286fcca188dbb001d10 100644 --- a/src/traft/node.rs +++ b/src/traft/node.rs @@ -13,16 +13,10 @@ use crate::loop_start; use crate::r#loop::FlowControl; use crate::rpc; use crate::schema::{Distribution, IndexDef, SpaceDef}; +use crate::storage::acl; use crate::storage::ddl_meta_drop_space; use crate::storage::SnapshotData; use crate::storage::ToEntryIter as _; -use crate::storage::{ - acl_change_user_auth_on_master, acl_create_role_on_master, acl_create_user_on_master, - acl_drop_role_on_master, acl_drop_user_on_master, acl_global_change_user_auth, - acl_global_create_role, acl_global_create_user, acl_global_drop_role, acl_global_drop_user, - acl_global_grant_privilege, acl_global_revoke_privilege, acl_grant_privilege_on_master, - acl_revoke_privilege_on_master, -}; use crate::storage::{ddl_abort_on_master, ddl_meta_space_update_operable}; use crate::storage::{local_schema_version, set_local_schema_version}; use crate::storage::{Clusterwide, ClusterwideSpaceId, PropertyName}; @@ -987,31 +981,31 @@ impl NodeImpl { } else { match &acl { Acl::CreateUser { user_def } => { - acl_create_user_on_master(user_def) + acl::on_master_create_user(user_def) .expect("creating user shouldn't fail"); } Acl::ChangeAuth { user_id, auth, .. } => { - acl_change_user_auth_on_master(*user_id, auth) + acl::on_master_change_user_auth(*user_id, auth) .expect("changing user auth shouldn't fail"); } Acl::DropUser { user_id, .. } => { - acl_drop_user_on_master(*user_id) + acl::on_master_drop_user(*user_id) .expect("droping user shouldn't fail"); } Acl::CreateRole { role_def } => { - acl_create_role_on_master(role_def) + acl::on_master_create_role(role_def) .expect("creating role shouldn't fail"); } Acl::DropRole { role_id, .. } => { - acl_drop_role_on_master(*role_id) + acl::on_master_drop_role(*role_id) .expect("droping role shouldn't fail"); } Acl::GrantPrivilege { priv_def } => { - acl_grant_privilege_on_master(priv_def) + acl::on_master_grant_privilege(priv_def) .expect("granting a privilege shouldn't fail"); } Acl::RevokePrivilege { priv_def } => { - acl_revoke_privilege_on_master(priv_def) + acl::on_master_revoke_privilege(priv_def) .expect("revoking a privilege shouldn't fail"); } } @@ -1021,31 +1015,31 @@ impl NodeImpl { match &acl { Acl::CreateUser { user_def } => { - acl_global_create_user(&self.storage, user_def) + acl::global_create_user(&self.storage, user_def) .expect("persisting a user definition shouldn't fail"); } Acl::ChangeAuth { user_id, auth, .. } => { - acl_global_change_user_auth(&self.storage, *user_id, auth) + acl::global_change_user_auth(&self.storage, *user_id, auth) .expect("changing user definition shouldn't fail"); } Acl::DropUser { user_id, .. } => { - acl_global_drop_user(&self.storage, *user_id) + acl::global_drop_user(&self.storage, *user_id) .expect("droping a user definition shouldn't fail"); } Acl::CreateRole { role_def } => { - acl_global_create_role(&self.storage, role_def) + acl::global_create_role(&self.storage, role_def) .expect("persisting a role definition shouldn't fail"); } Acl::DropRole { role_id, .. } => { - acl_global_drop_role(&self.storage, *role_id) + acl::global_drop_role(&self.storage, *role_id) .expect("droping a role definition shouldn't fail"); } Acl::GrantPrivilege { priv_def } => { - acl_global_grant_privilege(&self.storage, priv_def) + acl::global_grant_privilege(&self.storage, priv_def) .expect("persiting a privilege definition shouldn't fail"); } Acl::RevokePrivilege { priv_def } => { - acl_global_revoke_privilege(&self.storage, priv_def) + acl::global_revoke_privilege(&self.storage, priv_def) .expect("removing a privilege definition shouldn't fail"); } }