all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH proxmox v4 5/5] access-control: allow reading all acls of the current authid
Date: Fri, 14 Nov 2025 15:43:13 +0100	[thread overview]
Message-ID: <20251114144318.317322-6-s.sterz@proxmox.com> (raw)
In-Reply-To: <20251114144318.317322-1-s.sterz@proxmox.com>

adds a parameter to the `API_METHOD_READ_ACL` endpoint to allow
listing all ACL entries of the currently authenticated Authid.
allowing a user to see their own ACLs does not really expose any
additional confidential information. however, being able to query this
information allows us, for example, to adapt ui components to a users
capabilities.

this uses `AclTreeNode::extract_roles` for the extraction.
`extract_roles` already respects the so far incomplete groups feature.
the part that is still missing here, is looking up what groups a user
belongs to. by using `extract_roles` so we should avoid accidentally
breaking the ui once groups are added.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
---
 proxmox-access-control/src/api/acl.rs | 101 ++++++++++++++++++--------
 1 file changed, 71 insertions(+), 30 deletions(-)

diff --git a/proxmox-access-control/src/api/acl.rs b/proxmox-access-control/src/api/acl.rs
index 4326215c..1700f6e8 100644
--- a/proxmox-access-control/src/api/acl.rs
+++ b/proxmox-access-control/src/api/acl.rs
@@ -23,6 +23,12 @@ use crate::CachedUserInfo;
                 optional: true,
                 default: false,
             },
+            "all-for-authid": {
+                description: "Whether to return all ACL entries for the exact current authid only.",
+                type: bool,
+                optional: true,
+                default: false,
+            }
         },
     },
     returns: {
@@ -34,13 +40,17 @@ use crate::CachedUserInfo;
     },
     access: {
         permission: &Permission::Anybody,
-        description: "Returns all ACLs if user has sufficient privileges on this endpoint, otherwise it is limited to the user's API tokens.",
+        description: "Returns all ACLs if a user has sufficient privileges on this endpoint. \
+            Otherwise it is limited to the user's API tokens. However, if `all-for-authid` is \
+            specified, all ACLs of the current Authid will be returned, whether the Authid has \
+            privileges to list other ACLs here or not.",
     },
 )]
 /// Get ACL entries, can be filter by path.
 pub fn read_acl(
     path: Option<String>,
     exact: bool,
+    all_for_authid: bool,
     rpcenv: &mut dyn RpcEnvironment,
 ) -> Result<Vec<AclListItem>, Error> {
     let auth_id = rpcenv
@@ -58,7 +68,11 @@ pub fn read_acl(
         )
         .is_err();

-    let filter = if filter_entries { Some(auth_id) } else { None };
+    let filter = if filter_entries || all_for_authid {
+        Some(auth_id)
+    } else {
+        None
+    };

     let (mut tree, digest) = crate::acl::config()?;

@@ -74,7 +88,13 @@ pub fn read_acl(

     rpcenv["digest"] = hex::encode(digest).into();

-    Ok(extract_acl_node_data(node, path.as_deref(), exact, &filter))
+    Ok(extract_acl_node_data(
+        node,
+        path.as_deref(),
+        all_for_authid,
+        exact,
+        &filter,
+    ))
 }

 #[api(
@@ -241,6 +261,7 @@ pub fn update_acl(
 fn extract_acl_node_data(
     node: &AclTreeNode,
     path: Option<&str>,
+    all_for_authid: bool,
     exact: bool,
     auth_id_filter: &Option<Authid>,
 ) -> Vec<AclListItem> {
@@ -257,37 +278,57 @@ fn extract_acl_node_data(
     while let Some((path, node)) = nodes.pop() {
         let path_str = if path.is_empty() { "/" } else { &path };

-        for (user, roles) in &node.users {
-            if let Some(auth_id_filter) = auth_id_filter {
-                if !user.is_token() || user.user() != auth_id_filter.user() {
-                    continue;
+        if all_for_authid {
+            if let Some(auth_id) = auth_id_filter {
+                // this will extract all roles for `auth_id_filer` from the node. group acls will
+                // be handled according to the acl trees implementation. we mask them here as user
+                // ACLs to avoid disclosing more information than necessary.
+                //
+                // by setting `leaf` to true we always get all roles for this `auth_id` on the
+                // current node.
+                for (role, propagate) in node.extract_roles(auth_id, true) {
+                    to_return.push(AclListItem {
+                        path: path_str.to_owned(),
+                        propagate,
+                        ugid_type: AclUgidType::User,
+                        ugid: auth_id.to_string(),
+                        roleid: role.to_string(),
+                    })
+                }
+            }
+        } else {
+            for (user, roles) in &node.users {
+                if let Some(auth_id_filter) = auth_id_filter {
+                    if !user.is_token() || user.user() != auth_id_filter.user() {
+                        continue;
+                    }
+                }
+
+                for (role, propagate) in roles {
+                    to_return.push(AclListItem {
+                        path: path_str.to_owned(),
+                        propagate: *propagate,
+                        ugid_type: AclUgidType::User,
+                        ugid: user.to_string(),
+                        roleid: role.to_string(),
+                    });
                 }
             }

-            for (role, propagate) in roles {
-                to_return.push(AclListItem {
-                    path: path_str.to_owned(),
-                    propagate: *propagate,
-                    ugid_type: AclUgidType::User,
-                    ugid: user.to_string(),
-                    roleid: role.to_string(),
-                });
-            }
-        }
+            for (group, roles) in &node.groups {
+                if auth_id_filter.is_some() {
+                    continue;
+                }

-        for (group, roles) in &node.groups {
-            if auth_id_filter.is_some() {
-                continue;
-            }
-
-            for (role, propagate) in roles {
-                to_return.push(AclListItem {
-                    path: path_str.to_owned(),
-                    propagate: *propagate,
-                    ugid_type: AclUgidType::Group,
-                    ugid: group.to_string(),
-                    roleid: role.to_string(),
-                });
+                for (role, propagate) in roles {
+                    to_return.push(AclListItem {
+                        path: path_str.to_owned(),
+                        propagate: *propagate,
+                        ugid_type: AclUgidType::Group,
+                        ugid: group.to_string(),
+                        roleid: role.to_string(),
+                    });
+                }
             }
         }

--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


  parent reply	other threads:[~2025-11-14 14:43 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-14 14:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp v4 00/10] add support for checking acl permissions in (yew) front-ends Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH proxmox v4 1/5] access-control: add acl feature to only expose types and the AclTree Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH proxmox v4 2/5] access-control: use format strings where possible Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH proxmox v4 3/5] access-control: move functions querying privileges to the AclTree Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH proxmox v4 4/5] access-control: derive Debug and PartialEq on AclTree and AclTreeNode Shannon Sterz
2025-11-14 14:43 ` Shannon Sterz [this message]
2025-11-14 14:43 ` [pdm-devel] [PATCH yew-comp v4 1/2] acl_context: add AclContext and AclContextProvider Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH yew-comp v4 2/2] http_helpers: reload LocalAclTree when logging in or refreshing a ticket Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH datacenter-manager v4 1/3] move AccessControlConfig to pdm-api-types Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH datacenter-manager v4 2/3] ui: add an AclContext via the AclContextProvider to the main app ui Shannon Sterz
2025-11-14 14:43 ` [pdm-devel] [PATCH datacenter-manager v4 3/3] ui: main menu: use the AclContext to hide the Notes if appropriate Shannon Sterz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251114144318.317322-6-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal