From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id B1ACF1FF161 for ; Wed, 6 Nov 2024 15:48:46 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 6581A10E75; Wed, 6 Nov 2024 15:48:55 +0100 (CET) From: Daniel Kral To: pve-devel@lists.proxmox.com Date: Wed, 6 Nov 2024 15:48:13 +0100 Message-Id: <20241106144813.189056-1-d.kral@proxmox.com> X-Mailer: git-send-email 2.39.5 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.000 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [api-get-permissions-test.pl, api-tests.pl, perm-test7.pl, proxmox.com, perm-test8.pl] Subject: [pve-devel] [PATCH access-control] tests: api: add tests for expected output of get permissions endpoint X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" 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 --- 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.gruenbichler@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