From: Fabian Grünbichler Date: Tue, 21 Jan 2020 12:54:12 +0000 (+0100) Subject: API: add 'permissions' API endpoint X-Git-Url: https://git.proxmox.com/?p=pve-access-control.git;a=commitdiff_plain;h=c3fa8a36345fedf14bab1c628340d73f9908c52c API: add 'permissions' API endpoint 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 --- 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) = @_;