From 0020d2027b581e6bdfc5b78785a9b9171b7f7ef2 Mon Sep 17 00:00:00 2001 From: Andrew Jackson 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. v0002 patch This patch Removes all backwards compatibility issues. Now if the LDAP URL was specified in pg_service.conf then the values from pg_service.conf will be used and the LDAP lookup will not be performed. Cool --- doc/src/sgml/libpq.sgml | 6 +++ src/interfaces/libpq/fe-connect.c | 5 ++ .../t/003_ldap_connection_param_lookup.pl | 48 +++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 6db823808fc..88a5db2388d 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2333,6 +2333,12 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname name in pg_service.conf that holds additional connection parameters. This allows applications to specify only a service name so connection parameters can be centrally maintained. See . + + You can also specify an LDAP URL here which will look up connection parameters from an + LDAP server. See . Please note that if the LDAP URL + specified here exists as a service name in pg_service.conf, then + the pg_service.conf values will be used instead and no LDAP lookup + will be performed. diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index db9b4c8edbf..b12b9bceb12 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -6048,6 +6048,11 @@ next_file: last_file: if (!group_found) { +#ifdef USE_LDAP + if (strncmp(service, "ldap", 4) == 0) + /* if error ignore ldapServiceLookup return value, just return 3 */ + return ldapServiceLookup(service, options, errorMessage) ? 3 : 0; +#endif libpq_append_error(errorMessage, "definition of service \"%s\" not found", service); return 3; } 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..976c196df8c 100644 --- a/src/test/ldap/t/003_ldap_connection_param_lookup.pl +++ b/src/test/ldap/t/003_ldap_connection_param_lookup.pl @@ -62,6 +62,20 @@ description:port=} . $node->port . qq{ $ldap->ldapadd_file($ldif_valid); +my $ldif_valid_invalid = "$td/connection_params_ldif_valid_invalid.ldif"; +append_to_file( + $ldif_valid_invalid , qq{ +version:1 +dn:cn=mydatabasefoundinpgservice,dc=example,dc=net +changetype:add +objectclass:top +objectclass:device +cn:mydatabasefoundinpgservice +description:host=} . $node->host . qq{ +description:port=} . $node->port . qq{ +}); +$ldap->ldapadd_file($ldif_valid_invalid); + my ($ldap_server, $ldap_port, $ldaps_port, $ldap_url, $ldaps_url, $ldap_basedn, $ldap_rootdn ) = $ldap->prop(qw(server port s_port url s_url basedn rootdn)); @@ -80,6 +94,9 @@ append_to_file( $srvfile_valid, qq{ [my_srv] ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase) + +[ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabasefoundinpgservice)] +port=1234 }); # File defined with no contents, used as default value for @@ -196,6 +213,37 @@ 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}; + + # Below test should fail because the service value is defined as a literal service in pg_service.conf. + # The pg_service.conf entry should have an incorrect port and LDAP should not be looked up after reading + # the incorrect port + $dummy_node->connect_fails( + 'service=ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabasefoundinpgservice)"', + 'connection using cn=mydatabasefoundinpgservice', + expected_stdout => + qr/definition of service "undefined-service" not found/); + # Remove default pg_service.conf. unlink($srvfile_default); } -- 2.51.2