Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3d4fa22

Browse files
committed
Add support for Kerberos credential delegation
Support GSSAPI/Kerberos credentials being delegated to the server by aclient. With this, a user authenticating to PostgreSQL using Kerberos(GSSAPI) credentials can choose to delegate their credentials to thePostgreSQL server (which can choose to accept them, or not), allowingthe server to then use those delegated credentials to connect toanother service, such as with postgres_fdw or dblink or theoreticallyany other service which is able to be authenticated using Kerberos.Both postgres_fdw and dblink are changed to allow non-superuserpassword-less connections but only when GSSAPI credentials have beendelegated to the server by the client and GSSAPI is used toauthenticate to the remote system.Authors: Stephen Frost, Peifeng QiuReviewed-By: David ChristensenDiscussion:https://postgr.es/m/CO1PR05MB8023CC2CB575E0FAAD7DF4F8A8E29@CO1PR05MB8023.namprd05.prod.outlook.com
1 parentedc627a commit3d4fa22

36 files changed

+755
-136
lines changed

‎contrib/dblink/dblink.c

Lines changed: 82 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include"funcapi.h"
4949
#include"lib/stringinfo.h"
5050
#include"libpq-fe.h"
51+
#include"libpq/libpq-be.h"
5152
#include"libpq/libpq-be-fe-helpers.h"
5253
#include"mb/pg_wchar.h"
5354
#include"miscadmin.h"
@@ -111,7 +112,8 @@ static HeapTuple get_tuple_of_interest(Relation rel, int *pkattnums, int pknumat
111112
staticRelationget_rel_from_relname(text*relname_text,LOCKMODElockmode,AclModeaclmode);
112113
staticchar*generate_relation_name(Relationrel);
113114
staticvoiddblink_connstr_check(constchar*connstr);
114-
staticvoiddblink_security_check(PGconn*conn,remoteConn*rconn);
115+
staticbooldblink_connstr_has_pw(constchar*connstr);
116+
staticvoiddblink_security_check(PGconn*conn,remoteConn*rconn,constchar*connstr);
115117
staticvoiddblink_res_error(PGconn*conn,constchar*conname,PGresult*res,
116118
boolfail,constchar*fmt,...)pg_attribute_printf(5,6);
117119
staticchar*get_connect_string(constchar*servername);
@@ -213,7 +215,7 @@ dblink_get_conn(char *conname_or_str,
213215
errmsg("could not establish connection"),
214216
errdetail_internal("%s",msg)));
215217
}
216-
dblink_security_check(conn,rconn);
218+
dblink_security_check(conn,rconn,connstr);
217219
if (PQclientEncoding(conn)!=GetDatabaseEncoding())
218220
PQsetClientEncoding(conn,GetDatabaseEncodingName());
219221
freeconn= true;
@@ -307,7 +309,7 @@ dblink_connect(PG_FUNCTION_ARGS)
307309
}
308310

309311
/* check password actually used if not superuser */
310-
dblink_security_check(conn,rconn);
312+
dblink_security_check(conn,rconn,connstr);
311313

312314
/* attempt to set client encoding to match server encoding, if needed */
313315
if (PQclientEncoding(conn)!=GetDatabaseEncoding())
@@ -2584,64 +2586,99 @@ deleteConnection(const char *name)
25842586
errmsg("undefined connection name")));
25852587
}
25862588

2589+
/*
2590+
* We need to make sure that the connection made used credentials
2591+
* which were provided by the user, so check what credentials were
2592+
* used to connect and then make sure that they came from the user.
2593+
*/
25872594
staticvoid
2588-
dblink_security_check(PGconn*conn,remoteConn*rconn)
2595+
dblink_security_check(PGconn*conn,remoteConn*rconn,constchar*connstr)
25892596
{
2590-
if (!superuser())
2591-
{
2592-
if (!PQconnectionUsedPassword(conn))
2593-
{
2594-
libpqsrv_disconnect(conn);
2595-
if (rconn)
2596-
pfree(rconn);
2597+
/* Superuser bypasses security check */
2598+
if (superuser())
2599+
return;
25972600

2598-
ereport(ERROR,
2599-
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
2600-
errmsg("password is required"),
2601-
errdetail("Non-superuser cannot connect if the server does not request a password."),
2602-
errhint("Target server's authentication method must be changed.")));
2603-
}
2604-
}
2601+
/* If password was used to connect, make sure it was one provided */
2602+
if (PQconnectionUsedPassword(conn)&&dblink_connstr_has_pw(connstr))
2603+
return;
2604+
2605+
#ifdefENABLE_GSS
2606+
/* If GSSAPI creds used to connect, make sure it was one delegated */
2607+
if (PQconnectionUsedGSSAPI(conn)&&be_gssapi_get_deleg(MyProcPort))
2608+
return;
2609+
#endif
2610+
2611+
/* Otherwise, fail out */
2612+
libpqsrv_disconnect(conn);
2613+
if (rconn)
2614+
pfree(rconn);
2615+
2616+
ereport(ERROR,
2617+
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
2618+
errmsg("password or GSSAPI delegated credentials required"),
2619+
errdetail("Non-superusers may only connect using credentials they provide, eg: password in connection string or delegated GSSAPI credentials"),
2620+
errhint("Ensure provided credentials match target server's authentication method.")));
26052621
}
26062622

26072623
/*
2608-
*For non-superusers, insist that theconnstr specify a password. This
2609-
*prevents apassword from being picked up from .pgpass, a service file,
2610-
*the environment, etc. We don't want the postgres user's passwords
2611-
*to be accessible to non-superusers.
2624+
*Function to check if theconnection string includes an explicit
2625+
* password, needed to ensure that non-superuser password-based auth
2626+
*is using a provided password and not one picked up from the
2627+
*environment.
26122628
*/
2613-
staticvoid
2614-
dblink_connstr_check(constchar*connstr)
2629+
staticbool
2630+
dblink_connstr_has_pw(constchar*connstr)
26152631
{
2616-
if (!superuser())
2617-
{
2618-
PQconninfoOption*options;
2619-
PQconninfoOption*option;
2620-
boolconnstr_gives_password= false;
2632+
PQconninfoOption*options;
2633+
PQconninfoOption*option;
2634+
boolconnstr_gives_password= false;
26212635

2622-
options=PQconninfoParse(connstr,NULL);
2623-
if (options)
2636+
options=PQconninfoParse(connstr,NULL);
2637+
if (options)
2638+
{
2639+
for (option=options;option->keyword!=NULL;option++)
26242640
{
2625-
for (option=options;option->keyword!=NULL;option++)
2641+
if (strcmp(option->keyword,"password")==0)
26262642
{
2627-
if (strcmp(option->keyword,"password")==0)
2643+
if (option->val!=NULL&&option->val[0]!='\0')
26282644
{
2629-
if (option->val!=NULL&&option->val[0]!='\0')
2630-
{
2631-
connstr_gives_password= true;
2632-
break;
2633-
}
2645+
connstr_gives_password= true;
2646+
break;
26342647
}
26352648
}
2636-
PQconninfoFree(options);
26372649
}
2638-
2639-
if (!connstr_gives_password)
2640-
ereport(ERROR,
2641-
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
2642-
errmsg("password is required"),
2643-
errdetail("Non-superusers must provide a password in the connection string.")));
2650+
PQconninfoFree(options);
26442651
}
2652+
2653+
returnconnstr_gives_password;
2654+
}
2655+
2656+
/*
2657+
* For non-superusers, insist that the connstr specify a password, except
2658+
* if GSSAPI credentials have been delegated (and we check that they are used
2659+
* for the connection in dblink_security_check later). This prevents a
2660+
* password or GSSAPI credentials from being picked up from .pgpass, a
2661+
* service file, the environment, etc. We don't want the postgres user's
2662+
* passwords or Kerberos credentials to be accessible to non-superusers.
2663+
*/
2664+
staticvoid
2665+
dblink_connstr_check(constchar*connstr)
2666+
{
2667+
if (superuser())
2668+
return;
2669+
2670+
if (dblink_connstr_has_pw(connstr))
2671+
return;
2672+
2673+
#ifdefENABLE_GSS
2674+
if (be_gssapi_get_deleg(MyProcPort))
2675+
return;
2676+
#endif
2677+
2678+
ereport(ERROR,
2679+
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
2680+
errmsg("password or GSSAPI delegated credentials required"),
2681+
errdetail("Non-superusers must provide a password in the connection string or send delegated GSSAPI credentials.")));
26452682
}
26462683

26472684
/*

‎contrib/dblink/expected/dblink.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,8 +903,8 @@ GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO regress_dblink_user;
903903
SET SESSION AUTHORIZATION regress_dblink_user;
904904
-- should fail
905905
SELECT dblink_connect('myconn', 'fdtest');
906-
ERROR: passwordis required
907-
DETAIL: Non-superusers must provide a password in the connection string.
906+
ERROR: passwordor GSSAPI delegated credentials required
907+
DETAIL: Non-superusers must provide a password in the connection string or send delegated GSSAPI credentials.
908908
-- should succeed
909909
SELECT dblink_connect_u('myconn', 'fdtest');
910910
dblink_connect_u

‎contrib/postgres_fdw/connection.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include"catalog/pg_user_mapping.h"
1818
#include"commands/defrem.h"
1919
#include"funcapi.h"
20+
#include"libpq/libpq-be.h"
2021
#include"libpq/libpq-be-fe-helpers.h"
2122
#include"mb/pg_wchar.h"
2223
#include"miscadmin.h"
@@ -149,6 +150,8 @@ static void pgfdw_finish_pre_subcommit_cleanup(List *pending_entries,
149150
staticvoidpgfdw_finish_abort_cleanup(List*pending_entries,
150151
List*cancel_requested,
151152
booltoplevel);
153+
staticvoidpgfdw_security_check(constchar**keywords,constchar**values,
154+
UserMapping*user,PGconn*conn);
152155
staticboolUserMappingPasswordRequired(UserMapping*user);
153156
staticbooldisconnect_cached_connections(Oidserverid);
154157

@@ -384,6 +387,47 @@ make_new_connection(ConnCacheEntry *entry, UserMapping *user)
384387
entry->conn,server->servername,user->umid,user->userid);
385388
}
386389

390+
/*
391+
* Check that non-superuser has used password or delegated credentials
392+
* to establish connection; otherwise, he's piggybacking on the
393+
* postgres server's user identity. See also dblink_security_check()
394+
* in contrib/dblink and check_conn_params.
395+
*/
396+
staticvoid
397+
pgfdw_security_check(constchar**keywords,constchar**values,UserMapping*user,PGconn*conn)
398+
{
399+
/* Superusers bypass the check */
400+
if (superuser_arg(user->userid))
401+
return;
402+
403+
#ifdefENABLE_GSS
404+
/* Connected via GSSAPI with delegated credentials- all good. */
405+
if (PQconnectionUsedGSSAPI(conn)&&be_gssapi_get_deleg(MyProcPort))
406+
return;
407+
#endif
408+
409+
/* Ok if superuser set PW required false. */
410+
if (!UserMappingPasswordRequired(user))
411+
return;
412+
413+
/* Connected via PW, with PW required true, and provided non-empty PW. */
414+
if (PQconnectionUsedPassword(conn))
415+
{
416+
/* ok if params contain a non-empty password */
417+
for (inti=0;keywords[i]!=NULL;i++)
418+
{
419+
if (strcmp(keywords[i],"password")==0&&values[i][0]!='\0')
420+
return;
421+
}
422+
}
423+
424+
ereport(ERROR,
425+
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
426+
errmsg("password or GSSAPI delegated credentials required"),
427+
errdetail("Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials."),
428+
errhint("Target server's authentication method must be changed or password_required=false set in the user mapping attributes.")));
429+
}
430+
387431
/*
388432
* Connect to remote server using specified server and user mapping properties.
389433
*/
@@ -495,19 +539,8 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
495539
server->servername),
496540
errdetail_internal("%s",pchomp(PQerrorMessage(conn)))));
497541

498-
/*
499-
* Check that non-superuser has used password to establish connection;
500-
* otherwise, he's piggybacking on the postgres server's user
501-
* identity. See also dblink_security_check() in contrib/dblink and
502-
* check_conn_params.
503-
*/
504-
if (!superuser_arg(user->userid)&&UserMappingPasswordRequired(user)&&
505-
!PQconnectionUsedPassword(conn))
506-
ereport(ERROR,
507-
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
508-
errmsg("password is required"),
509-
errdetail("Non-superuser cannot connect if the server does not request a password."),
510-
errhint("Target server's authentication method must be changed or password_required=false set in the user mapping attributes.")));
542+
/* Perform post-connection security checks */
543+
pgfdw_security_check(keywords,values,user,conn);
511544

512545
/* Prepare new session for use */
513546
configure_remote_session(conn);
@@ -561,7 +594,8 @@ UserMappingPasswordRequired(UserMapping *user)
561594
}
562595

563596
/*
564-
* For non-superusers, insist that the connstr specify a password. This
597+
* For non-superusers, insist that the connstr specify a password or that the
598+
* user provided their own GSSAPI delegated credentials. This
565599
* prevents a password from being picked up from .pgpass, a service file, the
566600
* environment, etc. We don't want the postgres user's passwords,
567601
* certificates, etc to be accessible to non-superusers. (See also
@@ -576,6 +610,12 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
576610
if (superuser_arg(user->userid))
577611
return;
578612

613+
#ifdefENABLE_GSS
614+
/* ok if the user provided their own delegated credentials */
615+
if (be_gssapi_get_deleg(MyProcPort))
616+
return;
617+
#endif
618+
579619
/* ok if params contain a non-empty password */
580620
for (i=0;keywords[i]!=NULL;i++)
581621
{
@@ -589,8 +629,8 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
589629

590630
ereport(ERROR,
591631
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
592-
errmsg("passwordis required"),
593-
errdetail("Non-superusers must provide a password in the user mapping.")));
632+
errmsg("passwordor GSSAPI delegated credentials required"),
633+
errdetail("Non-superusers mustdelegate GSSAPI credentials orprovide a password in the user mapping.")));
594634
}
595635

596636
/*

‎contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ ALTER SERVER testserver1 OPTIONS (
171171
sslcrl 'value',
172172
--requirepeer 'value',
173173
krbsrvname 'value',
174-
gsslib 'value'
174+
gsslib 'value',
175+
gssdeleg 'value'
175176
--replication 'value'
176177
);
177178
-- Error, invalid list syntax
@@ -9840,8 +9841,8 @@ CREATE FOREIGN TABLE pg_temp.ft1_nopw (
98409841
c8 user_enum
98419842
) SERVER loopback_nopw OPTIONS (schema_name 'public', table_name 'ft1');
98429843
SELECT 1 FROM ft1_nopw LIMIT 1;
9843-
ERROR: passwordis required
9844-
DETAIL: Non-superusers must provide a password in the user mapping.
9844+
ERROR: passwordor GSSAPI delegated credentials required
9845+
DETAIL: Non-superusers mustdelegate GSSAPI credentials orprovide a password in the user mapping.
98459846
-- If we add a password to the connstr it'll fail, because we don't allow passwords
98469847
-- in connstrs only in user mappings.
98479848
ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
@@ -9853,16 +9854,16 @@ HINT: Perhaps you meant the option "passfile".
98539854
-- This won't work with installcheck, but neither will most of the FDW checks.
98549855
ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
98559856
SELECT 1 FROM ft1_nopw LIMIT 1;
9856-
ERROR: passwordis required
9857-
DETAIL: Non-superuser cannot connect if the server does not request a password.
9857+
ERROR: passwordor GSSAPI delegated credentials required
9858+
DETAIL: Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
98589859
HINT: Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
98599860
-- Unpriv user cannot make the mapping passwordless
98609861
ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password_required 'false');
98619862
ERROR: password_required=false is superuser-only
98629863
HINT: User mappings with the password_required option set to false may only be created or modified by the superuser.
98639864
SELECT 1 FROM ft1_nopw LIMIT 1;
9864-
ERROR: passwordis required
9865-
DETAIL: Non-superuser cannot connect if the server does not request a password.
9865+
ERROR: passwordor GSSAPI delegated credentials required
9866+
DETAIL: Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
98669867
HINT: Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
98679868
RESET ROLE;
98689869
-- But the superuser can
@@ -9890,8 +9891,8 @@ DROP USER MAPPING FOR CURRENT_USER SERVER loopback_nopw;
98909891
-- This will fail again as it'll resolve the user mapping for public, which
98919892
-- lacks password_required=false
98929893
SELECT 1 FROM ft1_nopw LIMIT 1;
9893-
ERROR: passwordis required
9894-
DETAIL: Non-superusers must provide a password in the user mapping.
9894+
ERROR: passwordor GSSAPI delegated credentials required
9895+
DETAIL: Non-superusers mustdelegate GSSAPI credentials orprovide a password in the user mapping.
98959896
RESET ROLE;
98969897
-- The user mapping for public is passwordless and lacks the password_required=false
98979898
-- mapping option, but will work because the current user is a superuser.

‎contrib/postgres_fdw/option.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,12 @@ InitPgFdwOptions(void)
288288
{"sslcert",UserMappingRelationId, true},
289289
{"sslkey",UserMappingRelationId, true},
290290

291+
/*
292+
* gssdeleg is also a libpq option but should be allowed in a user
293+
* mapping context too
294+
*/
295+
{"gssdeleg",UserMappingRelationId, true},
296+
291297
{NULL,InvalidOid, false}
292298
};
293299

‎contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ ALTER SERVER testserver1 OPTIONS (
185185
sslcrl'value',
186186
--requirepeer 'value',
187187
krbsrvname'value',
188-
gsslib'value'
188+
gsslib'value',
189+
gssdeleg'value'
189190
--replication 'value'
190191
);
191192

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp