Adds test cases for the GET permissions API endpoint to ensure that: - users with the Sys.Audit perm can access any user's permissions - users with the Sys.Audit perm can access any token's permissions - users without the Sys.Audit perm can access their own permissions - users without the Sys.Audit perm can access their token's permissions - tokens with the Sys.Audit perm can access any user's permissions - tokens without the Sys.Audit perm can access their own permissions
These tests also separate whether a token has the privilege-separated property or not. Signed-off-by: Daniel Kral <d.k...@proxmox.com> --- This is related to the following patch series and should be only applied after it: https://lore.proxmox.com/pve-devel/20241105083039.150454-1-f.gruenbich...@proxmox.com/ Without the patch series above applied, test cases 2-4, 8, 13, 29 should fail, as these were not considered before. src/test/Makefile | 1 + src/test/api-get-permissions-test.cfg | 17 ++ src/test/api-get-permissions-test.pl | 325 ++++++++++++++++++++++++++ src/test/api-tests.pl | 12 + 4 files changed, 355 insertions(+) create mode 100644 src/test/api-get-permissions-test.cfg create mode 100644 src/test/api-get-permissions-test.pl create mode 100755 src/test/api-tests.pl diff --git a/src/test/Makefile b/src/test/Makefile index 859a84b..53f2da7 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -13,3 +13,4 @@ check: perl -I.. perm-test7.pl perl -I.. perm-test8.pl perl -I.. realm_sync_test.pl + perl -I.. api-tests.pl diff --git a/src/test/api-get-permissions-test.cfg b/src/test/api-get-permissions-test.cfg new file mode 100644 index 0000000..d9e415e --- /dev/null +++ b/src/test/api-get-permissions-test.cfg @@ -0,0 +1,17 @@ +user:auditor@pam:1: +token:auditor@pam!noprivsep::0: +token:auditor@pam!privsep::1: +user:stranger@pve:1: +token:stranger@pve!noprivsep::0: +token:stranger@pve!privsep::1: + +role:sys_auditor:Sys.Audit: +role:vm_lurker:VM.Audit,VM.Console: +role:vm_manager:VM.PowerMgmt: + +acl:1:/access:auditor@pam:sys_auditor: +acl:1:/vms:auditor@pam:vm_lurker: +acl:1:/vms:auditor@pam!privsep:vm_lurker: +acl:1:/vms:stranger@pve:vm_lurker: +acl:1:/vms:stranger@pve:vm_manager: +acl:1:/vms:stranger@pve!privsep:vm_lurker: diff --git a/src/test/api-get-permissions-test.pl b/src/test/api-get-permissions-test.pl new file mode 100644 index 0000000..f1af49f --- /dev/null +++ b/src/test/api-get-permissions-test.pl @@ -0,0 +1,325 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use lib qw(..); + +use PVE::Tools; + +use Test::More; +use Test::MockModule; + +use PVE::AccessControl; +use PVE::RPCEnvironment; +use PVE::API2::AccessControl; + +my $cluster_module = Test::MockModule->new('PVE::Cluster'); +# make cfs_update a stub as it's not relevant to the test cases and will +# make these tests fail if the user doesn't have access to the cluster ipcc +$cluster_module->noop('cfs_update'); + +my $rpcenv = PVE::RPCEnvironment->init('cli'); +$rpcenv->init_request(userconfig => 'api-get-permissions-test.cfg'); + +my ($handler, $handler_info) = PVE::API2::AccessControl->find_handler('GET', 'permissions'); + +# stranger = user without Sys.Audit permission +my $stranger_perms = $rpcenv->get_effective_permissions('stranger@pve'); +my $stranger_privsep_perms = $rpcenv->get_effective_permissions('stranger@pve!privsep'); + +my $stranger_user_tests = [ + { + description => 'get stranger\'s perms without passing the user\'s userid', + rpcuser => 'stranger@pve', + params => {}, + result => $stranger_perms, + }, + { + description => 'get stranger\'s perms with passing the user\'s userid', + rpcuser => 'stranger@pve', + params => { + userid => 'stranger@pve', + }, + result => $stranger_perms, + }, + { + description => 'get stranger-owned non-priv-sep\'d token\'s perms from stranger user', + rpcuser => 'stranger@pve', + params => { + userid => 'stranger@pve!noprivsep', + }, + result => $stranger_perms, + }, + { + description => 'get stranger-owned priv-sep\'d token\'s perms from stranger user', + rpcuser => 'stranger@pve', + params => { + userid => 'stranger@pve!privsep', + }, + result => $stranger_privsep_perms, + }, + { + description => 'get auditor\'s perms from stranger user', + should_fail => 1, + rpcuser => 'stranger@pve', + params => { + userid => 'auditor@pam', + }, + }, + { + description => 'get auditor-owned token\'s perms from stranger user', + should_fail => 1, + rpcuser => 'stranger@pve', + params => { + userid => 'auditor@pam!noprivsep', + }, + }, +]; + +my $stranger_nonprivsep_tests = [ + { + description => 'get stranger-owned non-priv-sep\'d token\'s perms without passing the token', + rpcuser => 'stranger@pve!noprivsep', + params => {}, + result => $stranger_perms, + }, + { + description => 'get stranger-owned non-priv-sep\'d token\'s perms with passing the token', + rpcuser => 'stranger@pve!noprivsep', + params => { + userid => 'stranger@pve!noprivsep', + }, + result => $stranger_perms, + }, + { + description => 'get stranger\'s perms from stranger-owned non-priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!noprivsep', + params => { + userid => 'stranger@pve', + }, + }, + { + description => 'get stranger-owned priv-sep\'d token\'s perms ' + . 'from stranger-owned non-priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!noprivsep', + params => { + userid => 'stranger@pve!privsep', + }, + }, + { + description => 'get auditor-owned token\'s perms from stranger-owned non-priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!noprivsep', + params => { + userid => 'auditor@pam!noprivsep', + } + }, +]; + +my $stranger_privsep_tests = [ + { + description => 'get stranger-owned priv-sep\'d token\'s perms without passing the token', + rpcuser => 'stranger@pve!privsep', + params => {}, + result => $stranger_privsep_perms, + }, + { + description => 'get stranger-owned priv-sep\'d token\'s perms with passing the token', + rpcuser => 'stranger@pve!privsep', + params => { + userid => 'stranger@pve!privsep', + }, + result => $stranger_privsep_perms, + }, + { + description => 'get stranger\'s perms from stranger-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!privsep', + params => { + userid => 'stranger@pve', + }, + }, + { + description => 'get stranger-owned non-priv-sep\'d token\'s perms ' + . 'from stranger-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!privsep', + params => { + userid => 'stranger@pve!noprivsep', + }, + }, + { + description => 'get auditor-owned token\'s perms from stranger-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'stranger@pve!privsep', + params => { + userid => 'auditor@pam!noprivsep', + } + }, +]; + +# auditor = user with Sys.Audit permission +my $auditor_perms = $rpcenv->get_effective_permissions('auditor@pam'); +my $auditor_privsep_perms = $rpcenv->get_effective_permissions('auditor@pam!privsep'); + +my $auditor_user_tests = [ + { + description => 'get auditor\'s perms without passing the user\'s userid', + rpcuser => 'auditor@pam', + params => {}, + result => $auditor_perms, + }, + { + description => 'get auditor\'s perms with passing the user\'s userid', + rpcuser => 'auditor@pam', + params => { + userid => 'auditor@pam', + }, + result => $auditor_perms, + }, + { + description => 'get auditor-owned non-priv-sep\'d token\'s perms from auditor user', + rpcuser => 'auditor@pam', + params => { + userid => 'auditor@pam!noprivsep', + }, + result => $auditor_perms, + }, + { + description => 'get auditor-owned priv-sep\'d token\'s perms from auditor user', + rpcuser => 'auditor@pam', + params => { + userid => 'auditor@pam!privsep', + }, + result => $auditor_privsep_perms, + }, + { + description => 'get stranger\'s perms from auditor user', + rpcuser => 'auditor@pam', + params => { + userid => 'stranger@pve', + }, + result => $stranger_perms, + }, + { + description => 'get stranger-owned token\'s perms from auditor user', + rpcuser => 'auditor@pam', + params => { + userid => 'stranger@pve!noprivsep', + }, + result => $stranger_perms, + }, +]; + +my $auditor_nonprivsep_tests = [ + { + description => 'get auditor-owned non-priv-sep\'d token\'s perms without passing the token', + rpcuser => 'auditor@pam!noprivsep', + params => {}, + result => $auditor_perms, + }, + { + description => 'get auditor-owned non-priv-sep\'d token\'s perms with passing the token', + rpcuser => 'auditor@pam!noprivsep', + params => { + userid => 'auditor@pam!noprivsep', + }, + result => $auditor_perms, + }, + { + description => 'get auditor\'s perms from auditor-owned non-priv-sep\'d token', + rpcuser => 'auditor@pam!noprivsep', + params => { + userid => 'auditor@pam', + }, + result => $auditor_perms, + }, + { + description => 'get auditor-owned priv-sep\'d token\'s perms ' + . 'from auditor-owned non-priv-sep\'d token', + rpcuser => 'auditor@pam!noprivsep', + params => { + userid => 'auditor@pam!privsep', + }, + result => $auditor_privsep_perms, + }, + { + description => 'get stranger-owned token\'s perms from auditor-owned non-priv-sep\'d token', + rpcuser => 'auditor@pam!noprivsep', + params => { + userid => 'stranger@pve!noprivsep', + }, + result => $stranger_perms, + }, +]; + +my $auditor_privsep_tests = [ + { + description => 'get auditor-owned priv-sep\'d token\'s perms without passing the token', + rpcuser => 'auditor@pam!privsep', + params => {}, + result => $auditor_privsep_perms, + }, + { + description => 'get auditor-owned priv-sep\'d token\'s perms with passing the token', + rpcuser => 'auditor@pam!privsep', + params => { + userid => 'auditor@pam!privsep', + }, + result => $auditor_privsep_perms, + }, + { + description => 'get auditor\'s perms from auditor-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'auditor@pam!privsep', + params => { + userid => 'auditor@pam', + }, + }, + { + description => 'get auditor-owned non-priv-sep\'d token\'s perms ' + . 'from auditor-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'auditor@pam!privsep', + params => { + userid => 'auditor@pam!noprivsep', + }, + }, + { + description => 'get stranger-owned token\'s perms from auditor-owned priv-sep\'d token', + should_fail => 1, + rpcuser => 'auditor@pam!privsep', + params => { + userid => 'stranger@pve!noprivsep', + }, + }, +]; + +my $tests = [ + @$stranger_user_tests, + @$stranger_nonprivsep_tests, + @$stranger_privsep_tests, + @$auditor_user_tests, + @$auditor_nonprivsep_tests, + @$auditor_privsep_tests, +]; + +plan(tests => scalar($tests->@*)); + +for my $case ($tests->@*) { + $rpcenv->set_user($case->{rpcuser}); + + my $result = eval { $handler->handle($handler_info, $case->{params}) }; + + if ($@) { + my $should_fail = exists($case->{should_fail}) ? $case->{should_fail} : 0; + is(defined($@), $should_fail, "should fail: $case->{description}") || diag explain $@; + } else { + is_deeply($result, $case->{result}, $case->{description}); + } +} + +done_testing(); diff --git a/src/test/api-tests.pl b/src/test/api-tests.pl new file mode 100755 index 0000000..a1a987a --- /dev/null +++ b/src/test/api-tests.pl @@ -0,0 +1,12 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use TAP::Harness; + +my $harness = TAP::Harness->new({ verbosity => -1 }); + +my $result = $harness->runtests('api-get-permissions-test.pl'); + +exit -1 if $result->{failed}; -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel