Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teach pgBouncer to do auth_query for users defined without a password. #1039

Closed
wants to merge 20 commits into from

Conversation

benchub
Copy link
Contributor

@benchub benchub commented Mar 13, 2024

As described in #484, if a user is defined in the [users] section of
the config file (perhaps to take advantage of per-user overrides)
but then that user is not defined in auth_file, pgBouncer currently
gets confused when trying to check their password. It sees the user
exists, but fails to notice a password was never defined, resulting
in no running of auth_query.

Add a test case to catch this. The case successfully fails before
this patchset and succeeds after it.

Fixes #484
Fixes #706

Ben Chobot and others added 11 commits March 8, 2024 15:24
As described in pgbouncer#484, if a user is defined in the [users] section of
the config file (perhaps to take advantage of per-user overrides)
but then that user is *not* defined in auth_file, pgBouncer currently
gets confused when trying to check their password. It sees the user
exists, but fails to notice a password was never defined, resulting
in no running of auth_query.
As described in pgbouncer#484, if a user is defined in the [users] section of
the config file (perhaps to take advantage of per-user overrides)
but then that user is *not* defined in auth_file, pgBouncer currently
gets confused when trying to check their password. It sees the user
exists, but fails to notice a password was never defined, resulting
in no running of auth_query.

Add a test case to catch this. The case successfully fails before
this patchset and succeeds after it.
As described in pgbouncer#484, if a user is defined in the [users] section of
the config file (perhaps to take advantage of per-user overrides)
but then that user is *not* defined in auth_file, pgBouncer currently
gets confused when trying to check their password. It sees the user
exists, but fails to notice a password was never defined, resulting
in no running of auth_query.

Add a test case to catch this. The case successfully fails before
this patchset and succeeds after it.
As described in pgbouncer#484, if a user is defined in the [users] section of
the config file (perhaps to take advantage of per-user overrides)
but then that user is *not* defined in auth_file, pgBouncer currently
gets confused when trying to check their password. It sees the user
exists, but fails to notice a password was never defined, resulting
in no running of auth_query.t

Add a test case to catch this. The case successfully fails before
this patchset and succeeds after it.
@benchub
Copy link
Contributor Author

benchub commented Mar 13, 2024

I'm not really sure what's going on with these tests, and I think it's clear I'm flailing around more than enough on github. However, this really does seem to address an outstanding bug with auth_query and configured users.

src/loader.c Outdated Show resolved Hide resolved
src/loader.c Show resolved Hide resolved
JelteF added a commit to JelteF/pgbouncer that referenced this pull request Mar 13, 2024
While reviewing pgbouncer#1039 I had a hard time max_user_connections seeing if
max_user_connections was applied correctly because `SHOW USERS` didn't
list it. This addresses that by adding a `max_user_connections` and
`current_connections` column to the output of `SHOW USERS`.
Copy link
Member

@JelteF JelteF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this! This is indeed quite an annoying bug. I think overall direction is good, but I think we should go a bit further with the change because I dislike the cf_user checks that now proliferate the codebase.

Also, I just created while reviewing this PR #1040 I'd appreciate it if you could take a look at that and let me know if you think that change makes sense.

src/objects.c Outdated Show resolved Hide resolved
JelteF added a commit to JelteF/pgbouncer that referenced this pull request Mar 13, 2024
While reviewing pgbouncer#1039 I had a hard time max_user_connections seeing if
max_user_connections was applied correctly because `SHOW USERS` didn't
list it. This addresses that by adding a `max_user_connections` and
`current_connections` column to the output of `SHOW USERS`.
Ben Chobot and others added 3 commits March 13, 2024 11:33
This reduces checks that must be made throughout the code, though
it does not reduce the need to know which record is the proper
one (user or user->cf_user) to use.

Also, pre-emptively make uncrustify happy *before* github has a go
at it.
@benchub
Copy link
Contributor Author

benchub commented Mar 13, 2024

OK @JelteF, I think I addressed all your points. Let me know what you think.

include/bouncer.h Outdated Show resolved Hide resolved
src/client.c Outdated Show resolved Hide resolved
test/test_auth.py Outdated Show resolved Hide resolved
JelteF added a commit that referenced this pull request Mar 14, 2024
While reviewing #1039 I had a hard time seeing if
max_user_connections was applied correctly because `SHOW USERS` didn't
list it. This addresses that by adding a `max_user_connections` and
`current_connections` column to the output of `SHOW USERS`.
The comments are more accurate, and the unit test now runs against
freebsd as well as other OSs.
@benchub benchub requested a review from JelteF March 18, 2024 13:48
@emelsimsek
Copy link
Contributor

The current logic that adds those users to the auth_file users (struct AATree user_tree;) seems wrong to me.

I believe the following would be a better approach:

The users in the [user] section are not added to the same list with auth_file users. A new structure is used to maintain them, e.g:

struct AATree cf_user_user_tree;

If a user is not found in auth_file users

  Run auth_query
	  Create a PgUser from the query results
	  find_user_user_config()  ---> finds user in cf_user_user_tree.
	  Update the PgUser from auth_query results with the user config in cf_users.

@benchub
Copy link
Contributor Author

benchub commented Mar 21, 2024

Sorry @emelsimsek, I'm afraid I'm not seeing what we gain by having two different user trees? My understanding of user_tree is that it is used as the collection of users that pgBouncer knows about. What do we gain by having one set for users whose password comes from auth_query and another set where the password comes from auth_file? Wouldn't we need to check both trees in every place where we are currently checking just one?

@emelsimsek
Copy link
Contributor

I'm afraid I'm not seeing what we gain by having two different user trees?

@benchub My thinking goes like this: The Users section is for overriding user configurations for users that comes from various sources. The users and their authentication tokens could be defined in either auth_file or remote user directories such as LDAP. Therefore for flexibility reasons, the user configurations should be maintained in a different list then auth_file's list.

@benchub
Copy link
Contributor Author

benchub commented Mar 26, 2024

OK @emelsimsek, I've spent some time trying to understand more of the pgBouncer codebase and I'm afraid I don't understand how to implement what you're suggesting, or even understand enough to see how it would help.

I assume when you say, "remote user directories such as LDAP" you are talking about PAM authentication and using LDAP as a PAM provider. I can appreciate that having user credentials being possibly defined in 3 places (pam, auth_file, or auth_query) could get messy, but the documentation is clear that pam is incompatible with the other two options. And indeed, when I look at the code base, there are multiple times that pgBouncer says "Oh, in the case of PAM, do this all differently" - for example, client.c:set_pool(), admin.c:show_one_fd(), or objects.c:use_server_socket().

It's a fair question to ask if pgBouncer should do it all differently, or if it should, as you seem to be suggesting, be able to use auth_query, auth_file, and pam all at the same time. I would suggest that such a change in behavior is beyond the scope of this bug fix.

More importantly, I don't know how to test pgBouncer using PAM. I don't see any unit tests doing so to work from, I don't have PAM set up in any of my environments, and frankly, while I remember PAM coming to linux almost 30 years ago, I've never set it up in all that time. I'm sure somebody is using it, but it's not me. I'm uncomfortable proposing code I don't have the ability to test.

Less importantly, in many of the places that the (currently only) user_tree is queried, it looks like having additional trees would seem to complicate the code for little gain. For example, objects.c:user_client_socket(), admin.c:admin_setup(), or admin.c:show_one_fd().

@emelsimsek
Copy link
Contributor

emelsimsek commented Mar 27, 2024

OK @emelsimsek, I've spent some time trying to understand more of the pgBouncer codebase and I'm afraid I don't understand how to implement what you're suggesting, or even understand enough to see how it would help.

I assume when you say, "remote user directories such as LDAP" you are talking about PAM authentication and using LDAP as a PAM provider.

Yes, the users may be defined in an LDAP directory and this is integrated into pgbouncer using PAM libraries.

I can appreciate that having user credentials being possibly defined in 3 places (pam, auth_file, or auth_query) could get messy, but the documentation is clear that pam is incompatible with the other two options. And indeed, when I look at the code base, there are multiple times that pgBouncer says "Oh, in the case of PAM, do this all differently" - for example, client.c:set_pool(), admin.c:show_one_fd(), or objects.c:use_server_socket().

auth_file and LDAP are alternatives to each other. users section in the configuration file on the other hand looks like intended to overrride user configurations for particular users.
I am also not sure about the maturity/extent of LDAP support in pgbouncer.

It's a fair question to ask if pgBouncer should do it all differently, or if it should, as you seem to be suggesting, be able to use auth_query, auth_file, and pam all at the same time. I would suggest that such a change in behavior is beyond the scope of this bug fix.

I agree that for getting this functionality work in its simplest form, the code change can be kept limited as you had done.
Especially given the absence of test automation for PAM feature, it may be best to keep it as it is.

More importantly, I don't know how to test pgBouncer using PAM. I don't see any unit tests doing so to work from, I don't have PAM set up in any of my environments, and frankly, while I remember PAM coming to linux almost 30 years ago, I've never set it up in all that time. I'm sure somebody is using it, but it's not me. I'm uncomfortable proposing code I don't have the ability to test.

Less importantly, in many of the places that the (currently only) user_tree is queried, it looks like having additional trees would seem to complicate the code for little gain. For example, objects.c:user_client_socket(), admin.c:admin_setup(), or admin.c:show_one_fd().

@benchub
Copy link
Contributor Author

benchub commented Mar 27, 2024

Yeah. FWIW I did modify add_pam_user in the same way I modified add_db_user, and the unit test I added does make sure that add_db_user (for auth_query users) does work correctly, so I don't think it's unreasonable to assume pam users also work with this change. But again, I don't know how to test that.

So @JelteF, anything else needed to let this be merged?

@benchub
Copy link
Contributor Author

benchub commented Apr 12, 2024

@JelteF are you waiting on me for anything?

@goksgie
Copy link
Contributor

goksgie commented Apr 13, 2024

I feel like [users] section should be specific to configurations, rather than mixing it with authentication. Thus, @emelsimsek 's suggestion of utilizing different data structures for both makes more sense, as then you would have a clear separation of "configurations" and "authentication". Doing so would allow you to fetch configurations defined in [users] when such connection is being made, if it is not initialized already. I think this would probably be a cleaner solution in terms of maintainability and being future proof.

As a side note, adding self referencing pointer and additional boolean to make this work feels hacky to me. But that is of course up to @JelteF and @emelsimsek to decide.

Edit: some grammar improvements.

Edit-2: If we were to separate them into different structures, I guess it would be a breaking change, deserving a major version bump? Though this would require some compatibility tests when implemented.

@JelteF
Copy link
Member

JelteF commented Apr 17, 2024

The more I look into this the more I realize how big of a mess our user management currently is. I definitely think we need some distinction between different types of users. It's super confusing to reason about. I'm trying out a few options for this at the moment.

@JelteF JelteF mentioned this pull request Apr 18, 2024
@JelteF
Copy link
Member

JelteF commented Apr 18, 2024

I created a PR for the user management refactor here: #1052

@JelteF JelteF closed this in #1052 May 2, 2024
JelteF added a commit that referenced this pull request May 2, 2024
Based upon #1039, but changed a lot by splitting the PgUser type into
two different types. One type for storing global user configuration, auth
info, and connection count tracking and a second type for dynamically created
users (which always references a global user).

This makes user configuration work for dynamically created users and
will also
list dynamically created users in the output of `SHOW USERS`.

Fixes #484
Fixes #706
Resolves #1039

Co-authored-by: Ben Chobot <bench@instructure.com>
Co-authored-by: benchub <bench@silentmedia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pgbouncer didn't even try auth_query to verify user password
4 participants