dispchar for oauth_client_secret

Started by Noah Mischabout 1 year ago10 messageshackers
Jump to latest
#1Noah Misch
noah@leadboat.com
commit b3f0be7 wrote:
+	{"oauth_scope", NULL, NULL, NULL,
+		"OAuth-Scope", "", 15,
+	offsetof(struct pg_conn, oauth_scope)},

The field containing "" is documented as follows:

char *dispchar; /* Indicates how to display this field in a
* connect dialog. Values are: "" Display
* entered value as is "*" Password field -
* hide value "D" Debug option - don't show
* by default */

I suspect this should use .dispchar="*" to encourage UIs to display
oauth_client_secret like a password field. Thoughts?

[I didn't review commit b3f0be7, but this caught my attention.]

#2Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Noah Misch (#1)
Re: dispchar for oauth_client_secret

On Tue, Apr 15, 2025 at 12:14 PM Noah Misch <noah@leadboat.com> wrote:

I suspect this should use .dispchar="*" to encourage UIs to display
oauth_client_secret like a password field. Thoughts?

Hmm, from a UI perspective I agree. (The builtin flow targets "public
clients", where secrets are discouraged and/or understood to be
not-really-secret, but there's no reason to assume that all flows used
by the application are public.)

From a proxy perspective, this would mess with FDW handling. By making
the dispchar '*', oauth_client_secret will be made into a user mapping
option rather than a server option. (Neither is very useful to
postgres_fdw anyway, because the builtin flow needs an end user to
interact with the provider.) But I'm not sure if we'll need to handle
compatibility in the future if we implement a proxy-friendly flow. Is
it okay to move options back and forth during a major version bump? I
assume it would present a problem for pg_upgrade?

Thanks!
--Jacob

#3Noah Misch
noah@leadboat.com
In reply to: Jacob Champion (#2)
Re: dispchar for oauth_client_secret

On Tue, Apr 15, 2025 at 01:16:12PM -0700, Jacob Champion wrote:

On Tue, Apr 15, 2025 at 12:14 PM Noah Misch <noah@leadboat.com> wrote:

I suspect this should use .dispchar="*" to encourage UIs to display
oauth_client_secret like a password field. Thoughts?

Hmm, from a UI perspective I agree. (The builtin flow targets "public
clients", where secrets are discouraged and/or understood to be
not-really-secret, but there's no reason to assume that all flows used
by the application are public.)

From a proxy perspective, this would mess with FDW handling. By making
the dispchar '*', oauth_client_secret will be made into a user mapping
option rather than a server option. (Neither is very useful to
postgres_fdw anyway, because the builtin flow needs an end user to
interact with the provider.) But I'm not sure if we'll need to handle
compatibility in the future if we implement a proxy-friendly flow.

If we think oauth_client_secret should get dispchar="*" UI treatment yet be a
postgres_fdw server option, postgres_fdw code can make it so. postgres_fdw
already has explicit code to reclassify the "user" option.

Is
it okay to move options back and forth during a major version bump? I
assume it would present a problem for pg_upgrade?

It would break dump/reload, so it's best not to move options between
optcontext=ForeignServerRelationId and optcontext=UserMappingRelationId, even
at major versions. As above, we can change dispchar separately from
optcontext. The documentation of dispchar likely should tell people to update
the postgres_fdw documentation when adding a dispchar="*' option.

It sounds like we might end up wanting to allow oauth_client_secret in both of
ForeignServerRelationId and UserMappingRelationId, each catering to different
oauth implementations. Is that right? (It would be fine to allow one today
and later change to allow both.)

#4Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Noah Misch (#3)
Re: dispchar for oauth_client_secret

On Tue, Apr 15, 2025 at 1:48 PM Noah Misch <noah@leadboat.com> wrote:

If we think oauth_client_secret should get dispchar="*" UI treatment yet be a
postgres_fdw server option, postgres_fdw code can make it so. postgres_fdw
already has explicit code to reclassify the "user" option.

Agreed, I will add an open item.

The documentation of dispchar likely should tell people to update
the postgres_fdw documentation when adding a dispchar="*' option.

(Or dispchar="D".)

It sounds like we might end up wanting to allow oauth_client_secret in both of
ForeignServerRelationId and UserMappingRelationId, each catering to different
oauth implementations. Is that right? (It would be fine to allow one today
and later change to allow both.)

I think, for the short-to-medium term, it is best to think of
oauth_client_id/oauth_client_secret/oauth_issuer as a packaged triple.
You don't want to use a secret with the wrong client ID, you don't
want to send a secret to the wrong provider, and one provider's client
ID won't be recognized by another. There might be some providers that
let you issue multiple secrets per client ID, but I seem to recall
that's intended more for rotation than it is for separate end users.

(It is true that separate users could make use of separate issuers
entirely. But that's conceptually separate from allowing a user to
control the HTTP entry point of server-side libpq without OWNER
privilege on the server. I don't like that at all from a risk
management perspective, and I'd prefer that we keep oauth_issuer on
the server context. It might be safe at some point to pull both
oauth_client_id and _secret down to the user context, once there's a
use case.)

Thanks!
--Jacob

#5Jelte Fennema-Nio
postgres@jeltef.nl
In reply to: Noah Misch (#3)
Re: dispchar for oauth_client_secret

On Tue, 15 Apr 2025 at 22:48, Noah Misch <noah@leadboat.com> wrote:

yet be a
postgres_fdw server option, postgres_fdw code can make it so. postgres_fdw
already has explicit code to reclassify the "user" option.

I don't understand why it should be a server option instead of a user
mapping option. Having it be a server option means that *any* Postgres
user can read its contents. My knowledge on the purpose is pretty
limited, but having that be the case for something with "secret" in
the name seems very unintuitive.

#6Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Jelte Fennema-Nio (#5)
Re: dispchar for oauth_client_secret

On Tue, Apr 15, 2025 at 3:25 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

I don't understand why it should be a server option instead of a user
mapping option. Having it be a server option means that *any* Postgres
user can read its contents.

Thank you for saying something; I'd hallucinated that srvoptions was
limited to the server owner, and that's not true. It's pg_user_mapping
that has the protection.

But if you want to hide the client secret from your users, making it a
user mapping option has not made the situation better. The client ID
and secret are there to authenticate libpq (and by extension,
postgres_fdw), not the end user.

My knowledge on the purpose is pretty
limited, but having that be the case for something with "secret" in
the name seems very unintuitive.

From the point of view of a proxy, whether you use a secret at all is
up to the flow in use. And for 18, the only supported flow is focused
on authorizing an actual human at the keyboard, without any token
caching, making it pretty unhelpful for FDW. A more proxy-friendly
flow would be awesome -- and/or explicit integration of the existing
builtin flow into the proxies, both safely and helpfully -- but that's
not a v18 thing. (I view it as similar in spirit to the
SCRAM-passthrough work.)

So: maybe it'd be best to disallow the OAuth options in the proxy code
entirely, so that a proxy-friendly future implementation is not
accidentally tied to decisions we made in v18.

--Jacob

#7Jelte Fennema-Nio
postgres@jeltef.nl
In reply to: Jacob Champion (#6)
Re: dispchar for oauth_client_secret

On Wed, 16 Apr 2025 at 02:03, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

Thank you for saying something; I'd hallucinated that srvoptions was
limited to the server owner, and that's not true. It's pg_user_mapping
that has the protection.

FWIW, I have some ideas on being able to store secrets in a server in
a safe way. I'll probably start a thread on that somewhere in the next
few months.

So: maybe it'd be best to disallow the OAuth options in the proxy code
entirely, so that a proxy-friendly future implementation is not
accidentally tied to decisions we made in v18.

Seems fine to me.

On Wed, 16 Apr 2025 at 02:03, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

Show quoted text

On Tue, Apr 15, 2025 at 3:25 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

I don't understand why it should be a server option instead of a user
mapping option. Having it be a server option means that *any* Postgres
user can read its contents.

Thank you for saying something; I'd hallucinated that srvoptions was
limited to the server owner, and that's not true. It's pg_user_mapping
that has the protection.

But if you want to hide the client secret from your users, making it a
user mapping option has not made the situation better. The client ID
and secret are there to authenticate libpq (and by extension,
postgres_fdw), not the end user.

My knowledge on the purpose is pretty
limited, but having that be the case for something with "secret" in
the name seems very unintuitive.

From the point of view of a proxy, whether you use a secret at all is
up to the flow in use. And for 18, the only supported flow is focused
on authorizing an actual human at the keyboard, without any token
caching, making it pretty unhelpful for FDW. A more proxy-friendly
flow would be awesome -- and/or explicit integration of the existing
builtin flow into the proxies, both safely and helpfully -- but that's
not a v18 thing. (I view it as similar in spirit to the
SCRAM-passthrough work.)

So: maybe it'd be best to disallow the OAuth options in the proxy code
entirely, so that a proxy-friendly future implementation is not
accidentally tied to decisions we made in v18.

--Jacob

#8Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Jelte Fennema-Nio (#7)
Re: dispchar for oauth_client_secret

On Tue, Apr 15, 2025 at 11:11 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

On Wed, 16 Apr 2025 at 02:03, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

Thank you for saying something; I'd hallucinated that srvoptions was
limited to the server owner, and that's not true. It's pg_user_mapping
that has the protection.

FWIW, I have some ideas on being able to store secrets in a server in
a safe way. I'll probably start a thread on that somewhere in the next
few months.

Sounds great!

Attached is my proposed fix. 0001 disables use of the new oauth_*
options in our FDWs. 0002 changes dispchar.

Thanks,
--Jacob

Attachments:

0001-oauth-Disallow-OAuth-connections-via-postgres_fdw-db.patchapplication/octet-stream; name=0001-oauth-Disallow-OAuth-connections-via-postgres_fdw-db.patchDownload+52-5
0002-oauth-Classify-oauth_client_secret-as-a-password.patchapplication/octet-stream; name=0002-oauth-Classify-oauth_client_secret-as-a-password.patchDownload+7-2
#9Noah Misch
noah@leadboat.com
In reply to: Jacob Champion (#8)
Re: dispchar for oauth_client_secret

On Mon, Apr 21, 2025 at 08:18:58AM -0700, Jacob Champion wrote:

Attached is my proposed fix. 0001 disables use of the new oauth_*
options in our FDWs. 0002 changes dispchar.

Subject: [PATCH 1/2] oauth: Disallow OAuth connections via postgres_fdw/dblink
Subject: [PATCH 2/2] oauth: Classify oauth_client_secret as a password

Both look good.

#10Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Noah Misch (#9)
Re: dispchar for oauth_client_secret

On Mon, Apr 28, 2025 at 6:49 PM Noah Misch <noah@leadboat.com> wrote:

Subject: [PATCH 1/2] oauth: Disallow OAuth connections via postgres_fdw/dblink
Subject: [PATCH 2/2] oauth: Classify oauth_client_secret as a password

Both look good.

Committed. Thanks for the review!

--Jacob