1919#include "access/xact.h"
2020#include "catalog/pg_user_mapping.h"
2121#include "commands/defrem.h"
22+ #include "common/base64.h"
2223#include "funcapi.h"
2324#include "libpq/libpq-be.h"
2425#include "libpq/libpq-be-fe-helpers.h"
@@ -177,6 +178,7 @@ static void pgfdw_finish_abort_cleanup(List *pending_entries,
177178static void pgfdw_security_check (const char * * keywords , const char * * values ,
178179 UserMapping * user , PGconn * conn );
179180static bool UserMappingPasswordRequired (UserMapping * user );
181+ static bool UseScramPassthrough (ForeignServer * server , UserMapping * user );
180182static bool disconnect_cached_connections (Oid serverid );
181183static void postgres_fdw_get_connections_internal (FunctionCallInfo fcinfo ,
182184 enum pgfdwVersion api_version );
@@ -485,7 +487,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
485487 * for application_name, fallback_application_name, client_encoding,
486488 * end marker.
487489 */
488- n = list_length (server -> options ) + list_length (user -> options ) + 4 ;
490+ n = list_length (server -> options ) + list_length (user -> options ) + 4 + 2 ;
489491 keywords = (const char * * ) palloc (n * sizeof (char * ));
490492 values = (const char * * ) palloc (n * sizeof (char * ));
491493
@@ -554,10 +556,37 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
554556 values [n ] = GetDatabaseEncodingName ();
555557 n ++ ;
556558
559+ if (MyProcPort -> has_scram_keys && UseScramPassth
402E
rough (server , user ))
560+ {
561+ int len ;
562+
563+ keywords [n ] = "scram_client_key" ;
564+ len = pg_b64_enc_len (sizeof (MyProcPort -> scram_ClientKey ));
565+ /* don't forget the zero-terminator */
566+ values [n ] = palloc0 (len + 1 );
567+ pg_b64_encode ((const char * ) MyProcPort -> scram_ClientKey ,
568+ sizeof (MyProcPort -> scram_ClientKey ),
569+ (char * ) values [n ], len );
570+ n ++ ;
571+
572+ keywords [n ] = "scram_server_key" ;
573+ len = pg_b64_enc_len (sizeof (MyProcPort -> scram_ServerKey ));
574+ /* don't forget the zero-terminator */
575+ values [n ] = palloc0 (len + 1 );
576+ pg_b64_encode ((const char * ) MyProcPort -> scram_ServerKey ,
577+ sizeof (MyProcPort -> scram_ServerKey ),
578+ (char * ) values [n ], len );
579+ n ++ ;
580+ }
581+
557582 keywords [n ] = values [n ] = NULL ;
558583
559- /* verify the set of connection parameters */
560- check_conn_params (keywords , values , user );
584+ /*
585+ * Verify the set of connection parameters only if scram pass-through
586+ * is not being used because the password is not necessary.
587+ */
588+ if (!(MyProcPort -> has_scram_keys && UseScramPassthrough (server , user )))
589+ check_conn_params (keywords , values , user );
561590
562591 /* first time, allocate or get the custom wait event */
563592 if (pgfdw_we_connect == 0 )
@@ -575,8 +604,12 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
575604 server -> servername ),
576605 errdetail_internal ("%s" , pchomp (PQerrorMessage (conn )))));
577606
578- /* Perform post-connection security checks */
579- pgfdw_security_check (keywords , values , user , conn );
607+ /*
608+ * Perform post-connection security checks only if scram pass-through
609+ * is not being used because the password is not necessary.
610+ */
611+ if (!(MyProcPort -> has_scram_keys && UseScramPassthrough (server , user )))
612+ pgfdw_security_check (keywords , values , user , conn );
580613
581614 /* Prepare new session for use */
582615 configure_remote_session (conn );
@@ -629,6 +662,30 @@ UserMappingPasswordRequired(UserMapping *user)
629662 return true;
630663}
631664
665+ static bool
666+ UseScramPassthrough (ForeignServer * server , UserMapping * user )
667+ {
668+ ListCell * cell ;
669+
670+ foreach (cell , server -> options )
671+ {
672+ DefElem * def = (DefElem * ) lfirst (cell );
673+
674+ if (strcmp (def -> defname , "use_scram_passthrough" ) == 0 )
675+ return defGetBoolean (def );
676+ }
677+
678+ foreach (cell , user -> options )
679+ {
680+ DefElem * def = (DefElem * ) lfirst (cell );
681+
682+ if (strcmp (def -> defname , "use_scram_passthrough" ) == 0 )
683+ return defGetBoolean (def );
684+ }
685+
686+ return false;
687+ }
688+
632689/*
633690 * For non-superusers, insist that the connstr specify a password or that the
634691 * user provided their own GSSAPI delegated credentials. This
@@ -666,7 +723,7 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
666723 ereport (ERROR ,
667724 (errcode (ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED ),
668725 errmsg ("password or GSSAPI delegated credentials required" ),
669- errdetail ("Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping." )));
726+ errdetail ("Non-superusers must delegate GSSAPI credentials, provide a password, or enable SCRAM pass-through in user mapping." )));
670727}
671728
672729/*
0 commit comments