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]