This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 3a5d95d  Refactor the example LDAP code
3a5d95d is described below

commit 3a5d95d798c46d52836e993e1ead17c55118255a
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed May 21 15:14:21 2025 +0100

    Refactor the example LDAP code
---
 atr/blueprints/admin/admin.py                   | 151 +++++++++++++-----------
 atr/blueprints/admin/templates/ldap-lookup.html |  16 +--
 2 files changed, 91 insertions(+), 76 deletions(-)

diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index 839c625..65ebcc2 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -15,7 +15,9 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import asyncio
 import collections
+import dataclasses
 import logging
 import os
 import pathlib
@@ -76,6 +78,20 @@ class LdapLookupForm(util.QuartFormTyped):
     submit = wtforms.SubmitField("Lookup")
 
 
+# We use a dataclass to support ldap3.Connection objects
[email protected]
+class LdapSearchParams:
+    uid_query: str | None = None
+    email_query: str | None = None
+    bind_dn_from_config: str | None = None
+    bind_password_from_config: str | None = None
+    results_list: list[dict[str, str | list[str]]] = 
dataclasses.field(default_factory=list)
+    err_msg: str | None = None
+    srv_info: str | None = None
+    detail_err: str | None = None
+    connection: ldap3.Connection | None = None
+
+
 @admin.BLUEPRINT.route("/data")
 @admin.BLUEPRINT.route("/data/<model>")
 async def admin_data(model: str = "Committee") -> str:
@@ -343,10 +359,6 @@ async def admin_toggle_view() -> response.Response:
 @admin.BLUEPRINT.route("/ldap/", methods=["GET"])
 async def ldap() -> str:
     form = await LdapLookupForm.create_form(data=quart.request.args)
-    results: list[dict[str, str | list[str]]] = []
-    error_message: str | None = None
-    server_info_for_debug: str | None = None
-    detailed_error_info: str | None = None
     asf_id_for_template: str | None = None
 
     web_session = await asfquart.session.read()
@@ -356,89 +368,92 @@ async def ldap() -> str:
     uid_query = form.uid.data
     email_query = form.email.data
 
-    ldap_querying: bool = bool((quart.request.method == "GET") and (uid_query 
or email_query))
-    if ldap_querying:
+    ldap_params: LdapSearchParams | None = None
+    if (quart.request.method == "GET") and (uid_query or email_query):
         bind_dn = quart.current_app.config.get("LDAP_BIND_DN")
         bind_password = quart.current_app.config.get("LDAP_BIND_PASSWORD")
 
-        results, error_message, server_info_for_debug, detailed_error_info = 
await _ldap_lookup_perform_search(
-            uid_query, email_query, bind_dn, bind_password
+        ldap_params = LdapSearchParams(
+            uid_query=uid_query,
+            email_query=email_query,
+            bind_dn_from_config=bind_dn,
+            bind_password_from_config=bind_password,
         )
+        await asyncio.to_thread(_ldap_lookup_perform_search, ldap_params)
 
     return await quart.render_template(
         "ldap-lookup.html",
         form=form,
-        results=results,
-        error_message=error_message,
+        ldap_params=ldap_params,
         asf_id=asf_id_for_template,
-        ldap_query_performed=ldap_querying,
-        server_info_for_debug=server_info_for_debug,
-        detailed_error_info=detailed_error_info,
+        ldap_query_performed=ldap_params is not None,
     )
 
 
-async def _ldap_lookup_perform_search(
-    uid_query: str | None,
-    email_query: str | None,
-    bind_dn_from_config: str | None,
-    bind_password_from_config: str | None,
-) -> tuple[list[dict[str, str | list[str]]], str | None, str | None, str | 
None]:
-    results_list: list[dict[str, str | list[str]]] = []
-    err_msg: str | None = None
-    srv_info: str | None = None
-    detail_err: str | None = None
-
+def _ldap_lookup_perform_search(params: LdapSearchParams) -> None:
     try:
-        server = ldap3.Server(LDAP_SERVER_HOST, use_ssl=True, 
get_info=ldap3.ALL)
-        srv_info = repr(server)
+        _ldap_lookup_perform_search_inner(params)
+    except Exception as e:
+        params.err_msg = f"An unexpected error occurred: {e!s}"
+        params.detail_err = f"Details: {e.args}"
+    finally:
+        if params.connection and params.connection.bound:
+            try:
+                params.connection.unbind()
+            except Exception:
+                ...
 
-        if bind_dn_from_config and bind_password_from_config:
-            conn = ldap3.Connection(
-                server, user=bind_dn_from_config, 
password=bind_password_from_config, auto_bind=True
-            )
-        else:
-            conn = ldap3.Connection(server, auto_bind=True)
 
-        filters: list[str] = []
-        if uid_query:
-            filters.append(f"(uid={conv.escape_filter_chars(uid_query)})")
+def _ldap_lookup_perform_search_inner(params: LdapSearchParams) -> None:
+    params.results_list = []
+    params.err_msg = None
+    params.srv_info = None
+    params.detail_err = None
+    params.connection = None
 
-        if email_query:
-            escaped_email = conv.escape_filter_chars(email_query)
-            if email_query.endswith("@apache.org"):
-                filters.append(f"(mail={escaped_email})")
-            else:
-                filters.append(f"(asf-altEmail={escaped_email})")
+    server = ldap3.Server(LDAP_SERVER_HOST, use_ssl=True, get_info=ldap3.ALL)
+    params.srv_info = repr(server)
+
+    if params.bind_dn_from_config and params.bind_password_from_config:
+        params.connection = ldap3.Connection(
+            server, user=params.bind_dn_from_config, 
password=params.bind_password_from_config, auto_bind=True
+        )
+    else:
+        params.connection = ldap3.Connection(server, auto_bind=True)
+
+    filters: list[str] = []
+    if params.uid_query:
+        filters.append(f"(uid={conv.escape_filter_chars(params.uid_query)})")
 
-        if not filters:
-            err_msg = "Please provide a UID or an email address to search."
+    if params.email_query:
+        escaped_email = conv.escape_filter_chars(params.email_query)
+        if params.email_query.endswith("@apache.org"):
+            filters.append(f"(mail={escaped_email})")
         else:
-            search_filter = f"(&{''.join(filters)})" if (len(filters) > 1) 
else filters[0]
-            conn.search(
-                search_base=LDAP_SEARCH_BASE,
-                search_filter=search_filter,
-                attributes=LDAP_ATTRIBUTES,
-            )
-            for entry in conn.entries:
-                result_item: dict[str, str | list[str]] = {"dn": 
entry.entry_dn}
-                result_item.update(entry.entry_attributes_as_dict)
-                results_list.append(result_item)
-
-            if (not results_list) and (not err_msg):
-                err_msg = "No results found for the given criteria."
-        if conn.bound:
-            conn.unbind()
-    # except exceptions.LDAPSocketOpenError as e:
-    #     err_msg = f"LDAP Socket Open Error: {e!s}"
-    #     detail_err = f"Details: {e.args}"
-    # except exceptions.LDAPException as e:
-    #     err_msg = f"LDAP Error: {e!s}"
-    #     detail_err = f"Details: {e.args}"
-    except Exception as e:
-        err_msg = f"An unexpected error occurred: {e!s}"
-        detail_err = f"Details: {e.args}"
+            filters.append(f"(asf-altEmail={escaped_email})")
+
+    if not filters:
+        params.err_msg = "Please provide a UID or an email address to search."
+        return
+
+    search_filter = f"(&{''.join(filters)})" if (len(filters) > 1) else 
filters[0]
+
+    if not params.connection:
+        params.err_msg = "LDAP Connection object not established or auto_bind 
failed."
+        return
+
+    params.connection.search(
+        search_base=LDAP_SEARCH_BASE,
+        search_filter=search_filter,
+        attributes=LDAP_ATTRIBUTES,
+    )
+    for entry in params.connection.entries:
+        result_item: dict[str, str | list[str]] = {"dn": entry.entry_dn}
+        result_item.update(entry.entry_attributes_as_dict)
+        params.results_list.append(result_item)
 
-    return results_list, err_msg, srv_info, detail_err
+    if (not params.results_list) and (not params.err_msg):
+        params.err_msg = "No results found for the given criteria."
 
 
 
@admin.BLUEPRINT.route("/ongoing-tasks/<project_name>/<version_name>/<revision>")
diff --git a/atr/blueprints/admin/templates/ldap-lookup.html 
b/atr/blueprints/admin/templates/ldap-lookup.html
index a7e2813..f51c401 100644
--- a/atr/blueprints/admin/templates/ldap-lookup.html
+++ b/atr/blueprints/admin/templates/ldap-lookup.html
@@ -40,19 +40,19 @@
         <h5 class="mb-0">Lookup results</h5>
       </div>
       <div class="card-body">
-        {% if error_message %}
+        {% if ldap_params and ldap_params.err_msg %}
           <div class="alert alert-danger" role="alert">
-            <p class="fw-bold">{{ error_message }}</p>
-            {% if server_info_for_debug %}
+            <p class="fw-bold">{{ ldap_params.err_msg }}</p>
+            {% if ldap_params.srv_info %}
               <p class="mb-1">Attempted server configuration:</p>
-              <pre class="small bg-light p-2 rounded"><code>{{ 
server_info_for_debug }}</code></pre>
+              <pre class="small bg-light p-2 rounded"><code>{{ 
ldap_params.srv_info }}</code></pre>
             {% endif %}
-            {% if detailed_error_info %}
+            {% if ldap_params.detail_err %}
               <p class="mb-1 mt-2">Detailed error information:</p>
-              <pre class="small bg-light p-2 rounded"><code>{{ 
detailed_error_info }}</code></pre>
+              <pre class="small bg-light p-2 rounded"><code>{{ 
ldap_params.detail_err }}</code></pre>
             {% endif %}
           </div>
-        {% elif results %}
+        {% elif ldap_params and ldap_params.results_list %}
           <table class="table table-striped table-hover">
             <thead>
               <tr>
@@ -65,7 +65,7 @@
               </tr>
             </thead>
             <tbody>
-              {% for result in results %}
+              {% for result in ldap_params.results_list %}
                 <tr>
                   <td>{{ result.get('dn', 'N/A') }}</td>
                   <td>{{ result.get('uid', ['N/A'])[0] }}</td>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to