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 998459346D for ; Wed, 4 Jan 2023 14:40:47 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 7B24D1F848 for ; Wed, 4 Jan 2023 14:40:47 +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 for ; Wed, 4 Jan 2023 14:40:46 +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 54A4643E6A for ; Wed, 4 Jan 2023 14:40:46 +0100 (CET) Date: Wed, 4 Jan 2023 14:40:45 +0100 From: Wolfgang Bumiller To: Lukas Wagner Cc: pbs-devel@lists.proxmox.com Message-ID: <20230104134045.claxj34i3efc465u@casey.proxmox.com> References: <20230103142308.656240-1-l.wagner@proxmox.com> <20230103142308.656240-8-l.wagner@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230103142308.656240-8-l.wagner@proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL 0.217 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 Subject: Re: [pbs-devel] [PATCH proxmox-backup 07/17] api-types: add config options for LDAP user sync X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Jan 2023 13:40:47 -0000 On Tue, Jan 03, 2023 at 03:22:58PM +0100, Lukas Wagner wrote: > Signed-off-by: Lukas Wagner > --- > pbs-api-types/src/ldap.rs | 124 ++++++++++++++++++++++++++++++++- > src/api2/config/access/ldap.rs | 37 ++++++++++ > 2 files changed, 159 insertions(+), 2 deletions(-) > > diff --git a/pbs-api-types/src/ldap.rs b/pbs-api-types/src/ldap.rs > index a08e124b..672c81cd 100644 > --- a/pbs-api-types/src/ldap.rs > +++ b/pbs-api-types/src/ldap.rs > @@ -1,6 +1,6 @@ > use serde::{Deserialize, Serialize}; > > -use proxmox_schema::{api, Updater}; > +use proxmox_schema::{api, ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, Updater}; > > use super::{REALM_ID_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA}; > > @@ -32,7 +32,19 @@ pub enum LdapMode { > "verify": { > optional: true, > default: false, > - } > + }, > + "sync-defaults-options": { > + schema: SYNC_DEFAULTS_STRING_SCHEMA, > + optional: true, > + }, > + "sync-attributes": { > + schema: SYNC_ATTRIBUTES_SCHEMA, > + optional: true, > + }, > + "user-classes" : { > + optional: true, > + schema: USER_CLASSES_SCHEMA, > + }, > }, > )] > #[derive(Serialize, Deserialize, Updater, Clone)] > @@ -68,4 +80,112 @@ pub struct LdapRealmConfig { > /// Bind password for the given bind-dn > #[serde(skip_serializing_if = "Option::is_none")] > pub password: Option, > + /// Custom LDAP search filter for user sync > + #[serde(skip_serializing_if = "Option::is_none")] > + pub filter: Option, > + /// Default options for LDAP sync > + #[serde(skip_serializing_if = "Option::is_none")] > + pub sync_defaults_options: Option, > + /// List of attributes to sync from LDAP to user config > + #[serde(skip_serializing_if = "Option::is_none")] > + pub sync_attributes: Option, > + /// User ``objectClass`` classes to sync > + #[serde(skip_serializing_if = "Option::is_none")] > + pub user_classes: Option, > +} > + > +#[api( > + properties: { > + "remove-vanished": { > + optional: true, > + schema: REMOVE_VANISHED_SCHEMA, > + }, > + }, > + > +)] > +#[derive(Serialize, Deserialize, Updater, Default, Debug)] > +#[serde(rename_all = "kebab-case")] > +/// Default options for LDAP synchronization runs > +pub struct SyncDefaultsOptions { > + /// How to handle vanished properties/users > + pub remove_vanished: Option, ^ Should be possible to actually use `RemoveVanished` as a type here? (and replace `schema: REMOVE_..` with `type: RemoveVanished,` in the `#[api]` block. > + /// Enable new users after sync > + pub enable_new: Option, > +} > + > +#[api()] > +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] > +#[serde(rename_all = "kebab-case")] > +/// remove-vanished options > +pub enum RemoveVanished { > + /// Delete ACLs for vanished users > + Acl, > + /// Remove vanished users > + Entry, > + /// Remove vanished properties from users (e.g. email) > + Properties, > } > + > +pub const SYNC_DEFAULTS_STRING_SCHEMA: Schema = StringSchema::new("sync defaults options") > + .format(&ApiStringFormat::PropertyString( > + &SyncDefaultsOptions::API_SCHEMA, > + )) > + .schema(); > + > +const REMOVE_VANISHED_DESCRIPTION: &str = > + "A semicolon-seperated list of things to remove when they or the user \ > +vanishes during user synchronization. The following values are possible: ``entry`` removes the \ > +user when not returned from the sync; ``properties`` removes any \ > +properties on existing user that do not appear in the source. \ > +``acl`` removes ACLs when the user is not returned from the sync."; > + > +pub const REMOVE_VANISHED_SCHEMA: Schema = StringSchema::new(REMOVE_VANISHED_DESCRIPTION) > + .format(&ApiStringFormat::PropertyString(&REMOVE_VANISHED_ARRAY)) > + .schema(); > + > +pub const REMOVE_VANISHED_ARRAY: Schema = ArraySchema::new( > + "Array of remove-vanished options", > + &RemoveVanished::API_SCHEMA, > +) > +.min_length(1) > +.schema(); > + > +#[api()] > +#[derive(Serialize, Deserialize, Updater, Default, Debug)] > +#[serde(rename_all = "kebab-case")] > +/// Determine which LDAP attributes should be synced to which user attributes > +pub struct SyncAttributes { > + /// Name of the LDAP attribute containing the user's email address > + pub email: Option, > + /// Name of the LDAP attribute containing the user's first name > + pub firstname: Option, > + /// Name of the LDAP attribute containing the user's last name > + pub lastname: Option, > +} > + > +const SYNC_ATTRIBUTES_TEXT: &str = "Comma-separated list of key=value pairs for specifying \ > +which LDAP attributes map to which PBS user field. For example, \ > +to map the LDAP attribute ``mail`` to PBS's ``email``, write \ > +``email=mail``."; > + > +pub const SYNC_ATTRIBUTES_SCHEMA: Schema = StringSchema::new(SYNC_ATTRIBUTES_TEXT) > + .format(&ApiStringFormat::PropertyString( > + &SyncAttributes::API_SCHEMA, > + )) > + .schema(); > + > +pub const USER_CLASSES_ARRAY: Schema = ArraySchema::new( > + "Array of user classes", > + &StringSchema::new("user class").schema(), > +) > +.min_length(1) > +.schema(); > + > +const USER_CLASSES_TEXT: &str = "Comma-separated list of allowed objectClass values for user synchronization. \ > +For instance, if ``user-classes`` is set to ``person,user``, then user synchronization will consider all LDAP entities > +where ``objectClass: person`` `or` ``objectClass: user``."; ^ seems to need reformatting (100 char limit) > + > +pub const USER_CLASSES_SCHEMA: Schema = StringSchema::new(USER_CLASSES_TEXT) > + .format(&ApiStringFormat::PropertyString(&USER_CLASSES_ARRAY)) > + .default("inetorgperson,posixaccount,person,user") > + .schema();