[pdm-devel] [PATCH datacenter-manager v2 1/2] server/api-types: move AccessControlConfig to shared api types
Shannon Sterz
s.sterz at proxmox.com
Wed Oct 22 15:11:23 CEST 2025
this doesn't really contain any information that is secret. moving it
to the shared api types allows re-using it in the ui to check what
privileges a user needs to access certain features.
Signed-off-by: Shannon Sterz <s.sterz at proxmox.com>
---
lib/pdm-api-types/Cargo.toml | 1 +
lib/pdm-api-types/src/acl.rs | 158 ++++++++++++++++++++++++++++++++++
server/src/acl.rs | 162 +----------------------------------
3 files changed, 161 insertions(+), 160 deletions(-)
diff --git a/lib/pdm-api-types/Cargo.toml b/lib/pdm-api-types/Cargo.toml
index e66558b..4b0edde 100644
--- a/lib/pdm-api-types/Cargo.toml
+++ b/lib/pdm-api-types/Cargo.toml
@@ -14,6 +14,7 @@ serde.workspace = true
serde_plain.workspace = true
proxmox-acme-api.workspace = true
+proxmox-access-control.workspace = true
proxmox-auth-api = { workspace = true, features = ["api-types"] }
proxmox-lang.workspace = true
proxmox-config-digest.workspace = true
diff --git a/lib/pdm-api-types/src/acl.rs b/lib/pdm-api-types/src/acl.rs
index 9e69c2f..baba3da 100644
--- a/lib/pdm-api-types/src/acl.rs
+++ b/lib/pdm-api-types/src/acl.rs
@@ -1,6 +1,12 @@
+use std::collections::HashMap;
use std::str::FromStr;
+use std::sync::LazyLock;
+use anyhow::{format_err, Context, Error};
use const_format::concatcp;
+use proxmox_access_control::types::User;
+use proxmox_auth_api::types::Authid;
+use proxmox_section_config::SectionConfigData;
use serde::de::{value, IntoDeserializer};
use serde::{Deserialize, Serialize};
@@ -179,3 +185,155 @@ pub struct AclListItem {
pub propagate: bool,
pub roleid: String,
}
+
+pub struct AccessControlConfig;
+
+impl proxmox_access_control::init::AccessControlConfig for AccessControlConfig {
+ fn privileges(&self) -> &HashMap<&str, u64> {
+ static PRIVS: LazyLock<HashMap<&str, u64>> =
+ LazyLock::new(|| PRIVILEGES.iter().copied().collect());
+
+ &PRIVS
+ }
+
+ #[rustfmt::skip]
+ fn roles(&self) -> &HashMap<&str, (u64, &str)> {
+ static ROLES: LazyLock<HashMap<&str, (u64, &str)>> = LazyLock::new(|| {
+ [
+ ("Administrator", (ROLE_ADMINISTRATOR, "Administrators can inspect and modify the system.")),
+ ("Auditor", (ROLE_AUDITOR, "An Auditor can inspect many aspects of the system, but not change them.")),
+ //("SystemAdministrator", pdm_api_types::ROLE_SYS_ADMINISTRATOR),
+ //("SystemAuditor", pdm_api_types::ROLE_SYS_AUDITOR),
+ //("ResourceAdministrator", pdm_api_types::ROLE_RESOURCE_ADMINISTRATOR),
+ //("ResourceAuditor", pdm_api_types::ROLE_RESOURCE_AUDITOR),
+ //("AccessAuditor", pdm_api_types::ROLE_ACCESS_AUDITOR),
+ ]
+ .into_iter()
+ .collect()
+ });
+
+ &ROLES
+ }
+
+ fn is_superuser(&self, auth_id: &Authid) -> bool {
+ !auth_id.is_token() && auth_id.user() == "root at pam"
+ }
+
+ fn role_admin(&self) -> Option<&str> {
+ Some("Administrator")
+ }
+
+ fn init_user_config(&self, config: &mut SectionConfigData) -> Result<(), Error> {
+ if !config.sections.contains_key("root at pam") {
+ config
+ .set_data(
+ "root at pam",
+ "user",
+ User {
+ userid: "root at pam".parse().expect("invalid user id"),
+ comment: Some("Superuser".to_string()),
+ enable: None,
+ expire: None,
+ firstname: None,
+ lastname: None,
+ email: None,
+ },
+ )
+ .context("failed to insert default user into user config")?
+ }
+
+ Ok(())
+ }
+
+ fn acl_audit_privileges(&self) -> u64 {
+ PRIV_ACCESS_AUDIT
+ }
+
+ fn acl_modify_privileges(&self) -> u64 {
+ PRIV_ACCESS_MODIFY
+ }
+
+ fn check_acl_path(&self, path: &str) -> Result<(), Error> {
+ let components = proxmox_access_control::acl::split_acl_path(path);
+
+ let components_len = components.len();
+
+ if components_len == 0 {
+ return Ok(());
+ }
+ match components[0] {
+ "access" => {
+ if components_len == 1 {
+ return Ok(());
+ }
+ match components[1] {
+ "acl" | "users" | "realm" => {
+ if components_len == 2 {
+ return Ok(());
+ }
+ }
+ _ => {}
+ }
+ }
+ "resource" => {
+ // `/resource` and `/resource/{remote}`
+ if components_len <= 2 {
+ return Ok(());
+ }
+ // `/resource/{remote-id}/{resource-type=guest,storage}/{resource-id}`
+ match components[2] {
+ "guest" | "storage" => {
+ // /resource/{remote-id}/{resource-type}
+ // /resource/{remote-id}/{resource-type}/{resource-id}
+ if components_len <= 4 {
+ return Ok(());
+ }
+ }
+ _ => {}
+ }
+ }
+ "system" => {
+ if components_len == 1 {
+ return Ok(());
+ }
+ match components[1] {
+ "certificates" | "disks" | "log" | "notifications" | "status" | "tasks"
+ | "time" => {
+ if components_len == 2 {
+ return Ok(());
+ }
+ }
+ "services" => {
+ // /system/services/{service}
+ if components_len <= 3 {
+ return Ok(());
+ }
+ }
+ "network" => {
+ if components_len == 2 {
+ return Ok(());
+ }
+ match components[2] {
+ "dns" => {
+ if components_len == 3 {
+ return Ok(());
+ }
+ }
+ "interfaces" => {
+ // /system/network/interfaces/{iface}
+ if components_len <= 4 {
+ return Ok(());
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+
+ Err(format_err!("invalid acl path '{}'.", path))
+ }
+}
diff --git a/server/src/acl.rs b/server/src/acl.rs
index 52a1f97..f421814 100644
--- a/server/src/acl.rs
+++ b/server/src/acl.rs
@@ -1,164 +1,6 @@
-use std::collections::HashMap;
-use std::sync::OnceLock;
-
-use anyhow::{format_err, Context as _, Error};
-
-use proxmox_access_control::types::User;
-use proxmox_auth_api::types::Authid;
-use proxmox_section_config::SectionConfigData;
-
-struct AccessControlConfig;
-
-static PRIVILEGES: OnceLock<HashMap<&str, u64>> = OnceLock::new();
-static ROLES: OnceLock<HashMap<&str, (u64, &str)>> = OnceLock::new();
-
-impl proxmox_access_control::init::AccessControlConfig for AccessControlConfig {
- fn privileges(&self) -> &HashMap<&str, u64> {
- PRIVILEGES.get_or_init(|| pdm_api_types::PRIVILEGES.iter().copied().collect())
- }
-
- #[rustfmt::skip]
- fn roles(&self) -> &HashMap<&str, (u64, &str)> {
- ROLES.get_or_init(|| {
- [
- ("Administrator", (pdm_api_types::ROLE_ADMINISTRATOR, "Administrators can inspect and modify the system.")),
- ("Auditor", (pdm_api_types::ROLE_AUDITOR, "An Auditor can inspect many aspects of the system, but not change them.")),
- //("SystemAdministrator", pdm_api_types::ROLE_SYS_ADMINISTRATOR),
- //("SystemAuditor", pdm_api_types::ROLE_SYS_AUDITOR),
- //("ResourceAdministrator", pdm_api_types::ROLE_RESOURCE_ADMINISTRATOR),
- //("ResourceAuditor", pdm_api_types::ROLE_RESOURCE_AUDITOR),
- //("AccessAuditor", pdm_api_types::ROLE_ACCESS_AUDITOR),
- ]
- .into_iter()
- .collect()
- })
- }
-
- fn is_superuser(&self, auth_id: &Authid) -> bool {
- !auth_id.is_token() && auth_id.user() == "root at pam"
- }
-
- fn role_admin(&self) -> Option<&str> {
- Some("Administrator")
- }
-
- fn init_user_config(&self, config: &mut SectionConfigData) -> Result<(), Error> {
- if !config.sections.contains_key("root at pam") {
- config
- .set_data(
- "root at pam",
- "user",
- User {
- userid: "root at pam".parse().expect("invalid user id"),
- comment: Some("Superuser".to_string()),
- enable: None,
- expire: None,
- firstname: None,
- lastname: None,
- email: None,
- },
- )
- .context("failed to insert default user into user config")?
- }
-
- Ok(())
- }
-
- fn acl_audit_privileges(&self) -> u64 {
- pdm_api_types::PRIV_ACCESS_AUDIT
- }
-
- fn acl_modify_privileges(&self) -> u64 {
- pdm_api_types::PRIV_ACCESS_MODIFY
- }
-
- fn check_acl_path(&self, path: &str) -> Result<(), Error> {
- let components = proxmox_access_control::acl::split_acl_path(path);
-
- let components_len = components.len();
-
- if components_len == 0 {
- return Ok(());
- }
- match components[0] {
- "access" => {
- if components_len == 1 {
- return Ok(());
- }
- match components[1] {
- "acl" | "users" | "realm" => {
- if components_len == 2 {
- return Ok(());
- }
- }
- _ => {}
- }
- }
- "resource" => {
- // `/resource` and `/resource/{remote}`
- if components_len <= 2 {
- return Ok(());
- }
- // `/resource/{remote-id}/{resource-type=guest,storage}/{resource-id}`
- match components[2] {
- "guest" | "storage" => {
- // /resource/{remote-id}/{resource-type}
- // /resource/{remote-id}/{resource-type}/{resource-id}
- if components_len <= 4 {
- return Ok(());
- }
- }
- _ => {}
- }
- }
- "system" => {
- if components_len == 1 {
- return Ok(());
- }
- match components[1] {
- "certificates" | "disks" | "log" | "notifications" | "status" | "tasks"
- | "time" => {
- if components_len == 2 {
- return Ok(());
- }
- }
- "services" => {
- // /system/services/{service}
- if components_len <= 3 {
- return Ok(());
- }
- }
- "network" => {
- if components_len == 2 {
- return Ok(());
- }
- match components[2] {
- "dns" => {
- if components_len == 3 {
- return Ok(());
- }
- }
- "interfaces" => {
- // /system/network/interfaces/{iface}
- if components_len <= 4 {
- return Ok(());
- }
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
- _ => {}
- }
-
- Err(format_err!("invalid acl path '{}'.", path))
- }
-}
-
pub(crate) fn init() {
- static ACCESS_CONTROL_CONFIG: AccessControlConfig = AccessControlConfig;
+ static ACCESS_CONTROL_CONFIG: pdm_api_types::AccessControlConfig =
+ pdm_api_types::AccessControlConfig;
proxmox_access_control::init::init(&ACCESS_CONTROL_CONFIG, pdm_buildcfg::configdir!("/access"))
.expect("failed to setup access control config");
--
2.47.3
More information about the pdm-devel
mailing list