[pve-devel] [PATCH v3 access-control 14/20] API: add 'permissions' API endpoint

Fabian Grünbichler f.gruenbichler at proxmox.com
Tue Jan 21 13:54:12 CET 2020


and related helper, to dump permissions + propagate info for
- a specific, given path
- generic top-level + user.cfg-referenced paths, including pools

Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---

Notes:
    new in v2

 PVE/API2/AccessControl.pm | 56 +++++++++++++++++++++++++++++++++++++++
 PVE/RPCEnvironment.pm     | 41 ++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/PVE/API2/AccessControl.pm b/PVE/API2/AccessControl.pm
index c6499be..5b63d2b 100644
--- a/PVE/API2/AccessControl.pm
+++ b/PVE/API2/AccessControl.pm
@@ -661,4 +661,60 @@ __PACKAGE__->register_method({
 	}
     }});
 
+__PACKAGE__->register_method({
+    name => 'permissions',
+    path => 'permissions',
+    method => 'GET',
+    description => 'Retrieve effective permissions of given user/token.',
+    permissions => {
+	description => "Each user/token is allowed to dump their own permissions. A user can dump the permissions of another user if they have 'Sys.Audit' permission on /access.",
+	user => 'all',
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    userid => {
+		type => 'string',
+		description => "User ID or full API token ID",
+		pattern => $PVE::AccessControl::userid_or_token_regex,
+		optional => 1,
+	    },
+	    path => get_standard_option('acl-path', {
+		description => "Only dump this specific path, not the whole tree.",
+		optional => 1,
+	    }),
+	},
+    },
+    returns => {
+	type => 'object',
+	description => 'Map of "path" => (Map of "privilege" => "propagate boolean").',
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $rpcenv = PVE::RPCEnvironment::get();
+
+	my $userid = $param->{userid};
+	if (defined($userid)) {
+	    $rpcenv->check($rpcenv->get_user(), '/access', ['Sys.Audit']);
+	} else {
+	    $userid = $rpcenv->get_user();
+	}
+
+	my $res;
+
+	if (my $path = $param->{path}) {
+	    my $perms = $rpcenv->permissions($userid, $path);
+	    if ($perms) {
+		$res = { $path => $perms };
+	    } else {
+		$res = {};
+	    }
+	} else {
+	    $res = $rpcenv->get_effective_permissions($userid);
+	}
+
+	return $res;
+    }});
+
 1;
diff --git a/PVE/RPCEnvironment.pm b/PVE/RPCEnvironment.pm
index 8384376..e66107b 100644
--- a/PVE/RPCEnvironment.pm
+++ b/PVE/RPCEnvironment.pm
@@ -127,6 +127,47 @@ sub permissions {
     return &$compile_acl_path($self, $user, $path);
 }
 
+sub get_effective_permissions {
+    my ($self, $user) = @_;
+
+    # default / top level paths
+    my $paths = {
+	'/' => 1,
+	'/access' => 1,
+	'/access/groups' => 1,
+	'/nodes' => 1,
+	'/pools' => 1,
+	'/storage' => 1,
+	'/vms' => 1,
+    };
+
+    my $cfg = $self->{user_cfg};
+
+    # paths explicitly listed in ACLs
+    foreach my $acl_path (keys %{$cfg->{acl}}) {
+	$paths->{$acl_path} = 1;
+    }
+
+    # paths referenced by pool definitions
+    foreach my $pool (keys %{$cfg->{pools}}) {
+	my $d = $cfg->{pools}->{$pool};
+	foreach my $vmid (keys %{$d->{vms}}) {
+	    $paths->{"/vms/$vmid"} = 1;
+	}
+	foreach my $storeid (keys %{$d->{storage}}) {
+	    $paths->{"/storage/$storeid"} = 1;
+	}
+    }
+
+    my $perms = {};
+    foreach my $path (keys %$paths) {
+	my $path_perms = $self->permissions($user, $path);
+	# filter paths where user has NO permissions
+	$perms->{$path} = $path_perms if %$path_perms;
+    }
+    return $perms;
+}
+
 sub check {
     my ($self, $user, $path, $privs, $noerr) = @_;
 
-- 
2.20.1





More information about the pve-devel mailing list