From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 0A120614C3 for ; Fri, 4 Feb 2022 15:25:04 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 06DB232F3B for ; Fri, 4 Feb 2022 15:25:04 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id BCA8832F30 for ; Fri, 4 Feb 2022 15:25:02 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 8FA2B44BDB for ; Fri, 4 Feb 2022 15:25:02 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Fri, 4 Feb 2022 15:24:59 +0100 Message-Id: <20220204142501.1461441-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220204142501.1461441-1-d.csapak@proxmox.com> References: <20220204142501.1461441-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.159 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - Subject: [pve-devel] [PATCH access-control v2 1/2] realm-sync: replace 'full' option with 'mode' 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: , X-List-Received-Date: Fri, 04 Feb 2022 14:25:04 -0000 to be able to add more modes in the future. full=0 maps to mode=update and full=1 to mode=full but keep 'full' for backwards-compatibiltiy. On create/update, replace full=1 with mode=full, on read, return both. add a deprecation notice to the description of full, and a todo to remove 'full' with 8.0 Signed-off-by: Dominik Csapak --- src/PVE/API2/Domains.pm | 57 ++++++++++++++++++++++++++++++++++------- src/PVE/Auth/Plugin.pm | 19 +++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/PVE/API2/Domains.pm b/src/PVE/API2/Domains.pm index 56e8394..2f351ad 100644 --- a/src/PVE/API2/Domains.pm +++ b/src/PVE/API2/Domains.pm @@ -17,6 +17,25 @@ my $domainconfigfile = "domains.cfg"; use base qw(PVE::RESTHandler); +# maps old 'full' parameter to new 'mode' +# TODO remove when we delete the 'full' parameter +my $map_sync_mode = sub { + my ($cfg, $delete_full) = @_; + + my $opt = $cfg->{'sync-defaults-options'}; + return if !defined($opt); + my $sync_opts_fmt = PVE::JSONSchema::get_format('realm-sync-options'); + + my $new_opt = PVE::JSONSchema::parse_property_string($sync_opts_fmt, $opt); + + $new_opt->{mode} = $new_opt->{mode} // ($new_opt->{full} ? 'full' : 'update'); + delete $new_opt->{full} if $delete_full; + + $cfg->{'sync-defaults-options'} = PVE::JSONSchema::print_property_string($new_opt, $sync_opts_fmt); + + return; +}; + __PACKAGE__->register_method ({ name => 'index', path => '', @@ -109,6 +128,10 @@ __PACKAGE__->register_method ({ die "unable to create builtin type '$type'\n" if ($type eq 'pam' || $type eq 'pve'); + if ($type eq 'ad' || $type eq 'ldap') { + $map_sync_mode->($param, 1); + } + my $plugin = PVE::Auth::Plugin->lookup($type); my $config = $plugin->check_config($realm, $param, 1, 1); @@ -173,7 +196,12 @@ __PACKAGE__->register_method ({ $delete_pw = 1 if $opt eq 'password'; } - my $plugin = PVE::Auth::Plugin->lookup($ids->{$realm}->{type}); + my $type = $ids->{$realm}->{type}; + if ($type eq 'ad' || $type eq 'ldap') { + $map_sync_mode->($param, 1); + } + + my $plugin = PVE::Auth::Plugin->lookup($type); my $config = $plugin->check_config($realm, $param, 0, 1); if ($config->{default}) { @@ -225,6 +253,11 @@ __PACKAGE__->register_method ({ my $data = $cfg->{ids}->{$realm}; die "domain '$realm' does not exist\n" if !$data; + my $type = $data->{type}; + if ($type eq 'ad' || $type eq 'ldap') { + $map_sync_mode->($data); + } + $data->{digest} = $cfg->{digest}; return $data; @@ -274,13 +307,14 @@ __PACKAGE__->register_method ({ my $update_users = sub { my ($usercfg, $realm, $synced_users, $opts) = @_; - print "syncing users\n"; + print "syncing users (mode: $opts->{mode})\n"; + $usercfg->{users} = {} if !defined($usercfg->{users}); my $users = $usercfg->{users}; my $oldusers = {}; - if ($opts->{'full'}) { - print "full sync, deleting outdated existing users first\n"; + if ($opts->{mode} eq 'full') { + print "deleting outdated existing users first\n"; foreach my $userid (sort keys %$users) { next if $userid !~ m/\@$realm$/; @@ -310,7 +344,7 @@ my $update_users = sub { $user->{tokens} = $olduser->{tokens}; } if (defined($oldusers->{$userid})) { - print "updated user '$userid'\n"; + print "overwrote user '$userid'\n"; } else { print "added user '$userid'\n"; } @@ -327,13 +361,14 @@ my $update_users = sub { my $update_groups = sub { my ($usercfg, $realm, $synced_groups, $opts) = @_; - print "syncing groups\n"; + print "syncing groups (mode: $opts->{mode})\n"; + $usercfg->{groups} = {} if !defined($usercfg->{groups}); my $groups = $usercfg->{groups}; my $oldgroups = {}; - if ($opts->{full}) { - print "full sync, deleting outdated existing groups first\n"; + if ($opts->{mode} eq 'full') { + print "deleting outdated existing groups first\n"; foreach my $groupid (sort keys %$groups) { next if $groupid !~ m/\-$realm$/; @@ -382,10 +417,14 @@ my $parse_sync_opts = sub { $res->{$opt} = $param->{$opt} // $cfg_defaults->{$opt} // $fmt->{default}; + # for now, the default of 'mode' depends on 'full'' raise_param_exc({ "$opt" => 'Not passed as parameter and not defined in realm default sync options.' - }) if !defined($res->{$opt}); + }) if !defined($res->{$opt}) && $opt ne 'mode'; } + + $map_sync_mode->($res, 1); + return $res; }; diff --git a/src/PVE/Auth/Plugin.pm b/src/PVE/Auth/Plugin.pm index 1413053..8a60062 100755 --- a/src/PVE/Auth/Plugin.pm +++ b/src/PVE/Auth/Plugin.pm @@ -56,11 +56,22 @@ my $realm_sync_options_desc = { enum => [qw(users groups both)], optional => '1', }, + mode => { + description => "Update (Default): Only updates/adds fields/users returned by the server. " + ."Full: Removes any field/user that was not returned and overwrites all " + ."existing users with information from the server. " + ."If set, this parameter supersedes the parameter 'full'.", + type => 'string', + enum => [qw(update full)], + optional => '1', + }, + # TODO check/rewrite in pve7to8, and remove with 8.0 full => { - description => "If set, uses the LDAP Directory as source of truth," - ." deleting users or groups not returned from the sync. Otherwise" - ." only syncs information which is not already present, and does not" - ." deletes or modifies anything else.", + description => "DEPRECATED: use 'mode' instead. If set, uses the LDAP Directory as source of truth," + ." deleting users or groups not returned from the sync and removing" + ." all locally modified properties of synced users. If not set," + ." only syncs information which is present in the synced data, and does not" + ." delete or modify anything else.", type => 'boolean', optional => '1', }, -- 2.30.2