acl api: implement update
This commit is contained in:
parent
ed3e60ae69
commit
9765092ede
@ -1,8 +1,7 @@
|
|||||||
use failure::*;
|
use failure::*;
|
||||||
use serde_json::Value;
|
|
||||||
use ::serde::{Deserialize, Serialize};
|
use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment};
|
use proxmox::api::{api, Router, RpcEnvironment};
|
||||||
use proxmox::api::schema::{Schema, StringSchema, BooleanSchema, ApiStringFormat};
|
use proxmox::api::schema::{Schema, StringSchema, BooleanSchema, ApiStringFormat};
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use crate::api2::types::*;
|
||||||
@ -27,7 +26,14 @@ pub const ACL_UGID_TYPE_SCHEMA: Schema = StringSchema::new(
|
|||||||
|
|
||||||
pub const ACL_ROLE_SCHEMA: Schema = StringSchema::new(
|
pub const ACL_ROLE_SCHEMA: Schema = StringSchema::new(
|
||||||
"Role.")
|
"Role.")
|
||||||
.format(&ApiStringFormat::Enum(&["Admin", "User", "Audit", "NoAccess"]))
|
.format(&ApiStringFormat::Enum(&[
|
||||||
|
"Admin",
|
||||||
|
"Audit",
|
||||||
|
"Datastore.Admin",
|
||||||
|
"Datastore.Audit",
|
||||||
|
"Datastore.User",
|
||||||
|
"NoAccess",
|
||||||
|
]))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
@ -109,7 +115,8 @@ pub fn read_acl(
|
|||||||
|
|
||||||
//let auth_user = rpcenv.get_user().unwrap();
|
//let auth_user = rpcenv.get_user().unwrap();
|
||||||
|
|
||||||
let (tree, digest) = acl::config()?;
|
// fixme: return digest?
|
||||||
|
let (tree, _digest) = acl::config()?;
|
||||||
|
|
||||||
let mut list: Vec<AclListItem> = Vec::new();
|
let mut list: Vec<AclListItem> = Vec::new();
|
||||||
extract_acl_node_data(&tree.root, "", &mut list);
|
extract_acl_node_data(&tree.root, "", &mut list);
|
||||||
@ -117,5 +124,86 @@ pub fn read_acl(
|
|||||||
Ok(list)
|
Ok(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
input: {
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
schema: ACL_PATH_SCHEMA,
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
schema: ACL_ROLE_SCHEMA,
|
||||||
|
},
|
||||||
|
propagate: {
|
||||||
|
optional: true,
|
||||||
|
schema: ACL_PROPAGATE_SCHEMA,
|
||||||
|
},
|
||||||
|
userid: {
|
||||||
|
optional: true,
|
||||||
|
schema: PROXMOX_USER_ID_SCHEMA,
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
optional: true,
|
||||||
|
schema: PROXMOX_GROUP_ID_SCHEMA,
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
optional: true,
|
||||||
|
description: "Remove permissions (instead of adding it).",
|
||||||
|
type: bool,
|
||||||
|
},
|
||||||
|
digest: {
|
||||||
|
optional: true,
|
||||||
|
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
/// Update Access Control List (ACLs).
|
||||||
|
pub fn update_acl(
|
||||||
|
path: String,
|
||||||
|
role: String,
|
||||||
|
propagate: Option<bool>,
|
||||||
|
userid: Option<String>,
|
||||||
|
group: Option<String>,
|
||||||
|
delete: Option<bool>,
|
||||||
|
digest: Option<String>,
|
||||||
|
_rpcenv: &mut dyn RpcEnvironment,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let _lock = crate::tools::open_file_locked(acl::ACL_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
|
||||||
|
|
||||||
|
let (mut tree, expected_digest) = acl::config()?;
|
||||||
|
|
||||||
|
if let Some(ref digest) = digest {
|
||||||
|
let digest = proxmox::tools::hex_to_digest(digest)?;
|
||||||
|
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixme: test if user/group exists?
|
||||||
|
|
||||||
|
// fixme: let propagate = propagate.unwrap_or(api_get_default!("propagate"));
|
||||||
|
let propagate = propagate.unwrap_or(true);
|
||||||
|
|
||||||
|
let delete = delete.unwrap_or(false);
|
||||||
|
|
||||||
|
if let Some(userid) = userid {
|
||||||
|
if delete {
|
||||||
|
tree.delete_user_role(&path, &userid, &role);
|
||||||
|
} else {
|
||||||
|
tree.insert_user_role(&path, &userid, &role, propagate);
|
||||||
|
}
|
||||||
|
} else if let Some(group) = group {
|
||||||
|
if delete {
|
||||||
|
tree.delete_group_role(&path, &group, &role);
|
||||||
|
} else {
|
||||||
|
tree.insert_group_role(&path, &group, &role, propagate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acl::save_config(&tree)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub const ROUTER: Router = Router::new()
|
pub const ROUTER: Router = Router::new()
|
||||||
.get(&API_METHOD_READ_ACL);
|
.get(&API_METHOD_READ_ACL)
|
||||||
|
.put(&API_METHOD_UPDATE_ACL);
|
||||||
|
@ -25,6 +25,7 @@ macro_rules! DNS_NAME { () => (concat!(r"(?:", DNS_LABEL!() , r"\.)*", DNS_LABEL
|
|||||||
// slash is not allowed because it is used as pve API delimiter
|
// slash is not allowed because it is used as pve API delimiter
|
||||||
// also see "man useradd"
|
// also see "man useradd"
|
||||||
macro_rules! USER_NAME_REGEX_STR { () => (r"(?:[^\s:/[:cntrl:]]+)") }
|
macro_rules! USER_NAME_REGEX_STR { () => (r"(?:[^\s:/[:cntrl:]]+)") }
|
||||||
|
macro_rules! GROUP_NAME_REGEX_STR { () => (USER_NAME_REGEX_STR!()) }
|
||||||
|
|
||||||
macro_rules! PROXMOX_SAFE_ID_REGEX_STR { () => (r"(?:[A-Za-z0-9_][A-Za-z0-9._\-]*)") }
|
macro_rules! PROXMOX_SAFE_ID_REGEX_STR { () => (r"(?:[A-Za-z0-9_][A-Za-z0-9._\-]*)") }
|
||||||
|
|
||||||
@ -54,9 +55,11 @@ const_regex!{
|
|||||||
|
|
||||||
pub PROXMOX_USER_ID_REGEX = concat!(r"^", USER_NAME_REGEX_STR!(), r"@", PROXMOX_SAFE_ID_REGEX_STR!(), r"$");
|
pub PROXMOX_USER_ID_REGEX = concat!(r"^", USER_NAME_REGEX_STR!(), r"@", PROXMOX_SAFE_ID_REGEX_STR!(), r"$");
|
||||||
|
|
||||||
|
pub PROXMOX_GROUP_ID_REGEX = concat!(r"^", GROUP_NAME_REGEX_STR!(), r"$");
|
||||||
|
|
||||||
pub CERT_FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
|
pub CERT_FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
|
||||||
|
|
||||||
pub ACL_PATH_REGEX = concat!(r"^(?:\/|", r"(?:\/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$");
|
pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
pub const SYSTEMD_DATETIME_FORMAT: ApiStringFormat =
|
||||||
@ -89,6 +92,9 @@ pub const DNS_NAME_OR_IP_FORMAT: ApiStringFormat =
|
|||||||
pub const PROXMOX_USER_ID_FORMAT: ApiStringFormat =
|
pub const PROXMOX_USER_ID_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&PROXMOX_USER_ID_REGEX);
|
ApiStringFormat::Pattern(&PROXMOX_USER_ID_REGEX);
|
||||||
|
|
||||||
|
pub const PROXMOX_GROUP_ID_FORMAT: ApiStringFormat =
|
||||||
|
ApiStringFormat::Pattern(&PROXMOX_GROUP_ID_REGEX);
|
||||||
|
|
||||||
pub const PASSWORD_FORMAT: ApiStringFormat =
|
pub const PASSWORD_FORMAT: ApiStringFormat =
|
||||||
ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
ApiStringFormat::Pattern(&PASSWORD_REGEX);
|
||||||
|
|
||||||
@ -218,6 +224,12 @@ pub const PROXMOX_USER_ID_SCHEMA: Schema = StringSchema::new("User ID")
|
|||||||
.max_length(64)
|
.max_length(64)
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
|
pub const PROXMOX_GROUP_ID_SCHEMA: Schema = StringSchema::new("Group ID")
|
||||||
|
.format(&PROXMOX_GROUP_ID_FORMAT)
|
||||||
|
.min_length(3)
|
||||||
|
.max_length(64)
|
||||||
|
.schema();
|
||||||
|
|
||||||
|
|
||||||
// Complex type definitions
|
// Complex type definitions
|
||||||
|
|
||||||
|
@ -220,7 +220,15 @@ fn list_acls(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Err
|
|||||||
fn acl_commands() -> CommandLineInterface {
|
fn acl_commands() -> CommandLineInterface {
|
||||||
|
|
||||||
let cmd_def = CliCommandMap::new()
|
let cmd_def = CliCommandMap::new()
|
||||||
.insert("list", CliCommand::new(&&API_METHOD_LIST_ACLS));
|
.insert("list", CliCommand::new(&&API_METHOD_LIST_ACLS))
|
||||||
|
.insert(
|
||||||
|
"update",
|
||||||
|
CliCommand::new(&api2::access::acl::API_METHOD_UPDATE_ACL)
|
||||||
|
.arg_param(&["path", "role"])
|
||||||
|
.completion_cb("userid", config::user::complete_user_name)
|
||||||
|
.completion_cb("path", config::datastore::complete_acl_path)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
cmd_def.into()
|
cmd_def.into()
|
||||||
}
|
}
|
||||||
|
@ -10,29 +10,31 @@ use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
|||||||
|
|
||||||
// define Privilege bitfield
|
// define Privilege bitfield
|
||||||
|
|
||||||
pub const PRIV_SYS_AUDIT: u64 = 1 << 0;
|
pub const PRIV_SYS_AUDIT: u64 = 1 << 0;
|
||||||
pub const PRIV_SYS_MODIFY: u64 = 1 << 1;
|
pub const PRIV_SYS_MODIFY: u64 = 1 << 1;
|
||||||
pub const PRIV_SYS_POWER_MANAGEMENT: u64 = 1 << 2;
|
pub const PRIV_SYS_POWER_MANAGEMENT: u64 = 1 << 2;
|
||||||
|
|
||||||
pub const PRIV_STORE_AUDIT: u64 = 1 << 3;
|
pub const PRIV_DATASTORE_AUDIT: u64 = 1 << 3;
|
||||||
pub const PRIV_STORE_ALLOCATE: u64 = 1 << 4;
|
pub const PRIV_DATASTORE_ALLOCATE: u64 = 1 << 4;
|
||||||
pub const PRIV_STORE_ALLOCATE_SPACE: u64 = 1 << 5;
|
pub const PRIV_DATASTORE_ALLOCATE_SPACE: u64 = 1 << 5;
|
||||||
|
|
||||||
pub const ROLE_ADMIN: u64 = std::u64::MAX;
|
pub const ROLE_ADMIN: u64 = std::u64::MAX;
|
||||||
pub const ROLE_NO_ACCESS: u64 = 0;
|
pub const ROLE_NO_ACCESS: u64 = 0;
|
||||||
|
|
||||||
pub const ROLE_AUDIT: u64 =
|
pub const ROLE_AUDIT: u64 =
|
||||||
PRIV_SYS_AUDIT |
|
PRIV_SYS_AUDIT |
|
||||||
PRIV_STORE_AUDIT;
|
PRIV_DATASTORE_AUDIT;
|
||||||
|
|
||||||
pub const ROLE_STORE_ADMIN: u64 =
|
pub const ROLE_DATASTORE_ADMIN: u64 =
|
||||||
PRIV_STORE_AUDIT |
|
PRIV_DATASTORE_AUDIT |
|
||||||
PRIV_STORE_ALLOCATE |
|
PRIV_DATASTORE_ALLOCATE |
|
||||||
PRIV_STORE_ALLOCATE_SPACE;
|
PRIV_DATASTORE_ALLOCATE_SPACE;
|
||||||
|
|
||||||
pub const ROLE_STORE_USER: u64 =
|
pub const ROLE_DATASTORE_USER: u64 =
|
||||||
PRIV_STORE_AUDIT |
|
PRIV_DATASTORE_AUDIT |
|
||||||
PRIV_STORE_ALLOCATE_SPACE;
|
PRIV_DATASTORE_ALLOCATE_SPACE;
|
||||||
|
|
||||||
|
pub const ROLE_DATASTORE_AUDIT: u64 = PRIV_DATASTORE_AUDIT;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ROLE_NAMES: HashMap<&'static str, u64> = {
|
static ref ROLE_NAMES: HashMap<&'static str, u64> = {
|
||||||
@ -42,8 +44,9 @@ lazy_static! {
|
|||||||
map.insert("Audit", ROLE_AUDIT);
|
map.insert("Audit", ROLE_AUDIT);
|
||||||
map.insert("NoAccess", ROLE_NO_ACCESS);
|
map.insert("NoAccess", ROLE_NO_ACCESS);
|
||||||
|
|
||||||
map.insert("Store.Admin", ROLE_STORE_ADMIN);
|
map.insert("Datastore.Admin", ROLE_DATASTORE_ADMIN);
|
||||||
map.insert("Store.User", ROLE_STORE_USER);
|
map.insert("Datastore.User", ROLE_DATASTORE_USER);
|
||||||
|
map.insert("Datastore.Audit", ROLE_DATASTORE_AUDIT);
|
||||||
|
|
||||||
map
|
map
|
||||||
};
|
};
|
||||||
@ -141,6 +144,22 @@ impl AclTreeNode {
|
|||||||
set
|
set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_group_role(&mut self, group: &str, role: &str) {
|
||||||
|
let roles = match self.groups.get_mut(group) {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
roles.remove(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_user_role(&mut self, userid: &str, role: &str) {
|
||||||
|
let roles = match self.users.get_mut(userid) {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
roles.remove(role);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_group_role(&mut self, group: String, role: String, propagate: bool) {
|
pub fn insert_group_role(&mut self, group: String, role: String, propagate: bool) {
|
||||||
self.groups
|
self.groups
|
||||||
.entry(group).or_insert_with(|| HashMap::new())
|
.entry(group).or_insert_with(|| HashMap::new())
|
||||||
@ -160,6 +179,17 @@ impl AclTree {
|
|||||||
Self { root: AclTreeNode::new() }
|
Self { root: AclTreeNode::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_node(&mut self, path: &[&str]) -> Option<&mut AclTreeNode> {
|
||||||
|
let mut node = &mut self.root;
|
||||||
|
for comp in path {
|
||||||
|
node = match node.children.get_mut(*comp) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(node)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_or_insert_node(&mut self, path: &[&str]) -> &mut AclTreeNode {
|
fn get_or_insert_node(&mut self, path: &[&str]) -> &mut AclTreeNode {
|
||||||
let mut node = &mut self.root;
|
let mut node = &mut self.root;
|
||||||
for comp in path {
|
for comp in path {
|
||||||
@ -169,6 +199,24 @@ impl AclTree {
|
|||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_group_role(&mut self, path: &str, group: &str, role: &str) {
|
||||||
|
let path = split_acl_path(path);
|
||||||
|
let node = match self.get_node(&path) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
node.delete_group_role(group, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_user_role(&mut self, path: &str, userid: &str, role: &str) {
|
||||||
|
let path = split_acl_path(path);
|
||||||
|
let node = match self.get_node(&path) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
node.delete_user_role(userid, role);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_group_role(&mut self, path: &str, group: &str, role: &str, propagate: bool) {
|
pub fn insert_group_role(&mut self, path: &str, group: &str, role: &str, propagate: bool) {
|
||||||
let path = split_acl_path(path);
|
let path = split_acl_path(path);
|
||||||
let node = self.get_or_insert_node(&path);
|
let node = self.get_or_insert_node(&path);
|
||||||
@ -382,7 +430,7 @@ pub fn config() -> Result<(AclTree, [u8; 32]), Error> {
|
|||||||
AclTree::load(&path)
|
AclTree::load(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_config(acl: &AclTree, filename: &Path) -> Result<(), Error> {
|
pub fn save_config(acl: &AclTree) -> Result<(), Error> {
|
||||||
let mut raw: Vec<u8> = Vec::new();
|
let mut raw: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
acl.write_config(&mut raw)?;
|
acl.write_config(&mut raw)?;
|
||||||
@ -396,12 +444,11 @@ pub fn store_config(acl: &AclTree, filename: &Path) -> Result<(), Error> {
|
|||||||
.owner(nix::unistd::ROOT)
|
.owner(nix::unistd::ROOT)
|
||||||
.group(backup_user.gid);
|
.group(backup_user.gid);
|
||||||
|
|
||||||
replace_file(filename, &raw, options)?;
|
replace_file(ACL_CFG_FILENAME, &raw, options)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
@ -430,15 +477,15 @@ mod test {
|
|||||||
let tree = AclTree::from_raw(r###"
|
let tree = AclTree::from_raw(r###"
|
||||||
acl:0:/store/store2:user1:Admin
|
acl:0:/store/store2:user1:Admin
|
||||||
acl:0:/store/store2:user2:Admin
|
acl:0:/store/store2:user2:Admin
|
||||||
acl:0:/store/store2:user1:Store.User
|
acl:0:/store/store2:user1:Datastore.User
|
||||||
acl:0:/store/store2:user2:Store.User
|
acl:0:/store/store2:user2:Datastore.User
|
||||||
"###)?;
|
"###)?;
|
||||||
|
|
||||||
let mut raw: Vec<u8> = Vec::new();
|
let mut raw: Vec<u8> = Vec::new();
|
||||||
tree.write_config(&mut raw)?;
|
tree.write_config(&mut raw)?;
|
||||||
let raw = std::str::from_utf8(&raw)?;
|
let raw = std::str::from_utf8(&raw)?;
|
||||||
|
|
||||||
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,Store.User\n");
|
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,Datastore.User\n");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -448,18 +495,18 @@ acl:0:/store/store2:user2:Store.User
|
|||||||
|
|
||||||
let tree = AclTree::from_raw(r###"
|
let tree = AclTree::from_raw(r###"
|
||||||
acl:1:/storage:user1@pbs:Admin
|
acl:1:/storage:user1@pbs:Admin
|
||||||
acl:1:/storage/store1:user1@pbs:Store.User
|
acl:1:/storage/store1:user1@pbs:Datastore.User
|
||||||
acl:1:/storage/store2:user2@pbs:Store.User
|
acl:1:/storage/store2:user2@pbs:Datastore.User
|
||||||
"###)?;
|
"###)?;
|
||||||
check_roles(&tree, "user1@pbs", "/", "");
|
check_roles(&tree, "user1@pbs", "/", "");
|
||||||
check_roles(&tree, "user1@pbs", "/storage", "Admin");
|
check_roles(&tree, "user1@pbs", "/storage", "Admin");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Store.User");
|
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.User");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
||||||
|
|
||||||
check_roles(&tree, "user2@pbs", "/", "");
|
check_roles(&tree, "user2@pbs", "/", "");
|
||||||
check_roles(&tree, "user2@pbs", "/storage", "");
|
check_roles(&tree, "user2@pbs", "/storage", "");
|
||||||
check_roles(&tree, "user2@pbs", "/storage/store1", "");
|
check_roles(&tree, "user2@pbs", "/storage/store1", "");
|
||||||
check_roles(&tree, "user2@pbs", "/storage/store2", "Store.User");
|
check_roles(&tree, "user2@pbs", "/storage/store2", "Datastore.User");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -470,22 +517,22 @@ acl:1:/storage/store2:user2@pbs:Store.User
|
|||||||
let tree = AclTree::from_raw(r###"
|
let tree = AclTree::from_raw(r###"
|
||||||
acl:1:/:user1@pbs:Admin
|
acl:1:/:user1@pbs:Admin
|
||||||
acl:1:/storage:user1@pbs:NoAccess
|
acl:1:/storage:user1@pbs:NoAccess
|
||||||
acl:1:/storage/store1:user1@pbs:Store.User
|
acl:1:/storage/store1:user1@pbs:Datastore.User
|
||||||
"###)?;
|
"###)?;
|
||||||
check_roles(&tree, "user1@pbs", "/", "Admin");
|
check_roles(&tree, "user1@pbs", "/", "Admin");
|
||||||
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Store.User");
|
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.User");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store2", "NoAccess");
|
check_roles(&tree, "user1@pbs", "/storage/store2", "NoAccess");
|
||||||
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
||||||
|
|
||||||
let tree = AclTree::from_raw(r###"
|
let tree = AclTree::from_raw(r###"
|
||||||
acl:1:/:user1@pbs:Admin
|
acl:1:/:user1@pbs:Admin
|
||||||
acl:0:/storage:user1@pbs:NoAccess
|
acl:0:/storage:user1@pbs:NoAccess
|
||||||
acl:1:/storage/store1:user1@pbs:Store.User
|
acl:1:/storage/store1:user1@pbs:Datastore.User
|
||||||
"###)?;
|
"###)?;
|
||||||
check_roles(&tree, "user1@pbs", "/", "Admin");
|
check_roles(&tree, "user1@pbs", "/", "Admin");
|
||||||
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Store.User");
|
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.User");
|
||||||
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
||||||
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
||||||
|
|
||||||
|
@ -101,3 +101,19 @@ pub fn complete_datastore_name(_arg: &str, _param: &HashMap<String, String>) ->
|
|||||||
Err(_) => return vec![],
|
Err(_) => return vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn complete_acl_path(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
|
||||||
|
let mut list = Vec::new();
|
||||||
|
|
||||||
|
list.push(String::from("/"));
|
||||||
|
list.push(String::from("/storage"));
|
||||||
|
list.push(String::from("/storage/"));
|
||||||
|
|
||||||
|
if let Ok((data, _digest)) = config() {
|
||||||
|
for id in data.sections.keys() {
|
||||||
|
list.push(format!("/storage/{}", id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user