aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/postgres_fdw/connection.c')
-rw-r--r--contrib/postgres_fdw/connection.c102
1 files changed, 88 insertions, 14 deletions
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 8ef9702c05c..9fa7f7e95cd 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -184,6 +184,7 @@ static void postgres_fdw_get_connections_internal(FunctionCallInfo fcinfo,
enum pgfdwVersion api_version);
static int pgfdw_conn_check(PGconn *conn);
static bool pgfdw_conn_checkable(void);
+static bool pgfdw_has_required_scram_options(const char **keywords, const char **values);
/*
* Get a PGconn which can be used to execute queries on the remote PostgreSQL
@@ -455,6 +456,15 @@ pgfdw_security_check(const char **keywords, const char **values, UserMapping *us
}
}
+ /*
+ * Ok if SCRAM pass-through is being used and all required SCRAM options
+ * are set correctly. If pgfdw_has_required_scram_options returns true we
+ * assume that UseScramPassthrough is also true since SCRAM options are
+ * only set when UseScramPassthrough is enabled.
+ */
+ if (MyProcPort->has_scram_keys && pgfdw_has_required_scram_options(keywords, values))
+ return;
+
ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
errmsg("password or GSSAPI delegated credentials required"),
@@ -485,9 +495,10 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
* and UserMapping. (Some of them might not be libpq options, in
* which case we'll just waste a few array slots.) Add 4 extra slots
* for application_name, fallback_application_name, client_encoding,
- * end marker.
+ * end marker, and 3 extra slots for scram keys and required scram
+ * pass-through options.
*/
- n = list_length(server->options) + list_length(user->options) + 4 + 2;
+ n = list_length(server->options) + list_length(user->options) + 4 + 3;
keywords = (const char **) palloc(n * sizeof(char *));
values = (const char **) palloc(n * sizeof(char *));
@@ -556,6 +567,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
values[n] = GetDatabaseEncodingName();
n++;
+ /* Add required SCRAM pass-through connection options if it's enabled. */
if (MyProcPort->has_scram_keys && UseScramPassthrough(server, user))
{
int len;
@@ -582,16 +594,20 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
if (encoded_len < 0)
elog(ERROR, "could not encode SCRAM server key");
n++;
+
+ /*
+ * Require scram-sha-256 to ensure that no other auth method is
+ * used when connecting with foreign server.
+ */
+ keywords[n] = "require_auth";
+ values[n] = "scram-sha-256";
+ n++;
}
keywords[n] = values[n] = NULL;
- /*
- * Verify the set of connection parameters only if scram pass-through
- * is not being used because the password is not necessary.
- */
- if (!(MyProcPort->has_scram_keys && UseScramPassthrough(server, user)))
- check_conn_params(keywords, values, user);
+ /* Verify the set of connection parameters. */
+ check_conn_params(keywords, values, user);
/* first time, allocate or get the custom wait event */
if (pgfdw_we_connect == 0)
@@ -609,12 +625,8 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
server->servername),
errdetail_internal("%s", pchomp(PQerrorMessage(conn)))));
- /*
- * 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);
+ /* Perform post-connection security checks. */
+ pgfdw_security_check(keywords, values, user, conn);
/* Prepare new session for use */
configure_remote_session(conn);
@@ -725,6 +737,15 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
if (!UserMappingPasswordRequired(user))
return;
+ /*
+ * Ok if SCRAM pass-through is being used and all required scram options
+ * are set correctly. If pgfdw_has_required_scram_options returns true we
+ * assume that UseScramPassthrough is also true since SCRAM options are
+ * only set when UseScramPassthrough is enabled.
+ */
+ if (MyProcPort->has_scram_keys && pgfdw_has_required_scram_options(keywords, values))
+ return;
+
ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
errmsg("password or GSSAPI delegated credentials required"),
@@ -2487,3 +2508,56 @@ pgfdw_conn_checkable(void)
return false;
#endif
}
+
+/*
+ * Ensure that require_auth and SCRAM keys are correctly set on values. SCRAM
+ * keys used to pass-through are coming from the initial connection from the
+ * client with the server.
+ *
+ * All required SCRAM options are set by postgres_fdw, so we just need to
+ * ensure that these options are not overwritten by the user.
+ */
+static bool
+pgfdw_has_required_scram_options(const char **keywords, const char **values)
+{
+ bool has_scram_server_key = false;
+ bool has_scram_client_key = false;
+ bool has_require_auth = false;
+ bool has_scram_keys = false;
+
+ /*
+ * Continue iterating even if we found the keys that we need to validate
+ * to make sure that there is no other declaration of these keys that can
+ * overwrite the first.
+ */
+ for (int i = 0; keywords[i] != NULL; i++)
+ {
+ if (strcmp(keywords[i], "scram_client_key") == 0)
+ {
+ if (values[i] != NULL && values[i][0] != '\0')
+ has_scram_client_key = true;
+ else
+ has_scram_client_key = false;
+ }
+
+ if (strcmp(keywords[i], "scram_server_key") == 0)
+ {
+ if (values[i] != NULL && values[i][0] != '\0')
+ has_scram_server_key = true;
+ else
+ has_scram_server_key = false;
+ }
+
+ if (strcmp(keywords[i], "require_auth") == 0)
+ {
+ if (values[i] != NULL && strcmp(values[i], "scram-sha-256") == 0)
+ has_require_auth = true;
+ else
+ has_require_auth = false;
+ }
+ }
+
+ has_scram_keys = has_scram_client_key && has_scram_server_key && MyProcPort->has_scram_keys;
+
+ return (has_scram_keys && has_require_auth);
+}