Thread
Commits
-
dblink: SCRAM authentication pass-through
- 3642df265d09 18.0 landed
-
postgres_fdw: improve security checks
- 76563f88cfbd 18.0 landed
-
dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-01-22T14:10:38Z
Hi, The attached patch enables SCRAM authentication for dblink connections when using dblink_fdw without requiring a plain-text password on user mapping properties. The implementation is very similar to what was implemented on postgres_fdw [0]. To make it more closer to what was implemented on postgres_fdw a refactor was needed on get connection routines. A connect_pg_server function was created to centralize all the logic to actually open the connection with the foreign server and then replace the duplicated code on dblink_get_conn and dblink_connect to just call this new function. The main reason for this refactor was to centralize the SCRAM logic in a single function, instead of checking if SCRAM is enabled on both functions. A new is_valid_dblink_fdw_option function was also created to check for valid dblink fdw options when creating a server with CREATE SERVER command. The is_valid_dblink_option function only checks for valid libpq options, and the use_scram_passthrough option is only valid on CREATE SERVER options. The documentation was also changed to include a new Foreign Data Wrapper section to describe the SCRAM pass-through feature. Thoughts? [0] https://www.postgresql.org/message-id/27b29a35-9b96-46a9-bc1a-914140869dac@gmail.com -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-02-10T23:19:46Z
On Wed, Jan 22, 2025 at 6:10 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > The attached patch enables SCRAM authentication for dblink connections when > using dblink_fdw without requiring a plain-text password on user mapping > properties. The implementation is very similar to what was implemented on > postgres_fdw [0]. Not a full review, but I wanted to highlight one aspect of the patch: > - dblink_connstr_check(connstr); > + /* > + * Verify the set of connection parameters only if scram pass-through is > + * not being used because the password is not necessary. > + */ > + if (!useScramPassthrough) > + dblink_connstr_check(connstr); and > - dblink_security_check(conn, rconn, connstr); > + /* > + * Perform post-connection security checks only if scram pass-through is > + * not being used because the password is not necessary. > + */ > + if (!useScramPassthrough) > + dblink_security_check(conn, rconn, connstr); These don't seem right to me. SCRAM passthrough should be considered as _part_ of the connstr/security checks, but I think it should not _bypass_ those checks. We have to enforce the use of the SCRAM credentials on the remote for safety, similarly to GSS delegation. (This might be a good place for `require_auth=scram-sha-256`?) I've attached a failing test to better illustrate what I mean. It looks like the postgres_fdw patch that landed also performs a bypass -- I think that may need an open item to fix? CC'd Peter. Thanks! --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-02-12T19:53:46Z
Hi, thanks for reviewing this patch! Em seg., 10 de fev. de 2025 às 20:19, Jacob Champion <jacob.champion@enterprisedb.com> escreveu: > > On Wed, Jan 22, 2025 at 6:10 AM Matheus Alcantara > <matheusssilv97@gmail.com> wrote: > > The attached patch enables SCRAM authentication for dblink connections when > > using dblink_fdw without requiring a plain-text password on user mapping > > properties. The implementation is very similar to what was implemented on > > postgres_fdw [0]. > > Not a full review, but I wanted to highlight one aspect of the patch: > > > - dblink_connstr_check(connstr); > > + /* > > + * Verify the set of connection parameters only if scram pass-through is > > + * not being used because the password is not necessary. > > + */ > > + if (!useScramPassthrough) > > + dblink_connstr_check(connstr); > > and > > > - dblink_security_check(conn, rconn, connstr); > > + /* > > + * Perform post-connection security checks only if scram pass-through is > > + * not being used because the password is not necessary. > > + */ > > + if (!useScramPassthrough) > > + dblink_security_check(conn, rconn, connstr); > > These don't seem right to me. SCRAM passthrough should be considered > as _part_ of the connstr/security checks, but I think it should not > _bypass_ those checks. We have to enforce the use of the SCRAM > credentials on the remote for safety, similarly to GSS delegation. > (This might be a good place for `require_auth=scram-sha-256`?) > Currently dblink_connstr_check and dblink_security_check only check if the password is present on connection options, in case of not superuser. I added this logic because the password is not required for SCRAM but I agree with you that it sounds strange. Maybe these functions could check if the SCRAM is being used and then skip the password validation if needed internally? I also agree that we should enforce the use of the SCRAM on the remote for safety. To do this I think that we could set require_auth=scram-sha-256 on connection options if SCRAM pass-through is being used, with this we will get a connection error. WYT? > I've attached a failing test to better illustrate what I mean. > Thanks for this! I'm attaching a v2 patch that includes the require_auth=scram-sha-256 option and also your test case, which I've just changed to the expected error message. > It looks like the postgres_fdw patch that landed also performs a > bypass -- I think that may need an open item to fix? CC'd Peter. > I can create a new patch to fix this on postgres_fdw too once we define the approach to this here on dblink. -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-02-13T23:25:46Z
On Wed, Feb 12, 2025 at 11:54 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > Currently dblink_connstr_check and dblink_security_check only check if the > password is present on connection options, in case of not superuser. They also check for GSS delegation. I think SCRAM passthrough should ideally be considered a second form of credentials delegation, from the perspective of those functions. > I added > this logic because the password is not required for SCRAM but I agree with you > that it sounds strange. Maybe these functions could check if the SCRAM is > being used and then skip the password validation if needed internally? As long as the end result is to enforce that the credentials must come from the end user, I think that would be fine in theory. > I also agree that we should enforce the use of the SCRAM on the remote for > safety. To do this I think that we could set require_auth=scram-sha-256 on > connection options if SCRAM pass-through is being used, with this we will get a > connection error. WYT? We would need to verify that the user mapping can't overwrite that with its own (less trusted) `require_auth` setting. (I think that should be true already, but I'm not 100% sure.) Hardcoding to scram-sha-256 would also prohibit the use of GSS or standard password auth, now that I think about it. The docs currently have a note about being able to choose... Should we add the other permitted authentication types, i.e. `password,md5,scram-sha-256,gss`? Or should we prohibit the use of other auth types if you've set use_scram_passthrough? Or maybe there's an easier way to enforce the use of the SCRAM keys, that better matches the current logic in dblink_security_check? > I can create a new patch to fix this on postgres_fdw too once we define the > approach to this here on dblink. Sounds good to me. Thanks, --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-02-19T20:01:58Z
On Thu, Feb 13, 2025 at 8:25 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > I also agree that we should enforce the use of the SCRAM on the remote for > > safety. To do this I think that we could set require_auth=scram-sha-256 on > > connection options if SCRAM pass-through is being used, with this we will get a > > connection error. WYT? > > We would need to verify that the user mapping can't overwrite that > with its own (less trusted) `require_auth` setting. (I think that > should be true already, but I'm not 100% sure.) > Yeah, this is true. The user mapping and the fdw options can overwrite this. I'll work on a fix for this. > Hardcoding to scram-sha-256 would also prohibit the use of GSS or > standard password auth, now that I think about it. The docs currently > have a note about being able to choose... Should we add the other > permitted authentication types, i.e. `password,md5,scram-sha-256,gss`? > Or should we prohibit the use of other auth types if you've set > use_scram_passthrough? Or maybe there's an easier way to enforce the > use of the SCRAM keys, that better matches the current logic in > dblink_security_check? > But would it be possible to use SCRAM pass-through feature using another auth method? We need the scram keys (that is saved on MyProcPort during scram_exchange) to perform the pass-through which I think that we would not have with another auth type? That being said I think that we could prohibit the usage of other auth types when use_scram_passthrough is set, what do you think? -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-02-19T23:19:10Z
On Wed, Feb 19, 2025 at 12:02 PM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > > Hardcoding to scram-sha-256 would also prohibit the use of GSS or > > standard password auth, now that I think about it. The docs currently > > have a note about being able to choose... Should we add the other > > permitted authentication types, i.e. `password,md5,scram-sha-256,gss`? > > Or should we prohibit the use of other auth types if you've set > > use_scram_passthrough? Or maybe there's an easier way to enforce the > > use of the SCRAM keys, that better matches the current logic in > > dblink_security_check? > > > But would it be possible to use SCRAM pass-through feature using another auth > method? No, but if you want the same foreign server to be accessible by users who log in with different authentication types, forcing a single require_auth setting will defeat that. I don't have a strong opinion about how important maintaining that functionality is, but the code seems to allow it today. -- Some thoughts on v2-0001: I like the conceptual simplification of get_connect_string(). > + /* first time, allocate or get the custom wait event */ > + if (dblink_we_connect == 0) > + dblink_we_connect = WaitEventExtensionNew("DblinkConnectPgServer"); Replacing two existing wait events with one new one is a user-facing change (see the documented list of events at [1]). Maybe we want that, but it hasn't been explained. I think that change should be made independently of a refactoring patch (or else defended in the commit message). > + if (foreign_server) > + { > + serverid = foreign_server->serverid; > + user_mapping = GetUserMapping(userid, serverid); > + > + connstr = get_connect_string(foreign_server, user_mapping); > + } Is there any other valid value for user_mapping that a caller can choose? If not, I'd like to see the GetUserMapping call pushed back down into get_connect_string(), unless there's another reason for pulling it up that I'm missing. > + static const PQconninfoOption *options = NULL; > + > + /* > + * Get list of valid libpq options. > + * > + * To avoid unnecessary work, we get the list once and use it throughout > + * the lifetime of this backend process. We don't need to care about > + * memory context issues, because PQconndefaults allocates with malloc. > + */ > + if (!options) > + { > + options = PQconndefaults(); > + if (!options) /* assume reason for failure is OOM */ > + ereport(ERROR, > + (errcode(ERRCODE_FDW_OUT_OF_MEMORY), > + errmsg("out of memory"), > + errdetail("Could not get libpq's default connection options."))); > + } It looks like `options` might be an unused variable in connect_pg_server()? > - if (PQstatus(conn) == CONNECTION_BAD) > + if (!conn || PQstatus(conn) != CONNECTION_OK) I don't think this should be changed in a refactoring patch. PQstatus() can handle a NULL conn pointer. > - if (rconn) > - pfree(rconn); Looks like this code in dblink_connect() was dropped. Thanks! --Jacob [1] https://www.postgresql.org/docs/current/dblink.html -
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-02-21T14:47:39Z
Hi, thanks for all the reviews. Attached v3 with some fixes. > They also check for GSS delegation. I think SCRAM passthrough should > ideally be considered a second form of credentials delegation, from > the perspective of those functions. > Changed dblink_connstr_check and dblink_security_check to receive information if scram passthrough is being used and then perform the validations. I just don't know if the order that I put the checks on these functions is the better or not, any input is welcome. > We would need to verify that the user mapping can't overwrite that > with its own (less trusted) `require_auth` setting. (I think that > should be true already, but I'm not 100% sure.) > When adding the require_auth on user mapping options we get an error `invalid option "require_auth"`, but it was possible to add the require_auth on foreign data wrapper server options. This new patch also add a validation on dblink_connstr_check and dblink_security_check to ensure that require_auth is is present on connection properties with scram-sha-256 as a value (we check only the connstr so I think that perform the validation only on the first security check function dblink_connstr_check would be enough, since I don't think that the connstr will be changed after this check, but I added on both functions just for sanity). > > > Hardcoding to scram-sha-256 would also prohibit the use of GSS or > > > standard password auth, now that I think about it. The docs currently > > > have a note about being able to choose... Should we add the other > > > permitted authentication types, i.e. `password,md5,scram-sha-256,gss`? > > > Or should we prohibit the use of other auth types if you've set > > > use_scram_passthrough? Or maybe there's an easier way to enforce the > > > use of the SCRAM keys, that better matches the current logic in > > > dblink_security_check? > > > > > But would it be possible to use SCRAM pass-through feature using another auth > > method? > > No, but if you want the same foreign server to be accessible by users > who log in with different authentication types, forcing a single > require_auth setting will defeat that. I don't have a strong opinion > about how important maintaining that functionality is, but the code > seems to allow it today. > The hard coded require_auth=scram-sha-256 will only be added if use_scram_passthrough is set and also if the client that connect into the server also uses the scram auth type, so that we can have the scram keys. So in case the user try to authenticate using a different auth type on the same foreign server that has use_scram_passthrough the require_auth=scram-sha-256 will not be added because MyProcPort->has_scram_keys is false. > -- > > Some thoughts on v2-0001: > > I like the conceptual simplification of get_connect_string(). > > > + /* first time, allocate or get the custom wait event */ > > + if (dblink_we_connect == 0) > > + dblink_we_connect = WaitEventExtensionNew("DblinkConnectPgServer"); > > Replacing two existing wait events with one new one is a user-facing > change (see the documented list of events at [1]). Maybe we want that, > but it hasn't been explained. I think that change should be made > independently of a refactoring patch (or else defended in the commit > message). > You're right, I've fixed it by changing the connect_pg_server to receive the wait event info. > > + if (foreign_server) > > + { > > + serverid = foreign_server->serverid; > > + user_mapping = GetUserMapping(userid, serverid); > > + > > + connstr = get_connect_string(foreign_server, user_mapping); > > + } > > Is there any other valid value for user_mapping that a caller can > choose? If not, I'd like to see the GetUserMapping call pushed back > down into get_connect_string(), unless there's another reason for > pulling it up that I'm missing. > I agree, I've just declared outside of get_connect_string because on 0002 we also need the user mapping for UseScramPassthrough function, so I think that it would make the review more easier. + useScramPassthrough = MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, user_mapping); > > + static const PQconninfoOption *options = NULL; > > + > > + /* > > + * Get list of valid libpq options. > > + * > > + * To avoid unnecessary work, we get the list once and use it throughout > > + * the lifetime of this backend process. We don't need to care about > > + * memory context issues, because PQconndefaults allocates with malloc. > > + */ > > + if (!options) > > + { > > + options = PQconndefaults(); > > + if (!options) /* assume reason for failure is OOM */ > > + ereport(ERROR, > > + (errcode(ERRCODE_FDW_OUT_OF_MEMORY), > > + errmsg("out of memory"), > > + errdetail("Could not get libpq's default connection options."))); > > + } > > It looks like `options` might be an unused variable in connect_pg_server()? > It's right. Fixed. > > - if (PQstatus(conn) == CONNECTION_BAD) > > + if (!conn || PQstatus(conn) != CONNECTION_OK) > > I don't think this should be changed in a refactoring patch. > PQstatus() can handle a NULL conn pointer. > Fixed > > - if (rconn) > > - pfree(rconn); > > Looks like this code in dblink_connect() was dropped. > Oops, fixed on connect_pg_server since this logic was moved to this function. ## Some other changes I also added a new TAP test case to ensure that we return an error if require_auth is overwritten with another value. ## Questions: - The new dblink_connstr_has_scam_require_auth function is very similar with dblink_connstr_has_pw, we may create a common function for these or let it duplicated? -- Matheus Alcantara -
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-03T17:01:37Z
On Fri, Feb 21, 2025 at 6:48 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > Hi, thanks for all the reviews. Attached v3 with some fixes. Thanks! I keep getting pulled away from my review of 0002, so I'll just comment on 0001 to get things moving again; sorry for the delay. > I agree, I've just declared outside of get_connect_string because on 0002 we > also need the user mapping for UseScramPassthrough function, so I think that it > would make the review more easier. Ah, I missed that part of 0002. Works for me. > > > - if (rconn) > > > - pfree(rconn); > > > > Looks like this code in dblink_connect() was dropped. > > > Oops, fixed on connect_pg_server since this logic was moved to this function. I think this fix may break the other usage in dblink_get_conn(), where rconn comes from a hash entry. Maybe dblink_connect() should instead put a PG_CATCH/pfree/PG_RE_THROW around the call to connect_pg_server(), to ensure that the rconn allocation in TopMemoryContext doesn't get leaked? > ## Questions: > > - The new dblink_connstr_has_scam_require_auth function is very similar with > dblink_connstr_has_pw, we may create a common function for these or let it > duplicated? My preference would be to wait for a third [1], but at the very least I think the new function should go right next to the old one, to highlight the similarity. I have attached some stylistic suggestions, plus pgindent/pgperltidy tweaks, as fixup commits 0002 and 0004. Thanks, --Jacob [1] https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-06T19:24:25Z
On Mon, Mar 3, 2025 at 9:01 AM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > I keep getting pulled away from my review of 0002 Here's a review of v3-0002: > +dblink_connstr_check(const char *connstr, bool useScramPassthrough) > { > + if (useScramPassthrough) > + { > + if (dblink_connstr_has_scram_require_auth(connstr)) > + return; Can a comment be added somewhere to state that the security of this check relies on scram_server_key and scram_client_key not coming from the environment or any mapping options? The fact that those two options are declared 1) without envvar names and 2) as debug options is doing a lot of heavy security lifting, but it's hard to see that from this part of the code. Alternatively, this check could also verify that scram_client_key/server_key are set in the connection string explicitly. It is still strange to me that we don't fall through to check other potential safe options (see comment on the dblink_security_check, below). > + ... > + } > + > if (superuser()) > return; > For the additions to dblink_connstr_check/security_check, I think the superuser checks should remain at the top. Superusers can still do what they want. > +dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr, bool useScramPassthrough) > { > + > + if (useScramPassthrough) > + { > + if (dblink_connstr_has_scram_require_auth(connstr)) > + return; I don't think this check should be the same as the connstr check above, but I don't have a concrete example of what it should do instead. require_auth is taking care of the accidental trust config... Should there be an API that checks that the server and client key were used during the SCRAM exchange, similar to PQconnectionUsedPassword()? Would that even add anything? This division between "connstr check" and "security check" is easier to describe when we allow a variety of safe options, and check to see if any of them have been used. use_scram_passthrough locks it down to one possible option, making this division a little muddier. > + appendStringInfo(buf, "scram_client_key='%s'", client_key); > + appendStringInfo(buf, "scram_server_key='%s'", server_key); > + appendStringInfo(buf, "require_auth='scram-sha-256'"); These should have spaces between them; i.e. "scram_client_key='%s' ". Thanks, --Jacob -
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-06T20:33:16Z
On 11.02.25 00:19, Jacob Champion wrote: > These don't seem right to me. SCRAM passthrough should be considered > as_part_ of the connstr/security checks, but I think it should not > _bypass_ those checks. We have to enforce the use of the SCRAM > credentials on the remote for safety, similarly to GSS delegation. > (This might be a good place for `require_auth=scram-sha-256`?) > > I've attached a failing test to better illustrate what I mean. > > It looks like the postgres_fdw patch that landed also performs a > bypass -- I think that may need an open item to fix? CC'd Peter. AFAICT, in pgfdw_security_check(), if SCRAM has been used for the outgoing server connection, then PQconnectionUsedPassword() is true, and then this check should fail if no "password" parameter was given. That check should be expanded to allow alternatively passing the SCRAM key component parameters. But that would mean the check is too restrictive, while you are apparently claiming that the check is not restrictive enough? (Also, this would appear to mean the current SCRAM pass-through code in postgres_fdw should mostly not work, but the tests work, so I'm confused.)
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-06T21:58:55Z
On Thu, Mar 6, 2025 at 12:33 PM Peter Eisentraut <peter@eisentraut.org> wrote: > AFAICT, in pgfdw_security_check(), if SCRAM has been used for the > outgoing server connection, then PQconnectionUsedPassword() is true, and > then this check should fail if no "password" parameter was given. That > check should be expanded to allow alternatively passing the SCRAM key > component parameters. pgfdw_security_check() is currently not called if SCRAM passthrough is in use, though: > /* > * Perform post-connection security checks only if scram pass-through > * is not being used because the password is not necessary. > */ > if (!(MyProcPort->has_scram_keys && UseScramPassthrough(server, user))) > pgfdw_security_check(keywords, values, user, conn); --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-07T16:22:12Z
On 06.03.25 22:58, Jacob Champion wrote: > On Thu, Mar 6, 2025 at 12:33 PM Peter Eisentraut <peter@eisentraut.org> wrote: >> AFAICT, in pgfdw_security_check(), if SCRAM has been used for the >> outgoing server connection, then PQconnectionUsedPassword() is true, and >> then this check should fail if no "password" parameter was given. That >> check should be expanded to allow alternatively passing the SCRAM key >> component parameters. > > pgfdw_security_check() is currently not called if SCRAM passthrough is > in use, though: > >> /* >> * Perform post-connection security checks only if scram pass-through >> * is not being used because the password is not necessary. >> */ >> if (!(MyProcPort->has_scram_keys && UseScramPassthrough(server, user))) >> pgfdw_security_check(keywords, values, user, conn); Right. How about the attached? It checks as an alternative to a password whether the SCRAM keys were provided. That should get us back to the same level of checking?
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-10T18:25:51Z
On Fri, Mar 7, 2025 at 8:22 AM Peter Eisentraut <peter@eisentraut.org> wrote: > Right. How about the attached? It checks as an alternative to a > password whether the SCRAM keys were provided. That should get us back > to the same level of checking? Yes, I think so. Attached is a set of tests to illustrate, mirroring the dblink tests added upthread; they fail without this patch. I like that this solution addresses some of the concerns from my dblink review. -- Not part of this patchset, but I think the errmsg in pgfdw_security_check() is confusing: ERROR: password or GSSAPI delegated credentials required DETAIL: Non-superuser cannot connect if the server does not request a password or... HINT: Target server's authentication method must be changed or... For the user to have gotten past check_conn_params, they *have* provided a password/credentials. But the server didn't ask for it (or at least, not the right one). The detail and hint messages are correct here, but I'd argue the error message itself is not. Thanks! --Jacob -
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-12T15:17:55Z
On Mon, Mar 10, 2025 at 11:25 AM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Fri, Mar 7, 2025 at 8:22 AM Peter Eisentraut <peter@eisentraut.org> wrote: > > Right. How about the attached? It checks as an alternative to a > > password whether the SCRAM keys were provided. That should get us back > > to the same level of checking? > > Yes, I think so. Attached is a set of tests to illustrate, mirroring > the dblink tests added upthread; they fail without this patch. In an offline discussion with Peter and Matheus, we figured out that this is still not enough. The latest patch checks that a password was used, but it doesn't ensure that the password material came from the SCRAM keys. Attached is an updated test to illustrate. Thanks, --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-13T13:59:17Z
Hi, thanks for all the comments! Attached v5 with some fixes (I'll answer comments for different emails on this since most of them is fixed on this new v5 version) > I think this fix may break the other usage in dblink_get_conn(), where > rconn comes from a hash entry. Maybe dblink_connect() should instead > put a PG_CATCH/pfree/PG_RE_THROW around the call to > connect_pg_server(), to ensure that the rconn allocation in > TopMemoryContext doesn't get leaked? > Fixed by wrapping on PG_CATCH/pfree/PG_RE_THROW. I didn't managed to create a test that use this code path, so let me know if I'm still missing something. > Can a comment be added somewhere to state that the security of this > check relies on scram_server_key and scram_client_key not coming from > the environment or any mapping options? The fact that those two > options are declared 1) without envvar names and 2) as debug options > is doing a lot of heavy security lifting, but it's hard to see that > from this part of the code. > I've added a code comment on dblink_connstr_has_required_scram_options function which is called on "connstr check" and "security check". Please let me know what you think. > Alternatively, this check could also verify that > scram_client_key/server_key are set in the connection string > explicitly. > I've added this validation on dblink_connstr_has_required_scram_options. > For the additions to dblink_connstr_check/security_check, I think the > superuser checks should remain at the top. Superusers can still do > what they want. > Fixed > I don't think this check should be the same as the connstr check > above, but I don't have a concrete example of what it should do > instead. require_auth is taking care of the accidental trust config... > Should there be an API that checks that the server and client key were > used during the SCRAM exchange, similar to PQconnectionUsedPassword()? > Would that even add anything? > I was also thinking about this, maybe we could add a new validation (similar with PQconnectionUsedPassword, on fe-connect.c) that check if the scram keys is set on PGconn (we only set these keys if we are actually using the scram pass-through feature) +int +PQconnectionUsedScramKeys(const PGconn *conn) +{ + if (conn->scram_client_key && conn->scram_server_key) + return true; + + return false; +} And then call on dblink_security_check - if (MyProcPort->has_scram_keys && dblink_connstr_has_required_scram_options(connstr)) + if (MyProcPort->has_scram_keys + && dblink_connstr_has_required_scram_options(connstr) + && PQconnectionUsedScramKeys(conn)) return; (Note that I didn't implement this on this new patch version, I'm just sharing some ideas that I had during development.) > These should have spaces between them; i.e. "scram_client_key='%s' ". > Fixed > > On Fri, Mar 7, 2025 at 8:22 AM Peter Eisentraut <peter@eisentraut.org> wrote: > > > Right. How about the attached? It checks as an alternative to a > > > password whether the SCRAM keys were provided. That should get us back > > > to the same level of checking? > > > > Yes, I think so. Attached is a set of tests to illustrate, mirroring > > the dblink tests added upthread; they fail without this patch. > > In an offline discussion with Peter and Matheus, we figured out that > this is still not enough. The latest patch checks that a password was > used, but it doesn't ensure that the password material came from the > SCRAM keys. Attached is an updated test to illustrate. > On this new patch version I also changed the "connstr check" and "security check" to have a validation very similar to what Peter implemented on 0001-WIP-postgres_fdw-Fix-SCRAM-pass-through-security patch. I also reproduced this test case that you've created on this new dblink patch version and we actually fail as expected (but with a different error message) because here we are adding require_auth=scram-sha-256. So, I think that having something similar to what Peter implemented on his patch and adding require_auth=scram-sha-256 may prevent this kind of security issue? -- Matheus Alcantara -
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-13T19:54:46Z
On Thu, Mar 13, 2025 at 6:59 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > Fixed by wrapping on PG_CATCH/pfree/PG_RE_THROW. I didn't managed to > create a test that use this code path, so let me know if I'm still > missing something. Thanks! Looks like the regression suite has one test that takes that path (found by adding an Assert(false) to the PG_CATCH branch): SET SESSION AUTHORIZATION regress_dblink_user; -- should fail SELECT dblink_connect('myconn', 'fdtest'); > PG_CATCH(); > { > if (rconn) > pfree(rconn); A comment in this branch might be nice, to draw attention to the fact that rconn is allocated in the TopMemoryContext and we can't leak it. > I've added a code comment on dblink_connstr_has_required_scram_options > function which is called on "connstr check" and "security check". Please > let me know what you think. That comment does not seem to match the code now: > + * All required scram options is set by ourself, so we just need to ensure > + * that these options are not overwritten by the user. But later, there's no provision to detect if the keys have been overwritten: > + if (strcmp(option->keyword, "scram_client_key") == 0 && option->val[0] != '\0') > + has_scram_client_key = true; > + if (strcmp(option->keyword, "scram_server_key") == 0 && option->val[0] != '\0') > + has_scram_server_key = true; This needs to match the handling directly above it, if we want to claim that we'll detect duplicates. > I was also thinking about this, maybe we could add a new validation > (similar with PQconnectionUsedPassword, on fe-connect.c) that check if > the scram keys is set on PGconn (we only set these keys if we are > actually using the scram pass-through feature) > > +int > +PQconnectionUsedScramKeys(const PGconn *conn) > +{ > + if (conn->scram_client_key && conn->scram_server_key) > + return true; > + > + return false; > +} If we implement this, it needs to check that the keys were actually sent during scram_exchange(). Having them set on the PGconn doesn't mean that we used them for authentication. > So, I think that having something similar to what Peter implemented on > his patch and adding require_auth=scram-sha-256 may prevent this kind of > security issue? Right. I think it'll come down to how Peter feels about putting that into the solution, vs. PQconnectionUsedScramKeys() or some third option. -- Miscellaneous patch review: > -dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr) > +dblink_security_check(PGconn *conn, remoteConn *rconn, > + const char *connstr) nit: this whitespace change is not necessary now that useScramPassthrough is no longer in the signature. Speaking of which, does get_connect_string() still need to take user_mapping as an argument? > + if (has_scram_keys && has_require_auth) > + return true; > + > + return false; nit: this is equivalent to `return (has_scram_keys && has_require_auth);` > + my ($ret2, $stdout2, $stderr2) = $node->psql( Declaring a second set of return values is probably unnecessary; the previous ones can be reused. > + is( $stderr, > + "psql:<stdin>:1: ERROR: invalid option \"scram_client_key\"", > + 'user mapping creation fails when using scram_client_key'); I think the two new tests like this should be using like() rather than is() so that they can match only the important part of the error. I don't think we want to pin the "psql:<stdin>" stuff in this test. > +($ret, $stdout, $stderr) = $node1->psql( > + $db0, > + "SELECT * FROM dblink('$fdw_server', 'SELECT * FROM t') AS t(a int, b int)", > + connstr => $node1->connstr($db0) . " user=$user"); > + > +is($ret, 3, 'loopback trust fails on the same cluster'); > +like( > + $stderr, > + qr/failed: authentication method requirement "scram-sha-256" failed: server did not complete authentication/, > + 'expected error from loopback trust (same cluster)'); Is this the same as the previous loopback-trust test? If so I think it can be removed (or the two sections merged completely). Thanks! --Jacob -
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-13T21:38:26Z
On Thu, Mar 13, 2025 at 4:54 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Thu, Mar 13, 2025 at 6:59 AM Matheus Alcantara > <matheusssilv97@gmail.com> wrote: > > Fixed by wrapping on PG_CATCH/pfree/PG_RE_THROW. I didn't managed to > > create a test that use this code path, so let me know if I'm still > > missing something. > > Thanks! Looks like the regression suite has one test that takes that > path (found by adding an Assert(false) to the PG_CATCH branch): > > SET SESSION AUTHORIZATION regress_dblink_user; > -- should fail > SELECT dblink_connect('myconn', 'fdtest'); > > > PG_CATCH(); > > { > > if (rconn) > > pfree(rconn); > > A comment in this branch might be nice, to draw attention to the fact > that rconn is allocated in the TopMemoryContext and we can't leak it. > Fixed > > I've added a code comment on dblink_connstr_has_required_scram_options > > function which is called on "connstr check" and "security check". Please > > let me know what you think. > > That comment does not seem to match the code now: > > > + * All required scram options is set by ourself, so we just need to ensure > > + * that these options are not overwritten by the user. > > But later, there's no provision to detect if the keys have been overwritten: > > > + if (strcmp(option->keyword, "scram_client_key") == 0 && option->val[0] != '\0') > > + has_scram_client_key = true; > > + if (strcmp(option->keyword, "scram_server_key") == 0 && option->val[0] != '\0') > > + has_scram_server_key = true; > > This needs to match the handling directly above it, if we want to > claim that we'll detect duplicates. > I thought about this; The problem is that at this point, the scram keys on connection options are base64 encoded (see appendSCRAMKeysInfo), so we can't compare with the values stored on MyProcPort. I don't know if decoding the option or encoding the keys on MyProcPort from/to base64 is a way to go, what do you think? I've implemented this check in this way because we don't allow adding the scram keys on user mapping or foreign server options, so the user can't actually overwrite the scram keys, unless there is the possibility of filling in these scram keys options in other places besides user mapping and foreign server options that I am missing? > > I was also thinking about this, maybe we could add a new validation > > (similar with PQconnectionUsedPassword, on fe-connect.c) that check if > > the scram keys is set on PGconn (we only set these keys if we are > > actually using the scram pass-through feature) > > > > +int > > +PQconnectionUsedScramKeys(const PGconn *conn) > > +{ > > + if (conn->scram_client_key && conn->scram_server_key) > > + return true; > > + > > + return false; > > +} > > If we implement this, it needs to check that the keys were actually > sent during scram_exchange(). Having them set on the PGconn doesn't > mean that we used them for authentication. > We use the client key and server key on calculate_client_proof and verify_server_signature respective during memcpy, it would be too hack to add new fields on pg_conn like scram_client_key_in_use and scram_server_key_in_use, set them to true on these functions and then validate that both are true on PQconnectionUsedScramKeys? > -- > > Miscellaneous patch review: > > > -dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr) > > +dblink_security_check(PGconn *conn, remoteConn *rconn, > > + const char *connstr) > > nit: this whitespace change is not necessary now that > useScramPassthrough is no longer in the signature. > Fixed > Speaking of which, does get_connect_string() still need to take > user_mapping as an argument? > Yes, because we need to check if the use_scram_passthrough option is set on foreign server or user mapping options: if (MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, user_mapping)) appendSCRAMKeysInfo(&buf); > > + if (has_scram_keys && has_require_auth) > > + return true; > > + > > + return false; > > nit: this is equivalent to `return (has_scram_keys && has_require_auth);` > Fixed > > + my ($ret2, $stdout2, $stderr2) = $node->psql( > > Declaring a second set of return values is probably unnecessary; the > previous ones can be reused. > Fixed > > + is( $stderr, > > + "psql:<stdin>:1: ERROR: invalid option \"scram_client_key\"", > > + 'user mapping creation fails when using scram_client_key'); > > I think the two new tests like this should be using like() rather than > is() so that they can match only the important part of the error. I > don't think we want to pin the "psql:<stdin>" stuff in this test. > Yes, having "psq:<stdin>" is weird, fixed. > > +($ret, $stdout, $stderr) = $node1->psql( > > + $db0, > > + "SELECT * FROM dblink('$fdw_server', 'SELECT * FROM t') AS t(a int, b int)", > > + connstr => $node1->connstr($db0) . " user=$user"); > > + > > +is($ret, 3, 'loopback trust fails on the same cluster'); > > +like( > > + $stderr, > > + qr/failed: authentication method requirement "scram-sha-256" failed: server did not complete authentication/, > > + 'expected error from loopback trust (same cluster)'); > > Is this the same as the previous loopback-trust test? If so I think it > can be removed (or the two sections merged completely). > The only difference is using "trust" vs "password" on $db2 pg_hba.conf, but the expectation of the test is the same. I've just removed the test using "trust". Good catch, I've made a small confusion on these tests. Thanks for all the comments! -- Matheus Alcantara -
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-17T16:49:17Z
On Thu, Mar 13, 2025 at 2:38 PM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > I thought about this; The problem is that at this point, the scram keys > on connection options are base64 encoded (see appendSCRAMKeysInfo), so > we can't compare with the values stored on MyProcPort. I don't think that's necessary -- the important part is to check whether they've been unset (empty string). > I've implemented this check in this way because we don't allow adding > the scram keys on user mapping or foreign server options, so the user > can't actually overwrite the scram keys, unless there is the possibility > of filling in these scram keys options in other places besides user > mapping and foreign server options that I am missing? Understood, but there are two separate comments that claim the code does something that it doesn't: + * All required scram options is set by ourself, so we just need to ensure + * that these options are not overwritten by the user. and + * First append hardcoded options needed for SCRAM pass-through, so if the + * user overwrite these options we can ereport on dblink_connstr_check and + * dblink_security_check. If the check functions aren't going to check those because it's unnecessary, then that's fine, but then the comments should be adjusted. > > If we implement this, it needs to check that the keys were actually > > sent during scram_exchange(). Having them set on the PGconn doesn't > > mean that we used them for authentication. > > > We use the client key and server key on calculate_client_proof and > verify_server_signature respective during memcpy, it would be too hack > to add new fields on pg_conn like scram_client_key_in_use and > scram_server_key_in_use, set them to true on these functions and then > validate that both are true on PQconnectionUsedScramKeys? I think that's probably a question for Peter: whether or not that additional API is something we want to support. > > > -dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr) > > > +dblink_security_check(PGconn *conn, remoteConn *rconn, > > > + const char *connstr) > > > > nit: this whitespace change is not necessary now that > > useScramPassthrough is no longer in the signature. > > > Fixed (This diff is still present in v6-0002.) > > Speaking of which, does get_connect_string() still need to take > > user_mapping as an argument? > > > Yes, because we need to check if the use_scram_passthrough option is set > on foreign server or user mapping options: > if (MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, > user_mapping)) > appendSCRAMKeysInfo(&buf); I was referring to the discussion upthread [1]; you'd mentioned that the only reason that get_connect_string() didn't call GetUserMapping() itself was because we needed that mapping later on for UseScramPassthrough(). But that's no longer true for this patch, because the later call to UseScramPassthrough() has been removed. So I think we can move GetUserMapping() back down, and remove that part of the refactoring from patch 0001. Thanks! --Jacob [1] https://postgr.es/m/CAFY6G8f%3DjRUAP5yiFRZkHmqstCiRkeeD5Zf2ixVf6HMmjBCgfg%40mail.gmail.com
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-17T18:54:08Z
On Mon, Mar 17, 2025 at 1:49 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Thu, Mar 13, 2025 at 2:38 PM Matheus Alcantara > <matheusssilv97@gmail.com> wrote: > > I thought about this; The problem is that at this point, the scram keys > > on connection options are base64 encoded (see appendSCRAMKeysInfo), so > > we can't compare with the values stored on MyProcPort. > > I don't think that's necessary -- the important part is to check > whether they've been unset (empty string). > > > I've implemented this check in this way because we don't allow adding > > the scram keys on user mapping or foreign server options, so the user > > can't actually overwrite the scram keys, unless there is the possibility > > of filling in these scram keys options in other places besides user > > mapping and foreign server options that I am missing? > > Understood, but there are two separate comments that claim the code > does something that it doesn't: > > + * All required scram options is set by ourself, so we just need to ensure > + * that these options are not overwritten by the user. > > and > > + * First append hardcoded options needed for SCRAM pass-through, so if the > + * user overwrite these options we can ereport on dblink_connstr_check and > + * dblink_security_check. > > If the check functions aren't going to check those because it's > unnecessary, then that's fine, but then the comments should be > adjusted. > Ok, now I get all of your points. I've misinterpreted your comments, sorry about that. I've changed on v7 to validate the scram keys using the same approach implemented for require_auth, so that now we correctly check for overwritten scram keys on connection options. I think that the code comments should be correct now? > > > If we implement this, it needs to check that the keys were actually > > > sent during scram_exchange(). Having them set on the PGconn doesn't > > > mean that we used them for authentication. > > > > > We use the client key and server key on calculate_client_proof and > > verify_server_signature respective during memcpy, it would be too hack > > to add new fields on pg_conn like scram_client_key_in_use and > > scram_server_key_in_use, set them to true on these functions and then > > validate that both are true on PQconnectionUsedScramKeys? > > I think that's probably a question for Peter: whether or not that > additional API is something we want to support. > Ok > > > > -dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr) > > > > +dblink_security_check(PGconn *conn, remoteConn *rconn, > > > > + const char *connstr) > > > > > > nit: this whitespace change is not necessary now that > > > useScramPassthrough is no longer in the signature. > > > > > Fixed > > (This diff is still present in v6-0002.) > Sorry, I think that now is fixed. > > > Speaking of which, does get_connect_string() still need to take > > > user_mapping as an argument? > > > > > Yes, because we need to check if the use_scram_passthrough option is set > > on foreign server or user mapping options: > > if (MyProcPort->has_scram_keys && UseScramPassthrough(foreign_server, > > user_mapping)) > > appendSCRAMKeysInfo(&buf); > > I was referring to the discussion upthread [1]; you'd mentioned that > the only reason that get_connect_string() didn't call GetUserMapping() > itself was because we needed that mapping later on for > UseScramPassthrough(). But that's no longer true for this patch, > because the later call to UseScramPassthrough() has been removed. So I > think we can move GetUserMapping() back down, and remove that part of > the refactoring from patch 0001. > Ok, it totally makes sense. Fixed on v7. -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-17T23:26:40Z
On Mon, Mar 17, 2025 at 11:54 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > > If the check functions aren't going to check those because it's > > unnecessary, then that's fine, but then the comments should be > > adjusted. > > > Ok, now I get all of your points. I've misinterpreted your comments, > sorry about that. I've changed on v7 to validate the scram keys using > the same approach implemented for require_auth, so that now we correctly > check for overwritten scram keys on connection options. I think that the > code comments should be correct now? Looks good. > > I was referring to the discussion upthread [1]; you'd mentioned that > > the only reason that get_connect_string() didn't call GetUserMapping() > > itself was because we needed that mapping later on for > > UseScramPassthrough(). But that's no longer true for this patch, > > because the later call to UseScramPassthrough() has been removed. So I > > think we can move GetUserMapping() back down, and remove that part of > > the refactoring from patch 0001. > > > Ok, it totally makes sense. Fixed on v7. The fix is in, but it needs to be part of 0001 rather than 0002; otherwise 0001 doesn't compile. -- A pgperltidy run is needed for some of the more recent test changes. But I'm rapidly running out of feedback, so I think this is very close. Thanks! --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-18T13:10:03Z
On Mon, Mar 17, 2025 at 8:26 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > > I was referring to the discussion upthread [1]; you'd mentioned that > > > the only reason that get_connect_string() didn't call GetUserMapping() > > > itself was because we needed that mapping later on for > > > UseScramPassthrough(). But that's no longer true for this patch, > > > because the later call to UseScramPassthrough() has been removed. So I > > > think we can move GetUserMapping() back down, and remove that part of > > > the refactoring from patch 0001. > > > > > Ok, it totally makes sense. Fixed on v7. > > The fix is in, but it needs to be part of 0001 rather than 0002; > otherwise 0001 doesn't compile. > Fixed. 0001 and 0002 are compiling now. > -- > > A pgperltidy run is needed for some of the more recent test changes. > But I'm rapidly running out of feedback, so I think this is very > close. > Fixed Thanks very much for all the reviews on this patch! -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-18T16:35:46Z
On 17.03.25 17:49, Jacob Champion wrote: >>> If we implement this, it needs to check that the keys were actually >>> sent during scram_exchange(). Having them set on the PGconn doesn't >>> mean that we used them for authentication. >>> >> We use the client key and server key on calculate_client_proof and >> verify_server_signature respective during memcpy, it would be too hack >> to add new fields on pg_conn like scram_client_key_in_use and >> scram_server_key_in_use, set them to true on these functions and then >> validate that both are true on PQconnectionUsedScramKeys? > I think that's probably a question for Peter: whether or not that > additional API is something we want to support. So the way I understand this is that the options are: (1) We add a libpq function like PQconnectionUsedScramKeys() in the style of PQconnectionUsedPassword() and call that function during the checks. (2) We make use_scram_passthrough=true imply require_auth=scram-sha-256. This is essentially a way to get the info from (1) out of libpq using existing facilities. But it would preempt certain setups that might otherwise work. (Which ones? Are they important?) Why can't we use PQconnectionUsedPassword()? What problems would that leave? The example test case that Jacob showed earlier involved the remote server using "trust". We don't want that, of course. But what we want to make sure is that some kind of authentication happened between postgres_fdw and the remote server. PQconnectionUsedPassword() does indicate that. (Or could we just stick in require_auth=!none to solve this problem once and for all?)
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-18T16:53:51Z
On Tue, Mar 18, 2025 at 9:35 AM Peter Eisentraut <peter@eisentraut.org> wrote: > So the way I understand this is that the options are: > > (1) We add a libpq function like PQconnectionUsedScramKeys() in the > style of PQconnectionUsedPassword() and call that function during the > checks. > > (2) We make use_scram_passthrough=true imply require_auth=scram-sha-256. > This is essentially a way to get the info from (1) out of libpq using > existing facilities. Right. > But it would preempt certain setups that might > otherwise work. (Which ones? Are they important?) If the backend HBA later changes, to require delegated GSS or a different type of password authentication, the user will have to unset use_scram_passthrough (or ask the owner of the foreign server to unset it). Whereas before they could just add a password to their user mapping or enable delegation to move forward immediately. I think this is probably not a serious limitation, in practice. > Why can't we use PQconnectionUsedPassword()? What problems would that > leave? The example test case that Jacob showed earlier involved the > remote server using "trust". We don't want that, of course. But what > we want to make sure is that some kind of authentication happened > between postgres_fdw and the remote server. PQconnectionUsedPassword() > does indicate that. That test also added a "password" HBA case, where the correct password got pulled from the environment instead of the connection string. Making sure authentication happens is only one part -- we have to ensure authentication takes place using the end user's credentials and not the server's. So since PQconnectionUsedPassword() can't differentiate between "I used your SCRAM key" and "I used a password I found lying around on disk", it's not strong enough for this check. > (Or could we just stick in require_auth=!none to solve this problem once > and for all?) It solves the trust case nicely (and we should maybe consider it for a future simplification?), but not the "wrong credentials were used" case. Thanks! --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-18T19:32:35Z
On 18.03.25 17:53, Jacob Champion wrote: > On Tue, Mar 18, 2025 at 9:35 AM Peter Eisentraut <peter@eisentraut.org> wrote: >> So the way I understand this is that the options are: >> >> (1) We add a libpq function like PQconnectionUsedScramKeys() in the >> style of PQconnectionUsedPassword() and call that function during the >> checks. >> >> (2) We make use_scram_passthrough=true imply require_auth=scram-sha-256. >> This is essentially a way to get the info from (1) out of libpq using >> existing facilities. > > Right. > >> But it would preempt certain setups that might >> otherwise work. (Which ones? Are they important?) > > If the backend HBA later changes, to require delegated GSS or a > different type of password authentication, the user will have to unset > use_scram_passthrough (or ask the owner of the foreign server to unset > it). Whereas before they could just add a password to their user > mapping or enable delegation to move forward immediately. > > I think this is probably not a serious limitation, in practice. Yeah, I think option (2) is enough for now. If someone wants to enable the kinds of things you describe, they can always come back and implement option (1) later.
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-19T19:21:02Z
On Tue, Mar 18, 2025 at 12:32 PM Peter Eisentraut <peter@eisentraut.org> wrote: > Yeah, I think option (2) is enough for now. If someone wants to enable > the kinds of things you describe, they can always come back and > implement option (1) later. Sounds good to me. -- Notes on v8: - The following documentation pieces need to be adjusted, now that we've decided that `use_scram_passthrough` will enforce `require_auth=scram-sha-256`: > + The remote server must request SCRAM authentication. (If desired, > + enforce this on the client side (FDW side) with the option > + <literal>require_auth</literal>.) If another authentication method is > + requested by the server, then that one will be used normally. and > + The user mapping password is not used. (It could be set to support other > + authentication methods, but that would arguably violate the point of this > + feature, which is to avoid storing plain-text passwords.) I think they should just be reduced to "The remote server must request SCRAM authentication." and "The user mapping password is not used." - In get_connect_string(): > + /* first gather the server connstr options */ > + Oid serverid = foreign_server->serverid; I think this comment belongs elsewhere (connect_pg_server) and should be deleted from this block. - Sorry for not realizing this before now, but I couldn't figure out why connect_pg_server() took the rconn pointer, and it turns out it just passes it along to dblink_security_check(), which pfree's it before throwing an error. So that will double-free with the current refactoring patch (and I'm not sure why assertions aren't catching that?). I thought for sure this inconsistency would be a problem on HEAD, but it turns out that rconn is set to NULL in the code path where it would be a bug... How confusing. Now that we handle the pfree() in PG_CATCH instead, that lower-level pfree should be removed, and then connect_pg_server() doesn't need to take an rconn pointer at all. For extra credit you could maybe move the allocation of rconn down below the call to connect_pg_server(), and get rid of the try/catch? > + /* Verify the set of connection parameters. */ > dblink_connstr_check(connstr); > ... > + /* Perform post-connection security checks. */ > dblink_security_check(conn, rconn, connstr); - These comment additions probably belong in 0001 rather than 0002. - As discussed offlist, 0002 needs pgperltidy'd rather than perltidy'd. - I have attached some additional nitpicky comment edits and whitespace changes as a diff; pick and choose as desired. Thanks! --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-20T19:54:08Z
On Wed, Mar 19, 2025 at 4:21 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Tue, Mar 18, 2025 at 12:32 PM Peter Eisentraut <peter@eisentraut.org> wrote: > > Yeah, I think option (2) is enough for now. If someone wants to enable > > the kinds of things you describe, they can always come back and > > implement option (1) later. > > Sounds good to me. Since the security checks are defined I'm attaching 0003 which include the fix of security checks for postgres_fdw. It implements the validations very similar to what are being implemented on dblink. > Notes on v8: > > - The following documentation pieces need to be adjusted, now that > we've decided that `use_scram_passthrough` will enforce > `require_auth=scram-sha-256`: > > > + The remote server must request SCRAM authentication. (If desired, > > + enforce this on the client side (FDW side) with the option > > + <literal>require_auth</literal>.) If another authentication method is > > + requested by the server, then that one will be used normally. > > and > > > + The user mapping password is not used. (It could be set to support other > > + authentication methods, but that would arguably violate the point of this > > + feature, which is to avoid storing plain-text passwords.) > > I think they should just be reduced to "The remote server must request > SCRAM authentication." and "The user mapping password is not used." I've removed the "user mapping password" <listitem> because we already mentioned above that the password is not used and having just "The user mapping password is not used." again seems redundant, what do you think? + ... With SCRAM pass-through + authentication, <filename>dblink_fdw</filename> uses SCRAM-hashed secrets + instead of plain-text user passwords to connect to the remote server. This + avoids storing plain-text user passwords in PostgreSQL system catalogs. > - In get_connect_string(): > > > + /* first gather the server connstr options */ > > + Oid serverid = foreign_server->serverid; > > I think this comment belongs elsewhere (connect_pg_server) and should > be deleted from this block. Removed > - Sorry for not realizing this before now, but I couldn't figure out > why connect_pg_server() took the rconn pointer, and it turns out it > just passes it along to dblink_security_check(), which pfree's it > before throwing an error. So that will double-free with the current > refactoring patch (and I'm not sure why assertions aren't catching > that?). > > I thought for sure this inconsistency would be a problem on HEAD, but > it turns out that rconn is set to NULL in the code path where it would > be a bug... How confusing. > > Now that we handle the pfree() in PG_CATCH instead, that lower-level > pfree should be removed, and then connect_pg_server() doesn't need to > take an rconn pointer at all. For extra credit you could maybe move > the allocation of rconn down below the call to connect_pg_server(), > and get rid of the try/catch? Good catch, thanks, it's much better now! With this change we can also remove the second if (connname) condition. All fixed on attached. > > + /* Verify the set of connection parameters. */ > > dblink_connstr_check(connstr); > > ... > > + /* Perform post-connection security checks. */ > > dblink_security_check(conn, rconn, connstr); > > - These comment additions probably belong in 0001 rather than 0002. Fixed > - As discussed offlist, 0002 needs pgperltidy'd rather than perltidy'd. Fixed > - I have attached some additional nitpicky comment edits and > whitespace changes as a diff; pick and choose as desired. I've squashed into this new version thanks! -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-21T00:02:36Z
On Thu, Mar 20, 2025 at 12:54 PM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > Since the security checks are defined I'm attaching 0003 which include > the fix of security checks for postgres_fdw. It implements the > validations very similar to what are being implemented on dblink. Comments on 0003: > + keywords[n] = "require_auth"; > + values[n] = "scram-sha-256"; > + n++; The keywords and values arrays need to be lengthened for this. > host all all $hostaddr/32 scram-sha-256 > - }); > + } > + ); Accidental diff? A few whitespace and comment tweaks are attached as well. -- > > I think they should just be reduced to "The remote server must request > > SCRAM authentication." and "The user mapping password is not used." > > I've removed the "user mapping password" <listitem> because we already > mentioned above that the password is not used and having just "The user > mapping password is not used." again seems redundant, what do you think? Personally, I think it's still useful to call out that the password in the user mapping is explicitly ignored. The other text motivates the feature, but it doesn't explain how it interacts with existing user mappings (most of which will have passwords). > > Now that we handle the pfree() in PG_CATCH instead, that lower-level > > pfree should be removed, and then connect_pg_server() doesn't need to > > take an rconn pointer at all. For extra credit you could maybe move > > the allocation of rconn down below the call to connect_pg_server(), > > and get rid of the try/catch? > > Good catch, thanks, it's much better now! With this change we can also > remove the second if (connname) condition. All fixed on attached. I like that; the patch is a lot easier to follow now. Thanks, --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-21T15:32:24Z
On Thu, Mar 20, 2025 at 9:02 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > On Thu, Mar 20, 2025 at 12:54 PM Matheus Alcantara > <matheusssilv97@gmail.com> wrote: > > Since the security checks are defined I'm attaching 0003 which include > > the fix of security checks for postgres_fdw. It implements the > > validations very similar to what are being implemented on dblink. > > Comments on 0003: > > > + keywords[n] = "require_auth"; > > + values[n] = "scram-sha-256"; > > + n++; > > The keywords and values arrays need to be lengthened for this. Fixed. I've also changed the code comment to mention the scram keys and required options. > > host all all $hostaddr/32 scram-sha-256 > > - }); > > + } > > + ); > > Accidental diff? Yep, sorry, I made some confusion with dblink formatting. Removed > A few whitespace and comment tweaks are attached as well. Squashed > -- > > > > I think they should just be reduced to "The remote server must request > > > SCRAM authentication." and "The user mapping password is not used." > > > > I've removed the "user mapping password" <listitem> because we already > > mentioned above that the password is not used and having just "The user > > mapping password is not used." again seems redundant, what do you think? > > Personally, I think it's still useful to call out that the password in > the user mapping is explicitly ignored. The other text motivates the > feature, but it doesn't explain how it interacts with existing user > mappings (most of which will have passwords). Fair point. I've changed it to just "The user mapping password is not used". -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Jacob Champion <jacob.champion@enterprisedb.com> — 2025-03-21T16:28:12Z
Great, thank you! Looking over v10, I think I've run out of feedback at this point. Marked Ready for Committer. --Jacob
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-21T18:24:25Z
On Fri, Mar 21, 2025 at 1:28 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > > Great, thank you! Looking over v10, I think I've run out of feedback > at this point. Marked Ready for Committer. Thanks for all the effort reviewing this patch! -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-24T16:16:40Z
On 21.03.25 19:24, Matheus Alcantara wrote: > On Fri, Mar 21, 2025 at 1:28 PM Jacob Champion > <jacob.champion@enterprisedb.com> wrote: >> >> Great, thank you! Looking over v10, I think I've run out of feedback >> at this point. Marked Ready for Committer. > > Thanks for all the effort reviewing this patch! I have committed the 0003 patch (the postgres_fdw bug fix). The dblink feature patch (0002) looks good to me. I'm a bit confused about the refactoring patch 0001. There are some details there that don't seem right. For example, you write that the pfree(rconn) calls are no longer necessary, but AFAICT, it would still be needed in dblink_get_conn(). Also, there appear to be some possible behavior changes, or at least it's not fully explained, like connect_pg_server() doing foreign-server name resolution, which dblink_get_conn() did not do before. But it's actually not clear to me how the refactoring in 0001 contributes to making the patch 0002 better, since patch 0002 barely touches the code touched by 0001. How would patch 0002 look without 0001 before it? Which code would need to be duplicated or what other awkward changes are you trying to avoid?
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-24T20:33:26Z
On Mon, Mar 24, 2025 at 1:16 PM Peter Eisentraut <peter@eisentraut.org> wrote: > > On 21.03.25 19:24, Matheus Alcantara wrote: > > On Fri, Mar 21, 2025 at 1:28 PM Jacob Champion > > <jacob.champion@enterprisedb.com> wrote: > >> > >> Great, thank you! Looking over v10, I think I've run out of feedback > >> at this point. Marked Ready for Committer. > > > > Thanks for all the effort reviewing this patch! > > I have committed the 0003 patch (the postgres_fdw bug fix). Thanks! > I'm a bit confused about the refactoring patch 0001. There are some > details there that don't seem right. For example, you write that the > pfree(rconn) calls are no longer necessary, but AFAICT, it would still > be needed in dblink_get_conn(). Also, there appear to be some possible > behavior changes, or at least it's not fully explained, like > connect_pg_server() doing foreign-server name resolution, which > dblink_get_conn() did not do before. > > But it's actually not clear to me how the refactoring in 0001 > contributes to making the patch 0002 better, since patch 0002 barely > touches the code touched by 0001. > > How would patch 0002 look without 0001 before it? Which code would need > to be duplicated or what other awkward changes are you trying to avoid? You are right, I think that the refactor was needed on the initial versions of the patch because it was referencing the UseScramPassthrough function in multiple places, so the refactor was needed to accomplish the parameters of the function. Since we now assume that the UseScramPassthrough is already checked on some parts of the code I agree that this refactor is not required anymore. Attached v11 without the refactor patch. Thanks! -- Matheus Alcantara
-
Re: dblink: Add SCRAM pass-through authentication
Peter Eisentraut <peter@eisentraut.org> — 2025-03-26T10:41:18Z
On 24.03.25 21:33, Matheus Alcantara wrote: >> I'm a bit confused about the refactoring patch 0001. There are some >> details there that don't seem right. For example, you write that the >> pfree(rconn) calls are no longer necessary, but AFAICT, it would still >> be needed in dblink_get_conn(). Also, there appear to be some possible >> behavior changes, or at least it's not fully explained, like >> connect_pg_server() doing foreign-server name resolution, which >> dblink_get_conn() did not do before. >> >> But it's actually not clear to me how the refactoring in 0001 >> contributes to making the patch 0002 better, since patch 0002 barely >> touches the code touched by 0001. >> >> How would patch 0002 look without 0001 before it? Which code would need >> to be duplicated or what other awkward changes are you trying to avoid? > You are right, I think that the refactor was needed on the initial > versions of the patch because it was referencing the UseScramPassthrough > function in multiple places, so the refactor was needed to accomplish the > parameters of the function. > > Since we now assume that the UseScramPassthrough is already checked on > some parts of the code I agree that this refactor is not required > anymore. Attached v11 without the refactor patch. Committed. I cut down the documentation a bit and instead linked to postgres_fdw for some of the details. I think that's better than having to maintain that text in two different places.
-
Re: dblink: Add SCRAM pass-through authentication
Matheus Alcantara <matheusssilv97@gmail.com> — 2025-03-26T11:39:05Z
On Wed, Mar 26, 2025 at 7:41 AM Peter Eisentraut <peter@eisentraut.org> wrote: > > On 24.03.25 21:33, Matheus Alcantara wrote: > >> I'm a bit confused about the refactoring patch 0001. There are some > >> details there that don't seem right. For example, you write that the > >> pfree(rconn) calls are no longer necessary, but AFAICT, it would still > >> be needed in dblink_get_conn(). Also, there appear to be some possible > >> behavior changes, or at least it's not fully explained, like > >> connect_pg_server() doing foreign-server name resolution, which > >> dblink_get_conn() did not do before. > >> > >> But it's actually not clear to me how the refactoring in 0001 > >> contributes to making the patch 0002 better, since patch 0002 barely > >> touches the code touched by 0001. > >> > >> How would patch 0002 look without 0001 before it? Which code would need > >> to be duplicated or what other awkward changes are you trying to avoid? > > You are right, I think that the refactor was needed on the initial > > versions of the patch because it was referencing the UseScramPassthrough > > function in multiple places, so the refactor was needed to accomplish the > > parameters of the function. > > > > Since we now assume that the UseScramPassthrough is already checked on > > some parts of the code I agree that this refactor is not required > > anymore. Attached v11 without the refactor patch. > > Committed. > > I cut down the documentation a bit and instead linked to postgres_fdw > for some of the details. I think that's better than having to maintain > that text in two different places. Thanks! -- Matheus Alcantara