Subject: Re: [PoC] Federated Authn/z with OAUTHBEARER

From: Wolfgang Walther <[email-masked]>
Date: Fri, 11 Apr 2025 18:21:14 +0200

Jacob Champion:
> On Wed, Apr 9, 2025 at 4:42 PM Jelte Fennema-Nio <[email-masked]> wrote:
>> I think your suggestion of not using any .so files would best there (from w user perspective). I'd be quite surprised if a static build still resulted in me having to manage shared library files anyway.
> Done this way in v5. I had planned to separate the implementations by
> a #define, but I ran into issues with Makefile.shlib, so I split the
> shared and dynamic versions into separate files. I just now realized
> that we do something about this exact problem in src/common, so I'll
> see if I can copy its technique for the next go round.

I tried to apply this patch to nixpkgs' libpq build [1]. First, I pinned 
a recent commit from master (one where the v5 patch will apply cleanly 
later) and enabled --with-libcurl [2].

At this stage, without the patch applied, I observe the following:

1. The default, dynamically linked, build succeeds and libpq.so is 
linked to libcurl.so as expected!

2. The statically linked build fails during configure:

   checking for curl_multi_init in -lcurl... no
   configure: error: library 'curl' does not provide curl_multi_init

config.log tells me that it can't link to libcurl, because of undefined 
references, for example:

   undefined reference to `psl_is_cookie_domain_acceptable'
   undefined reference to `nghttp2_session_check_request_allowed'

I assume the many libs listed in Libs.private in libcurl.pc are not 
added automatically for this check?

Next, I applied the v5 patch and:

3. Running the same build as in step 1 above (dynamically linked), I can 
see that libpq.so does have some reference to dlopen / libpq-oauth in it 
- good. But libpq-oauth.so itself is not built. The commands I am using 
to build just the libpq package are essentially like this:

   make submake-libpgport
   make submake-libpq
   make -C src/bin/pg_config install
   make -C src/common install
   make -C src/include install
   make -C src/interfaces/libpq install
   make -C src/port install

I tried adding "make submake-libpq-oauth", but that doesn't exist.

When I do "make -C src/interfaces/libpq-oauth", I get this error:

   make: *** No rule to make target 'oauth-curl.o', needed by 
'libpq-oauth-18.so'.  Stop.

Not sure how to proceed to build libpq-oauth.so.

4. The statically linked build fails with the same configure error as above.

I can only test autoconf right now, not meson - don't have a working 
setup for that, yet.

Best,

Wolfgang

[1]: 
https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/sql/postgresql/libpq.nix

---

From: Jacob Champion <[email-masked]>
Date: Mon, 14 Apr 2025 09:12:53 -0700

> later) and enabled --with-libcurl [2].

(The [2] link is missing, I think.)

> 2. The statically linked build fails during configure:

I'm confused by this -- the build produces staticlibs alongside the
dynamically linked ones, so that's what I've been testing against.
What different options do you pass to configure for a "statically
linked build"?

> added automatically for this check?

Not unless there is some magic in PKG_CHECK_MODULES I've never heard
of (which is entirely possible!). Furthermore I imagine that the
transitive dependencies of all its dependencies are not added either.

Does your build method currently work for dependency forests like
libgssapi_krb5 and libldap? (I want to make sure I'm not accidentally
doing less work than we currently support for those other deps, but
I'm also not planning to add more feature work as part of this
particular open item.)

> I tried adding "make submake-libpq-oauth", but that doesn't exist.

There is no submake for this because no other targets depend on it.
Currently I don't have any plans to add one (but -C should work).

> 'libpq-oauth-18.so'.  Stop.

I cannot reproduce this. The CI seems happy, too. Is this patch the
only modification you've made to our build system, or are there more
changes?

I'm about to rewrite this part somewhat, so a deep dive may not be very helpful.

Thanks,
--Jacob

---

From: Wolfgang Walther <[email-masked]>
Date: Mon, 14 Apr 2025 19:09:55 +0200

> (The [2] link is missing, I think.)

Ah, sry. This is the link:

https://github.com/wolfgangwalther/nixpkgs/commits/postgresql-libpq-curl/

It's the last two commits on that branch.

> What different options do you pass to configure for a "statically

It's not so much the options, but more that for this build there are no 
shared libs available at buildtime at all. You can consider it a "fully 
static system". So in your case, you'd always do the configure test with 
shared libs, but I can't.

The build system passes --enable-static and --disable-shared to 
configure, but both of those are ignored by configure, as indicated by a 
WARNING immediately.

>> transitive dependencies of all its dependencies are not added either.

IIUC, the transitive dependencies would be part of libcurl's 
Libs.private / Requires.private (assuming that file is correctly 
created). So that would be taken care of, I guess.

> I'm also not planning to add more feature work as part of this

We currently build libpq with neither libldap, nor libkrb5, at least for 
the static case. But I just tried on the bigger postgresql package and 
force-enabled libldap there for the static build - it fails in exactly 
the same way.

So yes, not related to your patch. I do understand that PostgreSQL's 
autoconf build system is not designed for "static only", I am certainly 
not expecting you to fix that.

I think meson will do better here, but I was not able to make that work, 
yet.

> only modification you've made to our build system, or are there more

We apply another patch to change the default socket directory to /run, 
but that's certainly unrelated. All the other custom stuff only kicks in 
afterwards, in the installPhase, so unrelated as well.

I just tried the same thing on the bigger postgresql package, where the 
full build is run and not only libpq / libpq-oauth. It fails with the 
same error. No rule for oauth-curl.o.

> I'm about to rewrite this part somewhat, so a deep dive may not be very helpful.

OK. I will try to get meson running, at least enough to try this patch 
again. Maybe that gives better results.

Thanks,

Wolfgang

---

From: Wolfgang Walther <[email-masked]>
Date: Mon, 14 Apr 2025 20:27:46 +0200

> I think meson will do better here, but I was not able to make that work,
I did a basic meson build. Full postgresql package, not libpq-only.

The static-only build just works. On master that is. Same as the regular 
build.

So yes, meson will handle the static stuff much better.

 > same error. No rule for oauth-curl.o.
Applying the v5 patch to the above meson build, will give me a different 
error. This time for both the static-only and the regular build:

   src/interfaces/libpq-oauth/meson.build:18:22: ERROR: File 
oauth-curl.c does not exist.

This.. clears it up, because that file is indeed missing for me on disk. 
I assume that's because this file is tracked as a rename in the v5 
patch. I can apply this with git, but not directly in the nix build 
system. TIL, I need to use "fetchpatch2" instead of "fetchpatch" for 
that. Sure thing.

So, with the patch applied correctly, I get the following:

1. Meson regular build:

libpq-oauth-18.so
libpq.so
libpq.so.5
libpq.so.5.18

The libpq.so file has references to dlopen and libpq-auth-18.so, cool.

2. Meson static-only build:

libpq.a
libpq-oauth-18.a

The libpq.a file has no references to dlopen, but plenty of references 
to curl stuff.

I'm not sure what the libpq-oauth-18.a file is for.

3. Back to the lipq-only build with autoconf, from where I started. I 
only need to add the following line:

make -C src/interfaces/libpq-oauth install

and get this:

libpq-oauth-18.so
libpq.so
libpq.so.5
libpq.so.5.18

Sweet!

4. Of course the static-only build does not work with autoconf, but 
that's expected.

So, sorry for the noise before. Now, that I know how to apply patches 
with renames, I will try your next patch as well.

Best,

Wolfgang

---

From: Jacob Champion <[email-masked]>
Date: Mon, 14 Apr 2025 12:14:20 -0700

> This.. clears it up, because that file is indeed missing for me on disk.

Aha! Okay, glad I don't need to track that down.

> The libpq.a file has no references to dlopen, but plenty of references

Which references? libpq-oauth should be the only thing using Curl symbols:

    $ nm src/interfaces/libpq/libpq.a | grep --count curl
    0
    $ nm src/interfaces/libpq-oauth/libpq-oauth-18.a | grep --count curl
    116

> I'm not sure what the libpq-oauth-18.a file is for.

That implements the flow. You'll need to link that into your
application or it will complain about missing flow symbols. (I don't
think there's an easy way to combine the two libraries in our Autoconf
setup; the only ways I can think of right now would introduce a
circular dependency between libpq and libpq-oauth...)

Thanks!
--Jacob

---

From: Wolfgang Walther <[email-masked]>
Date: Mon, 14 Apr 2025 21:46:29 +0200

>      $ nm src/interfaces/libpq-oauth/libpq-oauth-18.a | grep --count curl

Not sure what I was looking at earlier, probably too many different 
builds at the same time. Now I can't find the curl symbols in libpq.a 
either...

> circular dependency between libpq and libpq-oauth...)

... which immediately explains what the libpq-oauth-18.a file is for, yes.

But that means we'd need a -lpq-oauth-18 or something like that in 
Libs.private in libpq.pc, right?

This seems to be missing, I checked both the autoconf and meson builds.

Best,

Wolfgang

---

From: Jacob Champion <[email-masked]>
Date: Mon, 14 Apr 2025 13:17:13 -0700

> Libs.private in libpq.pc, right?

I believe so. I'm in the middle of the .pc stuff right now; v6 should
have the fixes as long as I don't get stuck.

Thanks,
--Jacob

---

From: Jacob Champion <[email-masked]>
Date: Mon, 14 Apr 2025 17:13:35 -0700

> have the fixes as long as I don't get stuck.

Done in v6-0001. I think this is now architecturally complete, so if
reviewers are happy I can work on docs and the commit message. As a
summary:

- We provide a libpq-oauth-18.so module for shared builds, and a
corresponding .a for static builds, when OAuth is enabled.
- Platforms which cannot support the builtin flow now error out if you
request OAuth at configure time.
- When OAuth is enabled and there's no custom client flow, libpq.so
loads the module via dlopen(), which respects RPATH/LD_LIBRARY_PATH et
al. If it's not installed, OAuth doesn't continue.
- Static builds must link libpq-oauth-18.a explicitly. libpq.pc now
puts -lpq-oauth-18 in Libs.private, and libcurl in Requires.private.
- Internally, we compile separate versions of fe-auth-oauth.c to
handle the different cases (disabled, dynamic, static). This is
borrowed from src/common.
- The only new export from libpq is appendPQExpBufferVA. Other
internal symbols are shared with libpq-oauth via dependency injection.

v6-0002 is a WIP rename of the --with-libcurl option to
--with-oauth-client. I'm not sure I have all of the Meson corner cases
with auto_features figured out, but maybe it doesn't matter since it's
temporary (it targets a total of seven buildfarm animals, and once
they've switched we can remove the old name). I have added a separate
open item for this.

Thanks,
--Jacob