public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH yew-comp 4/5] auth_edit_ldap: add helpers to properly edit ad & ldap realms
Date: Tue, 16 Sep 2025 16:48:21 +0200	[thread overview]
Message-ID: <20250916144827.551806-6-s.sterz@proxmox.com> (raw)
In-Reply-To: <20250916144827.551806-1-s.sterz@proxmox.com>

previously this view would run into issues when editing more complex
ldap and active directory realms. specifically:

- when editing a pre-existing realm and not opening the second tab of
the edit window, all attributes that would are configured through the
second tab would be removed. values for those fields would also not be
correctly loaded when opening that second tab. this issue stems from
how `FormContext` works and it requires rendering all tabs before
loading the form. fixed by specifying `force_render_all(true)` on the
TabPanel in the form

- properties specified via property strings (`sync-attributes` and
`sync-default-options`) where not properly formatted when submitting
them to the api, leading to errors warning about additional unknown
parameters. fixed by parsing the form and properly formatting the two
parameters.

- properties specified via property strings would not be correctly
loaded into the form as they weren't returned by the api in a way that
is compatible with how EditWindow's loader works. fixed by
implementing a loader that would properly parse these strings and
adapting them to the expected format.

- removing the last setting from the `sync-attributes` or
`sync-defaults-options` property strings would not get properly
removed as these two were missing from the appropriate
`delete_empty_values()` call.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 src/auth_edit_ldap.rs | 108 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 3 deletions(-)

diff --git a/src/auth_edit_ldap.rs b/src/auth_edit_ldap.rs
index 162f828..70fb638 100644
--- a/src/auth_edit_ldap.rs
+++ b/src/auth_edit_ldap.rs
@@ -1,9 +1,11 @@
 use std::rc::Rc;
 
 use anyhow::Error;
+use proxmox_client::ApiResponseData;
 use pwt::css::{Flex, Overflow};
 
 use pwt::widget::form::{Checkbox, Combobox, FormContext, InputType, Number};
+use serde_json::Value;
 use yew::html::{IntoEventCallback, IntoPropValue};
 use yew::virtual_dom::{VComp, VNode};
 
@@ -53,13 +55,109 @@ impl AuthEditLDAP {
     }
 }
 
+async fn load_realm(url: impl Into<String>) -> Result<ApiResponseData<Value>, Error> {
+    let mut response: ApiResponseData<Value> = crate::http_get_full(url, None).await?;
+
+    response.data["anonymous_search"] = Value::Bool(!response.data["bind-dn"].is_string());
+
+    if let Value::String(sync_default_options) = response.data["sync-defaults-options"].take() {
+        let split = sync_default_options.split(",");
+
+        for part in split {
+            let mut part = part.split("=");
+
+            match part.next() {
+                Some("enable-new") => {
+                    response.data["enable-new"] = Value::Bool(part.next() == Some("true"))
+                }
+                Some("remove-vanished") => {
+                    if let Some(part) = part.next() {
+                        for vanished_opt in part.split(";") {
+                            response.data[&format!("remove-vanished-{vanished_opt}")] =
+                                Value::Bool(true)
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+
+    if let Value::String(sync_attributes) = response.data["sync-attributes"].take() {
+        let split = sync_attributes.split(",");
+
+        for opt in split {
+            let mut opt = opt.split("=");
+            if let (Some(name), Some(val)) = (opt.next(), opt.next()) {
+                response.data[name] = Value::String(val.to_string());
+            }
+        }
+    }
+
+    Ok(response)
+}
+
+fn format_sync_and_default_options(data: &mut Value) -> Value {
+    let mut sync_default_options: Option<String> = None;
+
+    if let Value::Bool(val) = data["enable-new"].take() {
+        sync_default_options = Some(format!("enable-new={val}"))
+    }
+
+    let mut remove_vanished: Vec<&str> = Vec::new();
+
+    for prop in ["acl", "entry", "properties"] {
+        let prop_name = format!("remove-vanished-{prop}");
+        if data[&prop_name].take() == Value::Bool(true) {
+            remove_vanished.push(prop);
+        }
+    }
+
+    if !remove_vanished.is_empty() {
+        let vanished = format!("remove-vanished={}", remove_vanished.join(";"));
+
+        sync_default_options = sync_default_options
+            .map(|f| format!("{f},{vanished}"))
+            .or(Some(vanished));
+    }
+
+    if let Some(defaults) = sync_default_options {
+        data["sync-defaults-options"] = Value::String(defaults);
+    }
+
+    let mut sync_attributes = Vec::new();
+
+    for attribute in ["firstname", "lastname", "email"] {
+        if let Value::String(val) = &data[attribute].take() {
+            sync_attributes.push(format!("{attribute}={val}"));
+        }
+    }
+
+    if !sync_attributes.is_empty() {
+        data["sync-attributes"] = Value::String(sync_attributes.join(","));
+    }
+
+    let mut new = serde_json::json!({});
+
+    for (param, v) in data.as_object().unwrap().iter() {
+        if !v.is_null() {
+            new[param] = v.clone();
+        }
+    }
+
+    new
+}
+
 async fn create_item(form_ctx: FormContext, base_url: String) -> Result<(), Error> {
-    let data = form_ctx.get_submit_data();
+    let mut data = form_ctx.get_submit_data();
+    let data = format_sync_and_default_options(&mut data);
     crate::http_post(base_url, Some(data)).await
 }
 
 async fn update_item(form_ctx: FormContext, base_url: String) -> Result<(), Error> {
-    let data = form_ctx.get_submit_data();
+    let mut data = form_ctx.get_submit_data();
+
+    let data = format_sync_and_default_options(&mut data);
 
     let data = delete_empty_values(
         &data,
@@ -71,6 +169,8 @@ async fn update_item(form_ctx: FormContext, base_url: String) -> Result<(), Erro
             "comment",
             "user-classes",
             "filter",
+            "sync-attributes",
+            "sync-defaults-options",
         ],
         true,
     );
@@ -96,6 +196,7 @@ fn render_panel(form_ctx: FormContext, props: AuthEditLDAP) -> Html {
             TabBarItem::new().key("sync").label(tr!("Sync Options")),
             render_sync_form(form_ctx.clone(), props.clone()),
         )
+        .force_render_all(true)
         .into()
 }
 
@@ -301,7 +402,8 @@ impl Component for ProxmoxAuthEditLDAP {
                 props
                     .realm
                     .as_ref()
-                    .map(|realm| format!("{}/{}", props.base_url, percent_encode_component(realm))),
+                    .map(|realm| format!("{}/{}", props.base_url, percent_encode_component(realm)))
+                    .map(|url| move || load_realm(url.clone())),
             )
             .renderer({
                 let props = props.clone();
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


  parent reply	other threads:[~2025-09-16 14:48 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-16 14:48 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 00/11] Add LDAP and AD realm support to Proxmox Datacenter Manager Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH proxmox 1/1] ldap: add types and sync features Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH yew-comp 1/5] auth_view: add default column and allow setting ldap realms as default Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH yew-comp 2/5] utils: add pdm realm to `get_auth_domain_info` Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH yew-comp 3/5] auth_view/auth_edit_ldap: add support for active directory realms Shannon Sterz
2025-09-16 14:48 ` Shannon Sterz [this message]
2025-09-16 14:48 ` [pdm-devel] [PATCH yew-comp 5/5] auth_view: implement syncing ldap and ad realms Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH datacenter-manager 1/5] config: add domain config plugins for " Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH datacenter-manager 2/5] server: add ldap and active directory authenticators Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH datacenter-manager 3/5] server: api: add api endpoints for configuring ldap & ad realms Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH datacenter-manager 4/5] api/auth: add endpoint to start ldap sync jobs Shannon Sterz
2025-09-16 14:48 ` [pdm-devel] [PATCH datacenter-manager 5/5] ui: add a panel to allow handling realms Shannon Sterz
2025-09-19 10:02 ` [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 00/11] Add LDAP and AD realm support to Proxmox Datacenter Manager Christoph Heiss

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250916144827.551806-6-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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