mirror of
https://git.proxmox.com/git/pve-access-control
synced 2025-07-27 04:44:57 +00:00
cleanup permission checks
Added new Real.AllocateUser priviledge
This commit is contained in:
parent
8de1fb5ae3
commit
82b63965eb
@ -54,6 +54,9 @@ __PACKAGE__->register_method ({
|
|||||||
path => '',
|
path => '',
|
||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Directory index.",
|
description => "Directory index.",
|
||||||
|
permissions => {
|
||||||
|
user => 'all',
|
||||||
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
properties => {},
|
properties => {},
|
||||||
@ -220,10 +223,13 @@ __PACKAGE__->register_method ({
|
|||||||
path => 'password',
|
path => 'password',
|
||||||
method => 'PUT',
|
method => 'PUT',
|
||||||
permissions => {
|
permissions => {
|
||||||
description => "Each user is allowed to change his own password. A user can change the password of another user if he has modify permission on /access/groups/<group> on a group where user <userid> is member of.",
|
description => "Each user is allowed to change his own password. A user can change the password of another user if he has 'Realm.AllocateUser' (on the realm of user <userid>) and 'User.Modify' permission on /access/groups/<group> on a group where user <userid> is member of.",
|
||||||
check => [ 'or',
|
check => [ 'or',
|
||||||
['userid-param', 'self'],
|
['userid-param', 'self'],
|
||||||
['userid-group', ['User.Modify']],
|
[ 'and',
|
||||||
|
[ 'userid-param', 'Realm.AllocateUser'],
|
||||||
|
[ 'userid-group', ['User.Modify']]
|
||||||
|
]
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
protected => 1, # else we can't access shadow files
|
protected => 1, # else we can't access shadow files
|
||||||
|
@ -18,7 +18,10 @@ __PACKAGE__->register_method ({
|
|||||||
path => '',
|
path => '',
|
||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Authentication domain index.",
|
description => "Authentication domain index.",
|
||||||
permissions => { user => 'world' },
|
permissions => {
|
||||||
|
description => "Anyone can access that, because we need that list for the login box (before the user is authenticated).",
|
||||||
|
user => 'world',
|
||||||
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
properties => {},
|
properties => {},
|
||||||
@ -58,7 +61,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '',
|
path => '',
|
||||||
method => 'POST',
|
method => 'POST',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/realm', ['Realm.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Add an authentication server.",
|
description => "Add an authentication server.",
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -168,7 +171,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{realm}',
|
path => '{realm}',
|
||||||
method => 'PUT',
|
method => 'PUT',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/realm', ['Realm.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Update authentication server settings.",
|
description => "Update authentication server settings.",
|
||||||
protected => 1,
|
protected => 1,
|
||||||
@ -273,7 +276,7 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Get auth server configuration.",
|
description => "Get auth server configuration.",
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Audit']],
|
check => ['perm', '/access/realm', ['Realm.Allocate', 'Sys.Audit'], any => 1],
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
@ -301,7 +304,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{realm}',
|
path => '{realm}',
|
||||||
method => 'DELETE',
|
method => 'DELETE',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/realm', ['Realm.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Delete an authentication server.",
|
description => "Delete an authentication server.",
|
||||||
protected => 1,
|
protected => 1,
|
||||||
|
@ -15,7 +15,7 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Group index.",
|
description => "Group index.",
|
||||||
permissions => {
|
permissions => {
|
||||||
description => "The returned list is restricted to groups where you have 'User.Allocate' or 'Sys.Audit' permissions on '/access', or 'User.Allocate' on /access/groups/<group>.",
|
description => "The returned list is restricted to groups where you have 'User.Modify', 'Sys.Audit' or 'Group.Allocate' permissions on /access/groups/<group>.",
|
||||||
user => 'all',
|
user => 'all',
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -41,12 +41,10 @@ __PACKAGE__->register_method ({
|
|||||||
my $usercfg = cfs_read_file("user.cfg");
|
my $usercfg = cfs_read_file("user.cfg");
|
||||||
my $authuser = $rpcenv->get_user();
|
my $authuser = $rpcenv->get_user();
|
||||||
|
|
||||||
my $privs = [ 'User.Allocate', 'Sys.Audit' ];
|
my $privs = [ 'User.Modify', 'Sys.Audit', 'Group.Allocate'];
|
||||||
my $allow = $rpcenv->check_any($authuser, "/access", $privs, 1);
|
|
||||||
my $allowed_groups = $rpcenv->filter_groups($authuser, $privs, 1);
|
|
||||||
|
|
||||||
foreach my $group (keys %{$usercfg->{groups}}) {
|
foreach my $group (keys %{$usercfg->{groups}}) {
|
||||||
next if !($allow || $allowed_groups->{$group});
|
next if !$rpcenv->check_any($authuser, "/access/groups/$group", $privs, 1);
|
||||||
my $data = $usercfg->{groups}->{$group};
|
my $data = $usercfg->{groups}->{$group};
|
||||||
my $entry = { groupid => $group };
|
my $entry = { groupid => $group };
|
||||||
$entry->{comment} = $data->{comment} if defined($data->{comment});
|
$entry->{comment} = $data->{comment} if defined($data->{comment});
|
||||||
@ -62,7 +60,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '',
|
path => '',
|
||||||
method => 'POST',
|
method => 'POST',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/groups', ['Group.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Create new group.",
|
description => "Create new group.",
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -103,7 +101,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{groupid}',
|
path => '{groupid}',
|
||||||
method => 'PUT',
|
method => 'PUT',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/groups', ['Group.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Update group data.",
|
description => "Update group data.",
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -142,8 +140,8 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{groupid}',
|
path => '{groupid}',
|
||||||
method => 'GET',
|
method => 'GET',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Audit']],
|
check => ['perm', '/access/groups', ['Sys.Audit', 'Group.Allocate'], any => 1],
|
||||||
},
|
},
|
||||||
description => "Get group configuration.",
|
description => "Get group configuration.",
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
@ -191,7 +189,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{groupid}',
|
path => '{groupid}',
|
||||||
method => 'DELETE',
|
method => 'DELETE',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Modify']],
|
check => ['perm', '/access/groups', ['Group.Allocate']],
|
||||||
},
|
},
|
||||||
description => "Delete group.",
|
description => "Delete group.",
|
||||||
parameters => {
|
parameters => {
|
||||||
|
@ -19,7 +19,7 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Role index.",
|
description => "Role index.",
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Audit']],
|
user => 'all',
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
@ -141,7 +141,7 @@ __PACKAGE__->register_method ({
|
|||||||
path => '{roleid}',
|
path => '{roleid}',
|
||||||
method => 'GET',
|
method => 'GET',
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['perm', '/access', ['Sys.Audit']],
|
user => 'all',
|
||||||
},
|
},
|
||||||
description => "Get role configuration.",
|
description => "Get role configuration.",
|
||||||
parameters => {
|
parameters => {
|
||||||
|
@ -38,7 +38,7 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "User index.",
|
description => "User index.",
|
||||||
permissions => {
|
permissions => {
|
||||||
description => "The returned list is restricted to users where you have 'User.Modify' or 'User.Allocate' permissions on '/access' or on a group the user belongs too. But it always includes the current (authenticated) user.",
|
description => "The returned list is restricted to users where you have 'User.Modify' or 'Sys.Audit' permissions on '/access/groups' or on a group the user belongs too. But it always includes the current (authenticated) user.",
|
||||||
user => 'all',
|
user => 'all',
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -70,9 +70,8 @@ __PACKAGE__->register_method ({
|
|||||||
|
|
||||||
my $res = [];
|
my $res = [];
|
||||||
|
|
||||||
my $privs = [ 'User.Modify', 'User.Allocate' ];
|
my $privs = [ 'User.Modify', 'Sys.Audit' ];
|
||||||
|
my $canUserMod = $rpcenv->check_any($authuser, "/access/groups", $privs, 1);
|
||||||
my $canUserMod = $rpcenv->check_any($authuser, "/access", $privs, 1);
|
|
||||||
my $groups = $rpcenv->filter_groups($authuser, $privs, 1);
|
my $groups = $rpcenv->filter_groups($authuser, $privs, 1);
|
||||||
my $allowed_users = $rpcenv->group_member_join([keys %$groups]);
|
my $allowed_users = $rpcenv->group_member_join([keys %$groups]);
|
||||||
|
|
||||||
@ -102,8 +101,11 @@ __PACKAGE__->register_method ({
|
|||||||
path => '',
|
path => '',
|
||||||
method => 'POST',
|
method => 'POST',
|
||||||
permissions => {
|
permissions => {
|
||||||
description => "You need 'User.Allocate' permissions to '/access/groups/<group>' for any group specified, or 'User.Allocate' on '/access' if you pass no groups.",
|
description => "You need 'Realm.AllocateUser' on '/access/realm/<realm>' on the realm of user <userid>, and 'User.Modify' permissions to '/access/groups/<group>' for any group specified (or 'User.Modify' on '/access/groups' if you pass no groups.",
|
||||||
check => ['userid-group', ['User.Allocate'], groups_param => 1],
|
check => [ 'and',
|
||||||
|
[ 'userid-param', 'Realm.AllocateUser'],
|
||||||
|
[ 'userid-group', ['User.Modify'], groups_param => 1],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
description => "Create new user.",
|
description => "Create new user.",
|
||||||
parameters => {
|
parameters => {
|
||||||
@ -184,7 +186,7 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'GET',
|
method => 'GET',
|
||||||
description => "Get user configuration.",
|
description => "Get user configuration.",
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['userid-group', ['User.Modify']],
|
check => ['userid-group', ['User.Modify', 'Sys.Audit']],
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
@ -302,7 +304,10 @@ __PACKAGE__->register_method ({
|
|||||||
method => 'DELETE',
|
method => 'DELETE',
|
||||||
description => "Delete user.",
|
description => "Delete user.",
|
||||||
permissions => {
|
permissions => {
|
||||||
check => ['userid-group', ['User.Allocate']],
|
check => [ 'and',
|
||||||
|
[ 'userid-param', 'Realm.AllocateUser'],
|
||||||
|
[ 'userid-group', ['User.Modify']],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
parameters => {
|
parameters => {
|
||||||
additionalProperties => 0,
|
additionalProperties => 0,
|
||||||
|
@ -557,7 +557,7 @@ my $privgroups = {
|
|||||||
'VM.PowerMgmt',
|
'VM.PowerMgmt',
|
||||||
],
|
],
|
||||||
audit => [
|
audit => [
|
||||||
'VM.Audit'
|
'VM.Audit',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Sys => {
|
Sys => {
|
||||||
@ -588,10 +588,13 @@ my $privgroups = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
User => {
|
User => {
|
||||||
root => [],
|
root => [
|
||||||
|
'Realm.Allocate',
|
||||||
|
],
|
||||||
admin => [
|
admin => [
|
||||||
'User.Modify',
|
'User.Modify',
|
||||||
'User.Allocate',
|
'Group.Allocate', # edit/change group settings
|
||||||
|
'Realm.AllocateUser',
|
||||||
],
|
],
|
||||||
user => [],
|
user => [],
|
||||||
audit => [],
|
audit => [],
|
||||||
|
@ -348,12 +348,12 @@ sub exec_api2_perm_check {
|
|||||||
} elsif ($test eq 'userid-group') {
|
} elsif ($test eq 'userid-group') {
|
||||||
my $userid = $param->{userid};
|
my $userid = $param->{userid};
|
||||||
my ($t, $privs, %options) = @$check;
|
my ($t, $privs, %options) = @$check;
|
||||||
return if !$options{groups_param} && !$self->check_user_exist($userid, $noerr);
|
return 0 if !$options{groups_param} && !$self->check_user_exist($userid, $noerr);
|
||||||
if (!$self->check_any($username, "/access", $privs, 1)) {
|
if (!$self->check_any($username, "/access/groups", $privs, 1)) {
|
||||||
my $groups = $self->filter_groups($username, $privs, 1);
|
my $groups = $self->filter_groups($username, $privs, 1);
|
||||||
if ($options{groups_param}) {
|
if ($options{groups_param}) {
|
||||||
my @group_param = PVE::Tools::split_list($param->{groups});
|
my @group_param = PVE::Tools::split_list($param->{groups});
|
||||||
raise_perm_exc("/access, " . join("|", @$privs)) if !scalar(@group_param);
|
raise_perm_exc("/access/groups, " . join("|", @$privs)) if !scalar(@group_param);
|
||||||
foreach my $pg (@group_param) {
|
foreach my $pg (@group_param) {
|
||||||
raise_perm_exc("/access/groups/$pg, " . join("|", @$privs))
|
raise_perm_exc("/access/groups/$pg, " . join("|", @$privs))
|
||||||
if !$groups->{$pg};
|
if !$groups->{$pg};
|
||||||
@ -368,7 +368,7 @@ sub exec_api2_perm_check {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
} elsif ($test eq 'userid-param') {
|
} elsif ($test eq 'userid-param') {
|
||||||
my $userid = $param->{userid};
|
my ($userid, undef, $realm) = verify_username($param->{userid});
|
||||||
return if !$self->check_user_exist($userid, $noerr);
|
return if !$self->check_user_exist($userid, $noerr);
|
||||||
my ($t, $subtest) = @$check;
|
my ($t, $subtest) = @$check;
|
||||||
die "missing parameters" if !$subtest;
|
die "missing parameters" if !$subtest;
|
||||||
@ -376,10 +376,15 @@ sub exec_api2_perm_check {
|
|||||||
return 1 if $username eq 'userid';
|
return 1 if $username eq 'userid';
|
||||||
return 0 if $noerr;
|
return 0 if $noerr;
|
||||||
raise_perm_exc();
|
raise_perm_exc();
|
||||||
|
} elsif ($subtest eq 'Realm.AllocateUser') {
|
||||||
|
my $path = "/access/realm/$realm";
|
||||||
|
return $self->check($username, $path, ['Realm.AllocateUser'], $noerr);
|
||||||
|
return 0 if $noerr;
|
||||||
|
raise_perm_exc("$path, 'Realm.AllocateUser'");
|
||||||
} else {
|
} else {
|
||||||
die "unknown userid-param test";
|
die "unknown userid-param test";
|
||||||
}
|
}
|
||||||
} elsif ($test eq 'perm-modify') {
|
} elsif ($test eq 'perm-modify') {
|
||||||
my ($t, $tmplpath) = @$check;
|
my ($t, $tmplpath) = @$check;
|
||||||
my $path = PVE::Tools::template_replace($tmplpath, $param);
|
my $path = PVE::Tools::template_replace($tmplpath, $param);
|
||||||
$path = PVE::AccessControl::normalize_path($path);
|
$path = PVE::AccessControl::normalize_path($path);
|
||||||
|
Loading…
Reference in New Issue
Block a user