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

Commitf8d8581

Browse files
require_auth: prepare for multiple SASL mechanisms
Prior to this patch, the require_auth implementation assumed thatthe AuthenticationSASL protocol message was using SCRAM-SHA-256.In preparation for future SASL mechanisms, like OAUTHBEARER, splitthe implementation into two tiers: the first checks the acceptableAUTH_REQ_* codes, and the second checks acceptable mechanisms ifAUTH_REQ_SASL et.al are permitted.conn->allowed_sasl_mechs contains a list of pointers to acceptablemechanisms, and pg_SASL_init() will bail if the selected mechanismisn't contained in this array.Since there's only one mechansism supported right now, one branchof the second tier cannot be exercised yet and is protected by anAssert(false) call. This assertion will need to be removed whenthe next mechanism is added.This patch is extracted from a larger body of work aimed at addingsupport for OAUTHBEARER in libpq.Author: Jacob Champion <jacob.champion@enterprisedb.com>Reviewed-by: Daniel Gustafsson <daniel@yesql.se>Reviewed-by: Peter Eisentraut <peter@eisentraut.org>Discussion:https://postgr.es/m/CAOYmi+kJqzo6XsR9TEhvVfeVNQ-TyFM5LATypm9yoQVYk=4Wrw@mail.gmail.com
1 parente21d6f2 commitf8d8581

File tree

4 files changed

+208
-17
lines changed

4 files changed

+208
-17
lines changed

‎src/interfaces/libpq/fe-auth.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,35 @@ pg_SASL_init(PGconn *conn, int payloadlen)
543543
gotoerror;
544544
}
545545

546+
/* Make sure require_auth is satisfied. */
547+
if (conn->require_auth)
548+
{
549+
boolallowed= false;
550+
551+
for (inti=0;i<lengthof(conn->allowed_sasl_mechs);i++)
552+
{
553+
if (conn->sasl==conn->allowed_sasl_mechs[i])
554+
{
555+
allowed= true;
556+
break;
557+
}
558+
}
559+
560+
if (!allowed)
561+
{
562+
/*
563+
* TODO: this is dead code until a second SASL mechanism is added;
564+
* the connection can't have proceeded past check_expected_areq()
565+
* if no SASL methods are allowed.
566+
*/
567+
Assert(false);
568+
569+
libpq_append_conn_error(conn,"authentication method requirement \"%s\" failed: server requested %s authentication",
570+
conn->require_auth,selected_mechanism);
571+
gotoerror;
572+
}
573+
}
574+
546575
if (conn->channel_binding[0]=='r'&&/* require */
547576
strcmp(selected_mechanism,SCRAM_SHA_256_PLUS_NAME)!=0)
548577
{

‎src/interfaces/libpq/fe-connect.c

Lines changed: 167 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ static const PQEnvironmentOption EnvironmentOptions[] =
396396
}
397397
};
398398

399+
staticconstpg_fe_sasl_mech*supported_sasl_mechs[]=
400+
{
401+
&pg_scram_mech,
402+
};
403+
#defineSASL_MECHANISM_COUNT lengthof(supported_sasl_mechs)
404+
399405
/* The connection URI must start with either of the following designators: */
400406
staticconstcharuri_designator[]="postgresql://";
401407
staticconstcharshort_uri_designator[]="postgres://";
@@ -1117,6 +1123,57 @@ libpq_prng_init(PGconn *conn)
11171123
pg_prng_seed(&conn->prng_state,rseed);
11181124
}
11191125

1126+
/*
1127+
* Fills the connection's allowed_sasl_mechs list with all supported SASL
1128+
* mechanisms.
1129+
*/
1130+
staticinlinevoid
1131+
fill_allowed_sasl_mechs(PGconn*conn)
1132+
{
1133+
/*---
1134+
* We only support one mechanism at the moment, so rather than deal with a
1135+
* linked list, conn->allowed_sasl_mechs is an array of static length. We
1136+
* rely on the compile-time assertion here to keep us honest.
1137+
*
1138+
* To add a new mechanism to require_auth,
1139+
* - add it to supported_sasl_mechs,
1140+
* - update the length of conn->allowed_sasl_mechs,
1141+
* - handle the new mechanism name in the require_auth portion of
1142+
* pqConnectOptions2(), below.
1143+
*/
1144+
StaticAssertDecl(lengthof(conn->allowed_sasl_mechs)==SASL_MECHANISM_COUNT,
1145+
"conn->allowed_sasl_mechs[] is not sufficiently large for holding all supported SASL mechanisms");
1146+
1147+
for (inti=0;i<SASL_MECHANISM_COUNT;i++)
1148+
conn->allowed_sasl_mechs[i]=supported_sasl_mechs[i];
1149+
}
1150+
1151+
/*
1152+
* Clears the connection's allowed_sasl_mechs list.
1153+
*/
1154+
staticinlinevoid
1155+
clear_allowed_sasl_mechs(PGconn*conn)
1156+
{
1157+
for (inti=0;i<lengthof(conn->allowed_sasl_mechs);i++)
1158+
conn->allowed_sasl_mechs[i]=NULL;
1159+
}
1160+
1161+
/*
1162+
* Helper routine that searches the static allowed_sasl_mechs list for a
1163+
* specific mechanism.
1164+
*/
1165+
staticinlineint
1166+
index_of_allowed_sasl_mech(PGconn*conn,constpg_fe_sasl_mech*mech)
1167+
{
1168+
for (inti=0;i<lengthof(conn->allowed_sasl_mechs);i++)
1169+
{
1170+
if (conn->allowed_sasl_mechs[i]==mech)
1171+
returni;
1172+
}
1173+
1174+
return-1;
1175+
}
1176+
11201177
/*
11211178
*pqConnectOptions2
11221179
*
@@ -1358,17 +1415,19 @@ pqConnectOptions2(PGconn *conn)
13581415
boolnegated= false;
13591416

13601417
/*
1361-
* By default, start from an empty set of allowedoptions and add to
1362-
* it.
1418+
* By default, start from an empty set of allowedmethods and
1419+
*mechanisms, and add toit.
13631420
*/
13641421
conn->auth_required= true;
13651422
conn->allowed_auth_methods=0;
1423+
clear_allowed_sasl_mechs(conn);
13661424

13671425
for (first= true,more= true;more;first= false)
13681426
{
13691427
char*method,
13701428
*part;
1371-
uint32bits;
1429+
uint32bits=0;
1430+
constpg_fe_sasl_mech*mech=NULL;
13721431

13731432
part=parse_comma_separated_list(&s,&more);
13741433
if (part==NULL)
@@ -1384,11 +1443,12 @@ pqConnectOptions2(PGconn *conn)
13841443
if (first)
13851444
{
13861445
/*
1387-
* Switch to a permissive set of allowedoptions, and
1388-
* subtract from it.
1446+
* Switch to a permissive set of allowedmethods and
1447+
*mechanisms, andsubtract from it.
13891448
*/
13901449
conn->auth_required= false;
13911450
conn->allowed_auth_methods=-1;
1451+
fill_allowed_sasl_mechs(conn);
13921452
}
13931453
elseif (!negated)
13941454
{
@@ -1413,6 +1473,10 @@ pqConnectOptions2(PGconn *conn)
14131473
return false;
14141474
}
14151475

1476+
/*
1477+
* First group: methods that can be handled solely with the
1478+
* authentication request codes.
1479+
*/
14161480
if (strcmp(method,"password")==0)
14171481
{
14181482
bits= (1 <<AUTH_REQ_PASSWORD);
@@ -1431,13 +1495,21 @@ pqConnectOptions2(PGconn *conn)
14311495
bits= (1 <<AUTH_REQ_SSPI);
14321496
bits |= (1 <<AUTH_REQ_GSS_CONT);
14331497
}
1498+
1499+
/*
1500+
* Next group: SASL mechanisms. All of these use the same request
1501+
* codes, so the list of allowed mechanisms is tracked separately.
1502+
*
1503+
* supported_sasl_mechs must contain all mechanisms handled here.
1504+
*/
14341505
elseif (strcmp(method,"scram-sha-256")==0)
14351506
{
1436-
/* This currently assumes that SCRAM is the only SASL method. */
1437-
bits= (1 <<AUTH_REQ_SASL);
1438-
bits |= (1 <<AUTH_REQ_SASL_CONT);
1439-
bits |= (1 <<AUTH_REQ_SASL_FIN);
1507+
mech=&pg_scram_mech;
14401508
}
1509+
1510+
/*
1511+
* Final group: meta-options.
1512+
*/
14411513
elseif (strcmp(method,"none")==0)
14421514
{
14431515
/*
@@ -1473,20 +1545,68 @@ pqConnectOptions2(PGconn *conn)
14731545
return false;
14741546
}
14751547

1476-
/* Update the bitmask. */
1477-
if (negated)
1548+
if (mech)
14781549
{
1479-
if ((conn->allowed_auth_methods&bits)==0)
1480-
gotoduplicate;
1550+
/*
1551+
* Update the mechanism set only. The method bitmask will be
1552+
* updated for SASL further down.
1553+
*/
1554+
Assert(!bits);
1555+
1556+
if (negated)
1557+
{
1558+
/* Remove the existing mechanism from the list. */
1559+
i=index_of_allowed_sasl_mech(conn,mech);
1560+
if (i<0)
1561+
gotoduplicate;
1562+
1563+
conn->allowed_sasl_mechs[i]=NULL;
1564+
}
1565+
else
1566+
{
1567+
/*
1568+
* Find a space to put the new mechanism (after making
1569+
* sure it's not already there).
1570+
*/
1571+
i=index_of_allowed_sasl_mech(conn,mech);
1572+
if (i >=0)
1573+
gotoduplicate;
14811574

1482-
conn->allowed_auth_methods &= ~bits;
1575+
i=index_of_allowed_sasl_mech(conn,NULL);
1576+
if (i<0)
1577+
{
1578+
/* Should not happen; the pointer list is corrupted. */
1579+
Assert(false);
1580+
1581+
conn->status=CONNECTION_BAD;
1582+
libpq_append_conn_error(conn,
1583+
"internal error: no space in allowed_sasl_mechs");
1584+
free(part);
1585+
return false;
1586+
}
1587+
1588+
conn->allowed_sasl_mechs[i]=mech;
1589+
}
14831590
}
14841591
else
14851592
{
1486-
if ((conn->allowed_auth_methods&bits)==bits)
1487-
gotoduplicate;
1593+
/* Update the method bitmask. */
1594+
Assert(bits);
1595+
1596+
if (negated)
1597+
{
1598+
if ((conn->allowed_auth_methods&bits)==0)
1599+
gotoduplicate;
1600+
1601+
conn->allowed_auth_methods &= ~bits;
1602+
}
1603+
else
1604+
{
1605+
if ((conn->allowed_auth_methods&bits)==bits)
1606+
gotoduplicate;
14881607

1489-
conn->allowed_auth_methods |=bits;
1608+
conn->allowed_auth_methods |=bits;
1609+
}
14901610
}
14911611

14921612
free(part);
@@ -1505,6 +1625,36 @@ pqConnectOptions2(PGconn *conn)
15051625
free(part);
15061626
return false;
15071627
}
1628+
1629+
/*
1630+
* Finally, allow SASL authentication requests if (and only if) we've
1631+
* allowed any mechanisms.
1632+
*/
1633+
{
1634+
boolallowed= false;
1635+
constuint32sasl_bits=
1636+
(1 <<AUTH_REQ_SASL)
1637+
| (1 <<AUTH_REQ_SASL_CONT)
1638+
| (1 <<AUTH_REQ_SASL_FIN);
1639+
1640+
for (i=0;i<lengthof(conn->allowed_sasl_mechs);i++)
1641+
{
1642+
if (conn->allowed_sasl_mechs[i])
1643+
{
1644+
allowed= true;
1645+
break;
1646+
}
1647+
}
1648+
1649+
/*
1650+
* For the standard case, add the SASL bits to the (default-empty)
1651+
* set if needed. For the negated case, remove them.
1652+
*/
1653+
if (!negated&&allowed)
1654+
conn->allowed_auth_methods |=sasl_bits;
1655+
elseif (negated&& !allowed)
1656+
conn->allowed_auth_methods &= ~sasl_bits;
1657+
}
15081658
}
15091659

15101660
/*

‎src/interfaces/libpq/libpq-int.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ struct pg_conn
505505
* the server? */
506506
uint32allowed_auth_methods;/* bitmask of acceptable AuthRequest
507507
* codes */
508+
constpg_fe_sasl_mech*allowed_sasl_mechs[1];/* and acceptable SASL
509+
* mechanisms */
508510
boolclient_finished_auth;/* have we finished our half of the
509511
* authentication exchange? */
510512
charcurrent_auth_response;/* used by pqTraceOutputMessage to

‎src/test/authentication/t/001_password.pl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,16 @@ sub test_conn
277277
"require_auth methods cannot be duplicated, !none case",
278278
expected_stderr=>
279279
qr/require_auth method "!none" is specified more than once/);
280+
$node->connect_fails(
281+
"user=scram_role require_auth=scram-sha-256,scram-sha-256",
282+
"require_auth methods cannot be duplicated, scram-sha-256 case",
283+
expected_stderr=>
284+
qr/require_auth method "scram-sha-256" is specified more than once/);
285+
$node->connect_fails(
286+
"user=scram_role require_auth=!scram-sha-256,!scram-sha-256",
287+
"require_auth methods cannot be duplicated, !scram-sha-256 case",
288+
expected_stderr=>
289+
qr/require_auth method "!scram-sha-256" is specified more than once/);
280290

281291
# Unknown value defined in require_auth.
282292
$node->connect_fails(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp