]> git.proxmox.com Git - pve-access-control.git/commitdiff
API token: implement permission checks
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Tue, 21 Jan 2020 12:54:09 +0000 (13:54 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Wed, 29 Jan 2020 20:21:58 +0000 (21:21 +0100)
non-privsep tokens will always return the roles/permissions of their
associated users. privsep tokens will return unfiltered roles, but
filtered permissions.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
PVE/AccessControl.pm
PVE/RPCEnvironment.pm

index b5e1e094e7cfcaf424a45e8c08b08a645bfd3fb9..71ccf6ba7b7667c0a8d693abbd4a996d1913c04c 100644 (file)
@@ -1352,10 +1352,25 @@ sub roles {
     my ($cfg, $user, $path) = @_;
 
     # NOTE: we do not consider pools here.
+    # NOTE: for privsep tokens, this does not filter roles by those that the
+    # corresponding user has.
     # Use $rpcenv->permission() for any actual permission checks!
 
     return 'Administrator' if $user eq 'root@pam'; # root can do anything
 
+    if (pve_verify_tokenid($user, 1)) {
+       my $tokenid = $user;
+       my ($username, $token) = split_tokenid($tokenid);
+
+       my $token_info = $cfg->{users}->{$username}->{tokens}->{$token};
+       return () if !$token_info;
+
+       my @user_roles = roles($cfg, $username, $path);
+
+       # return full user privileges
+       return @user_roles if !$token_info->{privsep};
+    }
+
     my $perm = {};
 
     foreach my $p (sort keys %{$cfg->{acl}}) {
@@ -1367,6 +1382,21 @@ sub roles {
 
        #print "CHECKACL $path $p\n";
        #print "ACL $path = " . Dumper ($acl);
+       if (my $ri = $acl->{tokens}->{$user}) {
+           my $new;
+           foreach my $role (keys %$ri) {
+               my $propagate = $ri->{$role};
+               if ($final || $propagate) {
+                   #print "APPLY ROLE $p $user $role\n";
+                   $new = {} if !$new;
+                   $new->{$role} = 1;
+               }
+           }
+           if ($new) {
+               $perm = $new; # overwrite previous settings
+               next;
+           }
+       }
 
        if (my $ri = $acl->{users}->{$user}) {
            my $new;
index 7e0af7047a6aeb5e7519367538fde44bc0159692..e37c6481780431915e9b4aabc61ea7ab5e05eefb 100644 (file)
@@ -30,6 +30,9 @@ my $compile_acl_path = sub {
     $cache->{$user} = {} if !$cache->{$user};
     my $data = $cache->{$user};
 
+    my ($username, undef) = PVE::AccessControl::split_tokenid($user, 1);
+    die "internal error" if $username && $username ne 'root@pam' && !defined($cache->{$username});
+
     if (!$data->{poolroles}) {
        $data->{poolroles} = {};
 
@@ -76,6 +79,13 @@ my $compile_acl_path = sub {
            }
        }
     }
+
+    if ($username && $username ne 'root@pam') {
+       # intersect user and token permissions
+       my $user_privs = $cache->{$username}->{privs}->{$path};
+       $privs = { map { $_ => 1 } grep { $user_privs->{$_} } keys %$privs };
+    }
+
     $data->{privs}->{$path} = $privs;
 
     return $privs;
@@ -89,8 +99,21 @@ sub permissions {
        return $cfg->{roles}->{'Administrator'};
     }
 
-    $user = PVE::AccessControl::verify_username($user, 1);
-    return {} if !$user;
+    if (PVE::AccessControl::pve_verify_tokenid($user, 1)) {
+       my ($username, $token) = PVE::AccessControl::split_tokenid($user);
+       my $cfg = $self->{user_cfg};
+       my $token_info = $cfg->{users}->{$username}->{tokens}->{$token};
+       return {} if !$token_info;
+
+       # ensure cache for user is populated
+       my $user_perms = $self->permissions($username, $path);
+
+       # return user privs for non-privsep tokens
+       return $user_perms if !$token_info->{privsep};
+    } else {
+       $user = PVE::AccessControl::verify_username($user, 1);
+       return {} if !$user;
+    }
 
     my $cache = $self->{aclcache};
     $cache->{$user} = {} if !$cache->{$user};