From 5f9a720a526471286864d92559e6361460ca04cb Mon Sep 17 00:00:00 2001
From: Andrew Jackson <ajackson@drwholdings.com>
Date: Sat, 28 Mar 2026 23:29:48 -0500
Subject: [PATCH] Allow LDAP lookup from pgservice connection parameter

Currently there exists, only in pg_service.conf, the ability to look
up connection parameters from a centralized LDAP server. This patch
expands the usability of this be allowing it to be specified directly in
a connection string instead of only in a pg_service.conf file.

This patch adds a check in parseServiceInfo that checks if pgservice is
an LDAP scheme address and if so attempts to connect to that LDAP server
and grab connection parameters from there. This is a breaking change in
that it is possible that people previously named their pgservice after
an LDAP address.
---
 doc/src/sgml/libpq.sgml                       |  4 +++
 src/interfaces/libpq/fe-connect.c             |  5 ++++
 .../t/003_ldap_connection_param_lookup.pl     | 25 +++++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 6db823808fc..4d230a2a65f 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -2333,6 +2333,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
         name in <filename>pg_service.conf</filename> that holds additional connection parameters.
         This allows applications to specify only a service name so connection parameters
         can be centrally maintained. See <xref linkend="libpq-pgservice"/>.
+
+        You can also specify and LDAP address here which will look up parameters from an LDAP
+        server. See <xref linkend="libpq-ldap"/>. Please note that if an LDAP address is specified
+        no attempt will be made to look up parameters in <filename>pg_service.conf</filename>.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index db9b4c8edbf..50ada2939b6 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6006,6 +6006,11 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
 	if (service == NULL)
 		return 0;
 
+#ifdef USE_LDAP
+	if (pg_strncasecmp(service, LDAP_URL, strlen(LDAP_URL)) == 0)
+		return ldapServiceLookup(service, options, errorMessage);
+#endif
+
 	/*
 	 * First, try the "servicefile" option in connection string.  Then, try
 	 * the PGSERVICEFILE environment variable.  Finally, check
diff --git a/src/test/ldap/t/003_ldap_connection_param_lookup.pl b/src/test/ldap/t/003_ldap_connection_param_lookup.pl
index 359fc7a998a..67da90578cf 100644
--- a/src/test/ldap/t/003_ldap_connection_param_lookup.pl
+++ b/src/test/ldap/t/003_ldap_connection_param_lookup.pl
@@ -80,6 +80,9 @@ append_to_file(
 	$srvfile_valid, qq{
 [my_srv]
 ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)
+
+[my_srv_2]
+ldapservice=ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)
 });
 
 # File defined with no contents, used as default value for
@@ -196,6 +199,28 @@ local $ENV{PGSERVICEFILE} = "$srvfile_empty";
 		expected_stdout =>
 		  qr/definition of service "undefined-service" not found/);
 
+	delete $ENV{PGSERVICE};
+
+	$dummy_node->connect_ok(
+		"service=ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)",
+		'connection with correct "service" string populated with LDAP address',
+		sql => "SELECT 'connect2_4'",
+		expected_stdout => qr/connect2_4/);
+
+	$dummy_node->connect_ok(
+		"postgres://?service=ldap%3A%2F%2Flocalhost%3A$ldap_port%2Fdc%3Dexample%2Cdc%3Dnet%3Fdescription%3Fone%3F%28cn%3Dmydatabase%29",
+		'connection with correct "ldapservice" string populated with LDAP address',
+		sql => "SELECT 'connect2_5'",
+		expected_stdout => qr/connect2_5/);
+
+	local $ENV{PGSERVICE} = "ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)";
+	$dummy_node->connect_ok(
+		"",
+		'connection with correct "service" provided by env var populated with LDAP address',
+		sql => "SELECT 'connect2_6'",
+		expected_stdout => qr/connect2_6/);
+	delete $ENV{PGLDAPSERVICE};
+
 	# Remove default pg_service.conf.
 	unlink($srvfile_default);
 }
-- 
2.51.2

