public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints
@ 2023-02-13 14:31 Lukas Wagner
  2023-02-13 16:32 ` Friedrich Weber
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Lukas Wagner @ 2023-02-13 14:31 UTC (permalink / raw)
  To: pbs-devel

Previously, if the value of a synced property did not validate properly
(e.g only 1 character in length instead of the required 2), the whole
sync job failed without any useful error message.

In this commit, the values are validated manually by their
respective StringSchema. If the validation fails, the value is
ignored and a warning is displayed in the task log.

In addition to that, some error messages have been improved.
Also, user sync is now more fault-tolerant in general, showing
warnings if something goes wrong while creating/updating a
single user, instead of aborting the whole sync job.

Reported-by: Friedrich Weber <f.weber@proxmox.com>
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
 src/server/realm_sync_job.rs | 98 ++++++++++++++++++++++++++----------
 1 file changed, 72 insertions(+), 26 deletions(-)

diff --git a/src/server/realm_sync_job.rs b/src/server/realm_sync_job.rs
index 0fd8adfe..874fe850 100644
--- a/src/server/realm_sync_job.rs
+++ b/src/server/realm_sync_job.rs
@@ -1,16 +1,18 @@
 use anyhow::{bail, Context, Error};
 use pbs_config::{acl::AclTree, token_shadow, BackupLockGuard};
+use proxmox_lang::try_block;
 use proxmox_ldap::{Config, Connection, SearchParameters, SearchResult};
 use proxmox_rest_server::WorkerTask;
-use proxmox_schema::ApiType;
+use proxmox_schema::{ApiType, Schema};
 use proxmox_section_config::SectionConfigData;
-use proxmox_sys::task_log;
+use proxmox_sys::{task_log, task_warn};
 
 use std::{collections::HashSet, sync::Arc};
 
 use pbs_api_types::{
     ApiToken, Authid, LdapRealmConfig, Realm, RemoveVanished, SyncAttributes as LdapSyncAttributes,
-    SyncDefaultsOptions, User, Userid, REMOVE_VANISHED_ARRAY, USER_CLASSES_ARRAY,
+    SyncDefaultsOptions, User, Userid, EMAIL_SCHEMA, FIRST_NAME_SCHEMA, LAST_NAME_SCHEMA,
+    REMOVE_VANISHED_ARRAY, USER_CLASSES_ARRAY,
 };
 
 use crate::{auth, server::jobstate::Job};
@@ -157,20 +159,32 @@ impl LdapRealmSyncJob {
         let mut retrieved_users = HashSet::new();
 
         for result in users {
-            let mut username = result
-                .attributes
-                .get(&self.ldap_sync_settings.user_attr)
-                .context("userid attribute not in search result")?
-                .get(0)
-                .context("userid attribute array is empty")?
-                .clone();
-
-            username.push_str(&format!("@{}", self.realm.as_str()));
-
-            let userid: Userid = username.parse()?;
-            retrieved_users.insert(userid.clone());
-
-            self.create_or_update_user(user_config, userid, result)?;
+            let user_id_attribute = &self.ldap_sync_settings.user_attr;
+
+            let result = try_block!({
+                let username = result
+                    .attributes
+                    .get(user_id_attribute)
+                    .context(format!(
+                        "userid attribute `{user_id_attribute}` not in LDAP search result"
+                    ))?
+                    .get(0)
+                    .context("userid attribute array is empty")?
+                    .clone();
+
+                let username = format!("{username}@{realm}", realm = self.realm.as_str());
+
+                let userid: Userid = username
+                    .parse()
+                    .context(format!("could not parse username `{username}`"))?;
+                retrieved_users.insert(userid.clone());
+
+                self.create_or_update_user(user_config, &userid, result)?;
+                anyhow::Ok(())
+            });
+            if let Err(e) = result {
+                task_log!(self.worker, "could not create/update user: {e}");
+            }
         }
 
         Ok(retrieved_users)
@@ -179,7 +193,7 @@ impl LdapRealmSyncJob {
     fn create_or_update_user(
         &self,
         user_config: &mut SectionConfigData,
-        userid: Userid,
+        userid: &Userid,
         result: &SearchResult,
     ) -> Result<(), Error> {
         let existing_user = user_config.lookup::<User>("user", userid.as_str()).ok();
@@ -213,37 +227,67 @@ impl LdapRealmSyncJob {
     fn construct_or_update_user(
         &self,
         result: &SearchResult,
-        userid: Userid,
+        userid: &Userid,
         existing_user: Option<&User>,
     ) -> User {
-        let lookup = |a: Option<&String>| {
-            a.and_then(|e| result.attributes.get(e))
+        let lookup = |attribute: &str, ldap_attribute: Option<&String>, schema: Schema| {
+            ldap_attribute
+                .and_then(|e| result.attributes.get(e))
                 .and_then(|v| v.get(0))
+                .and_then(|value| {
+                    let schema = schema.unwrap_string_schema();
+
+                    if let Err(e) = schema.check_constraints(value) {
+                        task_warn!(
+                            self.worker,
+                            "{userid}: ignoring attribute `{attribute}`: {e}"
+                        );
+
+                        None
+                    } else {
+                        Some(value)
+                    }
+                })
                 .cloned()
         };
 
         User {
-            userid,
+            userid: userid.clone(),
             comment: existing_user.as_ref().and_then(|u| u.comment.clone()),
             enable: existing_user
                 .and_then(|o| o.enable)
                 .or(Some(self.general_sync_settings.enable_new)),
             expire: existing_user.and_then(|u| u.expire).or(Some(0)),
-            firstname: lookup(self.ldap_sync_settings.firstname_attr.as_ref()).or_else(|| {
+            firstname: lookup(
+                "firstname",
+                self.ldap_sync_settings.firstname_attr.as_ref(),
+                FIRST_NAME_SCHEMA,
+            )
+            .or_else(|| {
                 if !self.general_sync_settings.should_remove_properties() {
                     existing_user.and_then(|o| o.firstname.clone())
                 } else {
                     None
                 }
             }),
-            lastname: lookup(self.ldap_sync_settings.lastname_attr.as_ref()).or_else(|| {
+            lastname: lookup(
+                "lastname",
+                self.ldap_sync_settings.lastname_attr.as_ref(),
+                LAST_NAME_SCHEMA,
+            )
+            .or_else(|| {
                 if !self.general_sync_settings.should_remove_properties() {
                     existing_user.and_then(|o| o.lastname.clone())
                 } else {
                     None
                 }
             }),
-            email: lookup(self.ldap_sync_settings.email_attr.as_ref()).or_else(|| {
+            email: lookup(
+                "email",
+                self.ldap_sync_settings.email_attr.as_ref(),
+                EMAIL_SCHEMA,
+            )
+            .or_else(|| {
                 if !self.general_sync_settings.should_remove_properties() {
                     existing_user.and_then(|o| o.email.clone())
                 } else {
@@ -304,7 +348,9 @@ impl LdapRealmSyncJob {
                     user_config.sections.remove(&tokenid_string);
 
                     if !self.dry_run {
-                        token_shadow::delete_secret(&tokenid)?;
+                        if let Err(e) = token_shadow::delete_secret(&tokenid) {
+                            task_warn!(self.worker, "could not delete token for user {userid}: {e}",)
+                        }
                     }
 
                     if self.general_sync_settings.should_remove_acls() {
-- 
2.30.2





^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints
  2023-02-13 14:31 [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints Lukas Wagner
@ 2023-02-13 16:32 ` Friedrich Weber
  2023-03-14  8:35 ` Lukas Wagner
  2023-03-27  9:52 ` [pbs-devel] applied: " Wolfgang Bumiller
  2 siblings, 0 replies; 4+ messages in thread
From: Friedrich Weber @ 2023-02-13 16:32 UTC (permalink / raw)
  To: Lukas Wagner; +Cc: pbs-devel

Quickly tested this, and it works nicely -- as in, the user is created 
but the invalid attribute value is ignored, all other users are created 
fully, and the sync job succeeds with a warning. Thanks!

Tested-by: Friedrich Weber <f.weber@proxmox.com>




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints
  2023-02-13 14:31 [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints Lukas Wagner
  2023-02-13 16:32 ` Friedrich Weber
@ 2023-03-14  8:35 ` Lukas Wagner
  2023-03-27  9:52 ` [pbs-devel] applied: " Wolfgang Bumiller
  2 siblings, 0 replies; 4+ messages in thread
From: Lukas Wagner @ 2023-03-14  8:35 UTC (permalink / raw)
  To: pbs-devel

On 2/13/23 15:31, Lukas Wagner wrote:
> Previously, if the value of a synced property did not validate properly
> (e.g only 1 character in length instead of the required 2), the whole
> sync job failed without any useful error message.
> 
> In this commit, the values are validated manually by their
> respective StringSchema. If the validation fails, the value is
> ignored and a warning is displayed in the task log.
> 
> In addition to that, some error messages have been improved.
> Also, user sync is now more fault-tolerant in general, showing
> warnings if something goes wrong while creating/updating a
> single user, instead of aborting the whole sync job.
> 
> Reported-by: Friedrich Weber <f.weber@proxmox.com>
> Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>

Ping. Would be nice to get this in for the next release, as it improves the behavior
for the already merged user sync code.

There are two more smallish follow-up patches [1, 2] on the list which I won't ping
separately, since they are only cleanup.

[1] https://lists.proxmox.com/pipermail/pbs-devel/2023-February/005940.html
[2] https://lists.proxmox.com/pipermail/pbs-devel/2023-February/005939.html

-- 
- Lukas




^ permalink raw reply	[flat|nested] 4+ messages in thread

* [pbs-devel] applied: [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints
  2023-02-13 14:31 [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints Lukas Wagner
  2023-02-13 16:32 ` Friedrich Weber
  2023-03-14  8:35 ` Lukas Wagner
@ 2023-03-27  9:52 ` Wolfgang Bumiller
  2 siblings, 0 replies; 4+ messages in thread
From: Wolfgang Bumiller @ 2023-03-27  9:52 UTC (permalink / raw)
  To: Lukas Wagner; +Cc: pbs-devel

applied with f.weber's Tested-by tag, thanks




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-03-27  9:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-13 14:31 [pbs-devel] [PATCH proxmox-backup] realm sync: show warnings if attributes do not meet their constraints Lukas Wagner
2023-02-13 16:32 ` Friedrich Weber
2023-03-14  8:35 ` Lukas Wagner
2023-03-27  9:52 ` [pbs-devel] applied: " Wolfgang Bumiller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal