use proxmox 0.1.25, use new EnumEntry feature
This commit is contained in:
parent
acb428cdec
commit
bc0d03885c
@ -34,7 +34,7 @@ pam = "0.7"
|
||||
pam-sys = "0.5"
|
||||
percent-encoding = "2.1"
|
||||
pin-utils = "0.1.0-alpha"
|
||||
proxmox = { version = "0.1.24", features = [ "sortable-macro", "api-macro" ] }
|
||||
proxmox = { version = "0.1.25", features = [ "sortable-macro", "api-macro" ] }
|
||||
#proxmox = { git = "ssh://gitolite3@proxdev.maurer-it.com/rust/proxmox", version = "0.1.2", features = [ "sortable-macro", "api-macro" ] }
|
||||
#proxmox = { path = "../proxmox/proxmox", features = [ "sortable-macro", "api-macro" ] }
|
||||
regex = "1.2"
|
||||
|
@ -5,7 +5,7 @@ use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||
|
||||
use crate::api2::types::*;
|
||||
use crate::config::acl;
|
||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||
use crate::config::acl::{Role, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||
|
||||
#[api(
|
||||
properties: {
|
||||
@ -23,7 +23,7 @@ use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||
description: "User or Group ID.",
|
||||
},
|
||||
roleid: {
|
||||
schema: ACL_ROLE_SCHEMA,
|
||||
type: Role,
|
||||
}
|
||||
}
|
||||
)]
|
||||
@ -118,7 +118,7 @@ pub fn read_acl(
|
||||
schema: ACL_PATH_SCHEMA,
|
||||
},
|
||||
role: {
|
||||
schema: ACL_ROLE_SCHEMA,
|
||||
type: Role,
|
||||
},
|
||||
propagate: {
|
||||
optional: true,
|
||||
|
@ -6,7 +6,7 @@ use proxmox::api::{api, Permission};
|
||||
use proxmox::api::router::Router;
|
||||
|
||||
use crate::api2::types::*;
|
||||
use crate::config::acl::ROLE_NAMES;
|
||||
use crate::config::acl::{Role, ROLE_NAMES};
|
||||
|
||||
#[api(
|
||||
returns: {
|
||||
@ -17,7 +17,7 @@ use crate::config::acl::ROLE_NAMES;
|
||||
description: "User name with description.",
|
||||
properties: {
|
||||
role: {
|
||||
schema: ACL_ROLE_SCHEMA,
|
||||
type: Role,
|
||||
},
|
||||
comment: {
|
||||
schema: SINGLE_LINE_COMMENT_SCHEMA,
|
||||
|
@ -31,15 +31,9 @@ pub const API_METHOD_UPGRADE_BACKUP: ApiMethod = ApiMethod::new(
|
||||
concat!("Upgraded to backup protocol ('", PROXMOX_BACKUP_READER_PROTOCOL_ID_V1!(), "')."),
|
||||
&sorted!([
|
||||
("store", false, &DATASTORE_SCHEMA),
|
||||
("backup-type", false, &StringSchema::new("Backup type.")
|
||||
.format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
|
||||
.schema()
|
||||
),
|
||||
("backup-id", false, &StringSchema::new("Backup ID.").schema()),
|
||||
("backup-time", false, &IntegerSchema::new("Backup time (Unix epoch.)")
|
||||
.minimum(1_547_797_308)
|
||||
.schema()
|
||||
),
|
||||
("backup-type", false, &BACKUP_TYPE_SCHEMA),
|
||||
("backup-id", false, &BACKUP_ID_SCHEMA),
|
||||
("backup-time", false, &BACKUP_TIME_SCHEMA),
|
||||
("debug", true, &BooleanSchema::new("Enable verbose debug logging.").schema()),
|
||||
]),
|
||||
)
|
||||
|
@ -248,24 +248,9 @@ pub const ACL_PROPAGATE_SCHEMA: Schema = BooleanSchema::new(
|
||||
|
||||
pub const ACL_UGID_TYPE_SCHEMA: Schema = StringSchema::new(
|
||||
"Type of 'ugid' property.")
|
||||
.format(&ApiStringFormat::Enum(&["user", "group"]))
|
||||
.schema();
|
||||
|
||||
pub const ACL_ROLE_SCHEMA: Schema = StringSchema::new(
|
||||
"Role.")
|
||||
.format(&ApiStringFormat::Enum(&[
|
||||
"Admin",
|
||||
"Audit",
|
||||
"Datastore.Admin",
|
||||
"Datastore.Reader",
|
||||
"Datastore.Audit",
|
||||
"Datastore.Backup",
|
||||
"Datastore.PowerUser",
|
||||
"Remote.Admin",
|
||||
"Remote.Audit",
|
||||
"Remote.SyncOperator",
|
||||
"NoAccess",
|
||||
]))
|
||||
EnumEntry::new("user", "User"),
|
||||
EnumEntry::new("group", "Group")]))
|
||||
.schema();
|
||||
|
||||
pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema =
|
||||
@ -275,7 +260,10 @@ pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema =
|
||||
|
||||
pub const BACKUP_TYPE_SCHEMA: Schema =
|
||||
StringSchema::new("Backup type.")
|
||||
.format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
|
||||
.format(&ApiStringFormat::Enum(&[
|
||||
EnumEntry::new("vm", "Virtual Machine Backup"),
|
||||
EnumEntry::new("ct", "Container Backup"),
|
||||
EnumEntry::new("host", "Host Backup")]))
|
||||
.schema();
|
||||
|
||||
pub const BACKUP_ID_SCHEMA: Schema =
|
||||
|
@ -1852,7 +1852,9 @@ fn key_mgmt_cli() -> CliCommandMap {
|
||||
|
||||
const KDF_SCHEMA: Schema =
|
||||
StringSchema::new("Key derivation function. Choose 'none' to store the key unecrypted.")
|
||||
.format(&ApiStringFormat::Enum(&["scrypt", "none"]))
|
||||
.format(&ApiStringFormat::Enum(&[
|
||||
EnumEntry::new("scrypt", "SCrypt"),
|
||||
EnumEntry::new("none", "Do not encrypt the key")]))
|
||||
.default("scrypt")
|
||||
.schema();
|
||||
|
||||
|
@ -2,12 +2,17 @@ use std::io::Write;
|
||||
use std::collections::{HashMap, HashSet, BTreeMap, BTreeSet};
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use ::serde::{Deserialize, Serialize};
|
||||
use serde::de::{value, IntoDeserializer};
|
||||
|
||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
||||
use proxmox::api::{api, schema::*};
|
||||
|
||||
// define Privilege bitfield
|
||||
|
||||
@ -83,56 +88,56 @@ PRIV_REMOTE_PRUNE;
|
||||
|
||||
pub const ROLE_NAME_NO_ACCESS: &str ="NoAccess";
|
||||
|
||||
#[api()]
|
||||
#[repr(u64)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// Role
|
||||
pub enum Role {
|
||||
/// Administrator
|
||||
Admin = ROLE_ADMIN,
|
||||
/// Auditor
|
||||
Audit = ROLE_AUDIT,
|
||||
/// Disable Access
|
||||
NoAccess = ROLE_NO_ACCESS,
|
||||
/// Datastore Administrator
|
||||
DatastoreAdmin = ROLE_DATASTORE_ADMIN,
|
||||
/// Datastore Reader (inspect datastore content and do restores)
|
||||
DatastoreReader = ROLE_DATASTORE_READER,
|
||||
/// Datastore Backup (backup and restore owned backups)
|
||||
DatastoreBackup = ROLE_DATASTORE_BACKUP,
|
||||
/// Datastore PowerUser (backup, restore and prune owned backup)
|
||||
DatastorePowerUser = ROLE_DATASTORE_POWERUSER,
|
||||
/// Datastore Auditor
|
||||
DatastoreAudit = ROLE_DATASTORE_AUDIT,
|
||||
/// Remote Auditor
|
||||
RemoteAudit = ROLE_REMOTE_AUDIT,
|
||||
/// Remote Administrator
|
||||
RemoteAdmin = ROLE_REMOTE_ADMIN,
|
||||
/// Syncronisation Opertator
|
||||
RemoteSyncOperator = ROLE_REMOTE_SYNC_OPERATOR,
|
||||
}
|
||||
|
||||
impl FromStr for Role {
|
||||
type Err = value::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::deserialize(s.into_deserializer())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref ROLE_NAMES: HashMap<&'static str, (u64, &'static str)> = {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
map.insert("Admin", (
|
||||
ROLE_ADMIN,
|
||||
"Administrator",
|
||||
));
|
||||
map.insert("Audit", (
|
||||
ROLE_AUDIT,
|
||||
"Auditor",
|
||||
));
|
||||
map.insert(ROLE_NAME_NO_ACCESS, (
|
||||
ROLE_NO_ACCESS,
|
||||
"Disable access",
|
||||
));
|
||||
let list = match Role::API_SCHEMA {
|
||||
Schema::String(StringSchema { format: Some(ApiStringFormat::Enum(list)), .. }) => list,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
map.insert("Datastore.Admin", (
|
||||
ROLE_DATASTORE_ADMIN,
|
||||
"Datastore Administrator",
|
||||
));
|
||||
map.insert("Datastore.Reader", (
|
||||
ROLE_DATASTORE_READER,
|
||||
"Datastore Reader (inspect datastore content and do restores)",
|
||||
));
|
||||
map.insert("Datastore.Backup", (
|
||||
ROLE_DATASTORE_BACKUP,
|
||||
"Datastore Backup (backup and restore owned backups)",
|
||||
));
|
||||
map.insert("Datastore.PowerUser", (
|
||||
ROLE_DATASTORE_POWERUSER,
|
||||
"Datastore PowerUser (backup, restore and prune owned backup)",
|
||||
));
|
||||
map.insert("Datastore.Audit", (
|
||||
ROLE_DATASTORE_AUDIT,
|
||||
"Datastore Auditor",
|
||||
));
|
||||
|
||||
map.insert("Remote.Audit", (
|
||||
ROLE_REMOTE_AUDIT,
|
||||
"Remote Auditor",
|
||||
));
|
||||
map.insert("Remote.Admin", (
|
||||
ROLE_REMOTE_ADMIN,
|
||||
"Remote Administrator",
|
||||
));
|
||||
map.insert("Remote.SyncOperator", (
|
||||
ROLE_REMOTE_SYNC_OPERATOR,
|
||||
"Syncronisation Opertator",
|
||||
));
|
||||
for entry in list.iter() {
|
||||
let privs: u64 = Role::from_str(entry.value).unwrap() as u64;
|
||||
map.insert(entry.value, (privs, entry.description));
|
||||
}
|
||||
|
||||
map
|
||||
};
|
||||
@ -615,15 +620,15 @@ mod test {
|
||||
let tree = AclTree::from_raw(r###"
|
||||
acl:0:/store/store2:user1:Admin
|
||||
acl:0:/store/store2:user2:Admin
|
||||
acl:0:/store/store2:user1:Datastore.Backup
|
||||
acl:0:/store/store2:user2:Datastore.Backup
|
||||
acl:0:/store/store2:user1:DatastoreBackup
|
||||
acl:0:/store/store2:user2:DatastoreBackup
|
||||
"###)?;
|
||||
|
||||
let mut raw: Vec<u8> = Vec::new();
|
||||
tree.write_config(&mut raw)?;
|
||||
let raw = std::str::from_utf8(&raw)?;
|
||||
|
||||
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,Datastore.Backup\n");
|
||||
assert_eq!(raw, "acl:0:/store/store2:user1,user2:Admin,DatastoreBackup\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -633,18 +638,18 @@ acl:0:/store/store2:user2:Datastore.Backup
|
||||
|
||||
let tree = AclTree::from_raw(r###"
|
||||
acl:1:/storage:user1@pbs:Admin
|
||||
acl:1:/storage/store1:user1@pbs:Datastore.Backup
|
||||
acl:1:/storage/store2:user2@pbs:Datastore.Backup
|
||||
acl:1:/storage/store1:user1@pbs:DatastoreBackup
|
||||
acl:1:/storage/store2:user2@pbs:DatastoreBackup
|
||||
"###)?;
|
||||
check_roles(&tree, "user1@pbs", "/", "");
|
||||
check_roles(&tree, "user1@pbs", "/storage", "Admin");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
||||
|
||||
check_roles(&tree, "user2@pbs", "/", "");
|
||||
check_roles(&tree, "user2@pbs", "/storage", "");
|
||||
check_roles(&tree, "user2@pbs", "/storage/store1", "");
|
||||
check_roles(&tree, "user2@pbs", "/storage/store2", "Datastore.Backup");
|
||||
check_roles(&tree, "user2@pbs", "/storage/store2", "DatastoreBackup");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -655,22 +660,22 @@ acl:1:/storage/store2:user2@pbs:Datastore.Backup
|
||||
let tree = AclTree::from_raw(r###"
|
||||
acl:1:/:user1@pbs:Admin
|
||||
acl:1:/storage:user1@pbs:NoAccess
|
||||
acl:1:/storage/store1:user1@pbs:Datastore.Backup
|
||||
acl:1:/storage/store1:user1@pbs:DatastoreBackup
|
||||
"###)?;
|
||||
check_roles(&tree, "user1@pbs", "/", "Admin");
|
||||
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store2", "NoAccess");
|
||||
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
||||
|
||||
let tree = AclTree::from_raw(r###"
|
||||
acl:1:/:user1@pbs:Admin
|
||||
acl:0:/storage:user1@pbs:NoAccess
|
||||
acl:1:/storage/store1:user1@pbs:Datastore.Backup
|
||||
acl:1:/storage/store1:user1@pbs:DatastoreBackup
|
||||
"###)?;
|
||||
check_roles(&tree, "user1@pbs", "/", "Admin");
|
||||
check_roles(&tree, "user1@pbs", "/storage", "NoAccess");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "Datastore.Backup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store1", "DatastoreBackup");
|
||||
check_roles(&tree, "user1@pbs", "/storage/store2", "Admin");
|
||||
check_roles(&tree, "user1@pbs", "/system", "Admin");
|
||||
|
||||
|
@ -142,27 +142,3 @@ fn verify_root_api() -> Result<(), Error> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_acl_role_schema() -> Result<(), Error> {
|
||||
|
||||
let list = match api2::types::ACL_ROLE_SCHEMA {
|
||||
Schema::String(StringSchema { format: Some(ApiStringFormat::Enum(list)), .. }) => list,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let map = &proxmox_backup::config::acl::ROLE_NAMES;
|
||||
for item in *list {
|
||||
if !map.contains_key(item) {
|
||||
bail!("found role '{}' without description/mapping", item);
|
||||
}
|
||||
}
|
||||
|
||||
for role in map.keys() {
|
||||
if !list.contains(role) {
|
||||
bail!("role '{}' missing in ACL_ROLE_SCHEMA enum", role);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user