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

Commit3a465cc

Browse files
committed
libpq: Add support for require_auth to control authorized auth methods
The new connection parameter require_auth allows a libpq client todefine a list of comma-separated acceptable authentication types for usewith the server. There is no negotiation: if the server does notpresent one of the allowed authentication requests, the connectionattempt done by the client fails.The following keywords can be defined in the list:- password, for AUTH_REQ_PASSWORD.- md5, for AUTH_REQ_MD5.- gss, for AUTH_REQ_GSS[_CONT].- sspi, for AUTH_REQ_SSPI and AUTH_REQ_GSS_CONT.- scram-sha-256, for AUTH_REQ_SASL[_CONT|_FIN].- creds, for AUTH_REQ_SCM_CREDS (perhaps this should be removed entirelynow).- none, to control unauthenticated connections.All the methods that can be defined in the list can be negated, like"!password", in which case the server must NOT use the listedauthentication type. The special method "none" allows/disallows the useof unauthenticated connections (but it does not govern transport-levelauthentication via TLS or GSSAPI).Internally, the patch logic is tied to check_expected_areq(), that wasused for channel_binding, ensuring that an incoming request iscompatible with conn->require_auth. It also introduces a new flag,conn->client_finished_auth, which is set by various authenticationroutines when the client side of the handshake is finished. Thissignals to check_expected_areq() that an AUTH_REQ_OK from the server isexpected, and allows the client to complain if the server bypassesauthentication entirely, with for example the reception of a too-earlyAUTH_REQ_OK message.Regression tests are added in authentication TAP tests for all thekeywords supported (except "creds", because it is around only forcompatibility reasons). A new TAP script has been added for SSPI, asthere was no script dedicated to it yet. It relies on SSPI being thedefault authentication method on Windows, as set by pg_regress.Author: Jacob ChampionReviewed-by: Peter Eisentraut, David G. Johnston, Michael PaquierDiscussion:https://postgr.es/m/9e5a8ccddb8355ea9fa4b75a1e3a9edc88a70cd3.camel@vmware.com
1 parent7274009 commit3a465cc

File tree

12 files changed

+779
-0
lines changed

12 files changed

+779
-0
lines changed

‎doc/src/sgml/libpq.sgml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,111 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
12201220
</listitem>
12211221
</varlistentry>
12221222

1223+
<varlistentry id="libpq-connect-require-auth" xreflabel="require_auth">
1224+
<term><literal>require_auth</literal></term>
1225+
<listitem>
1226+
<para>
1227+
Specifies the authentication method that the client requires from the
1228+
server. If the server does not use the required method to authenticate
1229+
the client, or if the authentication handshake is not fully completed by
1230+
the server, the connection will fail. A comma-separated list of methods
1231+
may also be provided, of which the server must use exactly one in order
1232+
for the connection to succeed. By default, any authentication method is
1233+
accepted, and the server is free to skip authentication altogether.
1234+
</para>
1235+
<para>
1236+
Methods may be negated with the addition of a <literal>!</literal>
1237+
prefix, in which case the server must <emphasis>not</emphasis> attempt
1238+
the listed method; any other method is accepted, and the server is free
1239+
not to authenticate the client at all. If a comma-separated list is
1240+
provided, the server may not attempt <emphasis>any</emphasis> of the
1241+
listed negated methods. Negated and non-negated forms may not be
1242+
combined in the same setting.
1243+
</para>
1244+
<para>
1245+
As a final special case, the <literal>none</literal> method requires the
1246+
server not to use an authentication challenge. (It may also be negated,
1247+
to require some form of authentication.)
1248+
</para>
1249+
<para>
1250+
The following methods may be specified:
1251+
1252+
<variablelist>
1253+
<varlistentry>
1254+
<term><literal>password</literal></term>
1255+
<listitem>
1256+
<para>
1257+
The server must request plaintext password authentication.
1258+
</para>
1259+
</listitem>
1260+
</varlistentry>
1261+
1262+
<varlistentry>
1263+
<term><literal>md5</literal></term>
1264+
<listitem>
1265+
<para>
1266+
The server must request MD5 hashed password authentication.
1267+
</para>
1268+
</listitem>
1269+
</varlistentry>
1270+
1271+
<varlistentry>
1272+
<term><literal>gss</literal></term>
1273+
<listitem>
1274+
<para>
1275+
The server must either request a Kerberos handshake via
1276+
<acronym>GSSAPI</acronym> or establish a
1277+
<acronym>GSS</acronym>-encrypted channel (see also
1278+
<xref linkend="libpq-connect-gssencmode" />).
1279+
</para>
1280+
</listitem>
1281+
</varlistentry>
1282+
1283+
<varlistentry>
1284+
<term><literal>sspi</literal></term>
1285+
<listitem>
1286+
<para>
1287+
The server must request Windows <acronym>SSPI</acronym>
1288+
authentication.
1289+
</para>
1290+
</listitem>
1291+
</varlistentry>
1292+
1293+
<varlistentry>
1294+
<term><literal>scram-sha-256</literal></term>
1295+
<listitem>
1296+
<para>
1297+
The server must successfully complete a SCRAM-SHA-256 authentication
1298+
exchange with the client.
1299+
</para>
1300+
</listitem>
1301+
</varlistentry>
1302+
1303+
<varlistentry>
1304+
<term><literal>creds</literal></term>
1305+
<listitem>
1306+
<para>
1307+
The server must request SCM credential authentication (deprecated
1308+
as of <productname>PostgreSQL</productname> 9.1).
1309+
</para>
1310+
</listitem>
1311+
</varlistentry>
1312+
1313+
<varlistentry>
1314+
<term><literal>none</literal></term>
1315+
<listitem>
1316+
<para>
1317+
The server must not prompt the client for an authentication
1318+
exchange. (This does not prohibit client certificate authentication
1319+
via TLS, nor GSS authentication via its encrypted transport.)
1320+
</para>
1321+
</listitem>
1322+
</varlistentry>
1323+
</variablelist>
1324+
</para>
1325+
</listitem>
1326+
</varlistentry>
1327+
12231328
<varlistentry id="libpq-connect-channel-binding" xreflabel="channel_binding">
12241329
<term><literal>channel_binding</literal></term>
12251330
<listitem>
@@ -7774,6 +7879,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
77747879
</para>
77757880
</listitem>
77767881

7882+
<listitem>
7883+
<para>
7884+
<indexterm>
7885+
<primary><envar>PGREQUIREAUTH</envar></primary>
7886+
</indexterm>
7887+
<envar>PGREQUIREAUTH</envar> behaves the same as the <xref
7888+
linkend="libpq-connect-require-auth"/> connection parameter.
7889+
</para>
7890+
</listitem>
7891+
77777892
<listitem>
77787893
<para>
77797894
<indexterm>

‎src/include/libpq/pqcomm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ extern PGDLLIMPORT bool Db_user_namespace;
123123
#defineAUTH_REQ_SASL 10/* Begin SASL authentication */
124124
#defineAUTH_REQ_SASL_CONT 11/* Continue SASL authentication */
125125
#defineAUTH_REQ_SASL_FIN 12/* Final SASL message */
126+
#defineAUTH_REQ_MAX AUTH_REQ_SASL_FIN/* maximum AUTH_REQ_* value */
126127

127128
typedefuint32AuthRequest;
128129

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ scram_exchange(void *opaq, char *input, int inputlen,
282282
}
283283
*done= true;
284284
state->state=FE_SCRAM_FINISHED;
285+
state->conn->client_finished_auth= true;
285286
break;
286287

287288
default:

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

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ pg_GSS_continue(PGconn *conn, int payloadlen)
136136
}
137137

138138
if (maj_stat==GSS_S_COMPLETE)
139+
{
140+
conn->client_finished_auth= true;
139141
gss_release_name(&lmin_s,&conn->gtarg_nam);
142+
}
140143

141144
returnSTATUS_OK;
142145
}
@@ -321,6 +324,9 @@ pg_SSPI_continue(PGconn *conn, int payloadlen)
321324
FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
322325
}
323326

327+
if (r==SEC_E_OK)
328+
conn->client_finished_auth= true;
329+
324330
/* Cleanup is handled by the code in freePGconn() */
325331
returnSTATUS_OK;
326332
}
@@ -735,6 +741,8 @@ pg_local_sendauth(PGconn *conn)
735741
strerror_r(errno,sebuf,sizeof(sebuf)));
736742
returnSTATUS_ERROR;
737743
}
744+
745+
conn->client_finished_auth= true;
738746
returnSTATUS_OK;
739747
#else
740748
libpq_append_conn_error(conn,"SCM_CRED authentication method not supported");
@@ -805,6 +813,41 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
805813
returnret;
806814
}
807815

816+
/*
817+
* Translate a disallowed AuthRequest code into an error message.
818+
*/
819+
staticconstchar*
820+
auth_method_description(AuthRequestareq)
821+
{
822+
switch (areq)
823+
{
824+
caseAUTH_REQ_PASSWORD:
825+
returnlibpq_gettext("server requested a cleartext password");
826+
caseAUTH_REQ_MD5:
827+
returnlibpq_gettext("server requested a hashed password");
828+
caseAUTH_REQ_GSS:
829+
caseAUTH_REQ_GSS_CONT:
830+
returnlibpq_gettext("server requested GSSAPI authentication");
831+
caseAUTH_REQ_SSPI:
832+
returnlibpq_gettext("server requested SSPI authentication");
833+
caseAUTH_REQ_SCM_CREDS:
834+
returnlibpq_gettext("server requested UNIX socket credentials");
835+
caseAUTH_REQ_SASL:
836+
caseAUTH_REQ_SASL_CONT:
837+
caseAUTH_REQ_SASL_FIN:
838+
returnlibpq_gettext("server requested SASL authentication");
839+
}
840+
841+
returnlibpq_gettext("server requested an unknown authentication type");
842+
}
843+
844+
/*
845+
* Convenience macro for checking the allowed_auth_methods bitmask. Caller
846+
* must ensure that type is not greater than 31 (high bit of the bitmask).
847+
*/
848+
#defineauth_method_allowed(conn,type) \
849+
(((conn)->allowed_auth_methods & (1 << (type))) != 0)
850+
808851
/*
809852
* Verify that the authentication request is expected, given the connection
810853
* parameters. This is especially important when the client wishes to
@@ -814,6 +857,99 @@ static bool
814857
check_expected_areq(AuthRequestareq,PGconn*conn)
815858
{
816859
boolresult= true;
860+
constchar*reason=NULL;
861+
862+
StaticAssertDecl((sizeof(conn->allowed_auth_methods)*CHAR_BIT)>AUTH_REQ_MAX,
863+
"AUTH_REQ_MAX overflows the allowed_auth_methods bitmask");
864+
865+
/*
866+
* If the user required a specific auth method, or specified an allowed
867+
* set, then reject all others here, and make sure the server actually
868+
* completes an authentication exchange.
869+
*/
870+
if (conn->require_auth)
871+
{
872+
switch (areq)
873+
{
874+
caseAUTH_REQ_OK:
875+
876+
/*
877+
* Check to make sure we've actually finished our exchange (or
878+
* else that the user has allowed an authentication-less
879+
* connection).
880+
*
881+
* If the user has allowed both SCRAM and unauthenticated
882+
* (trust) connections, then this check will silently accept
883+
* partial SCRAM exchanges, where a misbehaving server does
884+
* not provide its verifier before sending an OK. This is
885+
* consistent with historical behavior, but it may be a point
886+
* to revisit in the future, since it could allow a server
887+
* that doesn't know the user's password to silently harvest
888+
* material for a brute force attack.
889+
*/
890+
if (!conn->auth_required||conn->client_finished_auth)
891+
break;
892+
893+
/*
894+
* No explicit authentication request was made by the server
895+
* -- or perhaps it was made and not completed, in the case of
896+
* SCRAM -- but there is one special case to check. If the
897+
* user allowed "gss", then a GSS-encrypted channel also
898+
* satisfies the check.
899+
*/
900+
#ifdefENABLE_GSS
901+
if (auth_method_allowed(conn,AUTH_REQ_GSS)&&conn->gssenc)
902+
{
903+
/*
904+
* If implicit GSS auth has already been performed via GSS
905+
* encryption, we don't need to have performed an
906+
* AUTH_REQ_GSS exchange. This allows require_auth=gss to
907+
* be combined with gssencmode, since there won't be an
908+
* explicit authentication request in that case.
909+
*/
910+
}
911+
else
912+
#endif
913+
{
914+
reason=libpq_gettext("server did not complete authentication");
915+
result= false;
916+
}
917+
918+
break;
919+
920+
caseAUTH_REQ_PASSWORD:
921+
caseAUTH_REQ_MD5:
922+
caseAUTH_REQ_GSS:
923+
caseAUTH_REQ_GSS_CONT:
924+
caseAUTH_REQ_SSPI:
925+
caseAUTH_REQ_SCM_CREDS:
926+
caseAUTH_REQ_SASL:
927+
caseAUTH_REQ_SASL_CONT:
928+
caseAUTH_REQ_SASL_FIN:
929+
930+
/*
931+
* We don't handle these with the default case, to avoid
932+
* bit-shifting past the end of the allowed_auth_methods mask
933+
* if the server sends an unexpected AuthRequest.
934+
*/
935+
result=auth_method_allowed(conn,areq);
936+
break;
937+
938+
default:
939+
result= false;
940+
break;
941+
}
942+
}
943+
944+
if (!result)
945+
{
946+
if (!reason)
947+
reason=auth_method_description(areq);
948+
949+
libpq_append_conn_error(conn,"auth method \"%s\" requirement failed: %s",
950+
conn->require_auth,reason);
951+
returnresult;
952+
}
817953

818954
/*
819955
* When channel_binding=require, we must protect against two cases: (1) we
@@ -1008,6 +1144,9 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
10081144
"fe_sendauth: error sending password authentication\n");
10091145
returnSTATUS_ERROR;
10101146
}
1147+
1148+
/* We expect no further authentication requests. */
1149+
conn->client_finished_auth= true;
10111150
break;
10121151
}
10131152

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp