From b56968599037f402b0b4c040483bd67e61bf2429 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Sat, 28 Mar 2026 23:29:48 -0500 Subject: [PATCH] Add ldapservice 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 adds the PGLDAPSERVICE env var that provides an envvar interface to this functionality. Also the functionality has been moved to conninfo_add_defaults after review. Also 2 tests have been added. One to validate the env var functionality and one to validate that this parameter is ignored when used in pg_service.conf files. -- 0005 patch changes This patch changes the relevant naming from ldapservice to ldapserviceurl. I also add a comment above the new ldapservicelookup call that explains the reasoning for ignoring all non zero return codes. Also I increase the value of dispsize for ldapserviceurl from 20 to 64. It could be reasonable to increase it past 64, was originally thinking about bumping it to 1024 but I am not sure what these values are used for in the codebase and thought it was safer to just bump it to the currently existing max for any parameter. Moves the placement of ldapserviceurl to below the GSS options and adds a comment explaining that the parameter is exposed even in non LDAP builds. This was done to reflect similar comments in GSS/SSL, though this comment does not exist for the new OAUTH parameters so this may not have been a good choice. Also Add filename tags to filename reference in docs --- doc/src/sgml/libpq.sgml | 23 +++++++++++++++ src/interfaces/libpq/fe-connect.c | 24 +++++++++++++++ src/interfaces/libpq/libpq-int.h | 1 + .../t/003_ldap_connection_param_lookup.pl | 29 +++++++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 6db823808fc..0e4b7f81551 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2350,6 +2350,19 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + ldapserviceurl + + + This option specifies an LDAP query that can be used to reference connection parameters + stored on an LDAP server. Any connection parameter that is looked up in this way is + overridden by explicitly named connection parameters. This parameter is ignored when used + in a pg_service.conf file. This functionality is described in more + detail in . + + + + target_session_attrs @@ -9170,6 +9183,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) + + + + PGLDAPSERVICEURL + + PGLDAPSERVICEURL behaves the same as the + connection parameter. + + + diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index db9b4c8edbf..d076bfe7701 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -376,6 +376,15 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "GSS-delegation", "", 1, offsetof(struct pg_conn, gssdelegation)}, + /* + * As with SSL and GSS options, ldapserviceurl is exposed even in builds + * that do not have support + */ + {"ldapserviceurl", "PGLDAPSERVICEURL", NULL, NULL, + "Database-LDAP-Service", "", 64, + offsetof(struct pg_conn, pgldapserviceurl)}, + + {"replication", NULL, NULL, NULL, "Replication", "D", 5, offsetof(struct pg_conn, replication)}, @@ -6726,6 +6735,21 @@ conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) PQconninfoOption *sslmode_default = NULL, *sslrootcert = NULL; char *tmp; +#ifdef USE_LDAP + const char *ldapserviceurl = conninfo_getval(options, "ldapserviceurl"); + + if (ldapserviceurl == NULL) + ldapserviceurl = getenv("PGLDAPSERVICEURL"); + + if (ldapserviceurl != NULL) + + /* + * ldapServiceLookup has 4 potential return values. We only care here + * if it succeeded, if it failed we dont care why, return failure. + */ + if (ldapServiceLookup(ldapserviceurl, options, errorMessage) != 0) + return false; +#endif /* * If there's a service spec, use it to obtain any not-explicitly-given diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index bd7eb59f5f8..f8b10635d41 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -392,6 +392,7 @@ struct pg_conn char *pgservice; /* Postgres service, if any */ char *pgservicefile; /* path to a service file containing * service(s) */ + char *pgldapserviceurl; /* Postgres LDAP service URL, if any */ char *pguser; /* Postgres username and password, if any */ char *pgpass; char *pgpassfile; /* path to a file containing password(s) */ 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..f1c5cc85eb6 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] +ldapserviceurl=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,32 @@ local $ENV{PGSERVICEFILE} = "$srvfile_empty"; expected_stdout => qr/definition of service "undefined-service" not found/); + delete $ENV{PGSERVICE}; + + $dummy_node->connect_ok( + "ldapserviceurl=ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)", + 'connection with correct "ldapservice" string', + sql => "SELECT 'connect2_4'", + expected_stdout => qr/connect2_4/); + + $dummy_node->connect_ok( + "postgres://?ldapserviceurl=ldap%3A%2F%2Flocalhost%3A$ldap_port%2Fdc%3Dexample%2Cdc%3Dnet%3Fdescription%3Fone%3F%28cn%3Dmydatabase%29", + 'connection with correct "ldapserviceurl"', + sql => "SELECT 'connect2_5'", + expected_stdout => qr/connect2_5/); + + local $ENV{PGLDAPSERVICEURL} = "ldap://localhost:$ldap_port/dc=example,dc=net?description?one?(cn=mydatabase)"; + $dummy_node->connect_ok( + "", + 'connection with correct "ldapserviceurl" provided by env var', + sql => "SELECT 'connect2_6'", + expected_stdout => qr/connect2_6/); + delete $ENV{PGLDAPSERVICEURL}; + + $dummy_node->connect_fails( + '', + 'connection fails with ldapserviceurl specified in pg_service.conf file'); + # Remove default pg_service.conf. unlink($srvfile_default); } -- 2.51.2