Skip to content

Commit 65a26f3

Browse files
committed
Apply 0007-Support-for-SCRAM-SHA-256-authentication-RFC-5802-an.patch + cherry-pick 8d3b9cc
1 parent ae93312 commit 65a26f3

File tree

29 files changed

+2411
-100
lines changed

29 files changed

+2411
-100
lines changed

contrib/passwordcheck/passwordcheck.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
#endif
2222

2323
#include "commands/user.h"
24-
#include "fmgr.h"
2524
#include "libpq/md5.h"
25+
#include "libpq/scram.h"
26+
#include "fmgr.h"
2627

2728
PG_MODULE_MAGIC;
2829

@@ -57,14 +58,15 @@ check_password(const char *username,
5758
{
5859
int namelen = strlen(username);
5960
int pwdlen = strlen(password);
60-
char encrypted[MD5_PASSWD_LEN + 1];
61+
char *encrypted;
6162
int i;
6263
bool pwd_has_letter,
6364
pwd_has_nonletter;
6465

6566
switch (password_type)
6667
{
6768
case PASSWORD_TYPE_MD5:
69+
case PASSWORD_TYPE_SCRAM:
6870

6971
/*
7072
* Unfortunately we cannot perform exhaustive checks on encrypted
@@ -74,12 +76,23 @@ check_password(const char *username,
7476
*
7577
* We only check for username = password.
7678
*/
77-
if (!pg_md5_encrypt(username, username, namelen, encrypted))
78-
elog(ERROR, "password encryption failed");
79+
if (password_type == PASSWORD_TYPE_MD5)
80+
{
81+
encrypted = palloc(MD5_PASSWD_LEN + 1);
82+
if (pg_md5_encrypt(username, username, namelen, encrypted))
83+
elog(ERROR, "password encryption failed");
84+
}
85+
else if (password_type == PASSWORD_TYPE_SCRAM)
86+
{
87+
encrypted = scram_build_verifier(username, password, 0);
88+
}
89+
else
90+
Assert(0); /* should not happen */
7991
if (strcmp(password, encrypted) == 0)
8092
ereport(ERROR,
8193
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8294
errmsg("password must not contain user name")));
95+
pfree(encrypted);
8396
break;
8497

8598
case PASSWORD_TYPE_PLAINTEXT:

doc/src/sgml/config.sgml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,8 +1176,10 @@ include_dir 'conf.d'
11761176
password is to be encrypted. The default value is <literal>md5</>, which
11771177
stores the password as an MD5 hash. Setting this to <literal>plain</> stores
11781178
it in plaintext. <literal>on</> and <literal>off</> are also accepted, as
1179-
aliases for <literal>md5</> and <literal>plain</>, respectively.
1180-
</para>
1179+
aliases for <literal>md5</> and <literal>plain</>, respectively. Setting
1180+
this parameter to <literal>scram</> will encrypt the password with
1181+
SCRAM-SHA-256.
1182+
</para>
11811183

11821184
</listitem>
11831185
</varlistentry>
@@ -1251,7 +1253,7 @@ include_dir 'conf.d'
12511253
Authentication checks are always done with the server's user name
12521254
so authentication methods must be configured for the
12531255
server's user name, not the client's. Because
1254-
<literal>md5</> uses the user name as salt on both the
1256+
<literal>md5</>uses the user name as salt on both the
12551257
client and server, and <literal>scram</> uses the user name as
12561258
a portion of the salt used on both the client and server,
12571259
<literal>md5</> and <literal>scram</> cannot be used with

doc/src/sgml/protocol.sgml

Lines changed: 142 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@
228228
The server then sends an appropriate authentication request message,
229229
to which the frontend must reply with an appropriate authentication
230230
response message (such as a password).
231-
For all authentication methods except GSSAPI and SSPI, there is at most
232-
one request and one response. In some methods, no response
231+
For all authentication methods except GSSAPI, SSPI and SASL, there is at
232+
most one request and one response. In some methods, no response
233233
at all is needed from the frontend, and so no authentication request
234-
occurs. For GSSAPI and SSPI, multiple exchanges of packets may be needed
235-
to complete the authentication.
234+
occurs. For GSSAPI, SSPI and SASL, multiple exchanges of packets may be
235+
needed to complete the authentication.
236236
</para>
237237

238238
<para>
@@ -366,6 +366,35 @@
366366
</listitem>
367367
</varlistentry>
368368

369+
<varlistentry>
370+
<term>AuthenticationSASL</term>
371+
<listitem>
372+
<para>
373+
The frontend must now initiate a SASL negotiation, using the SASL
374+
mechanism specified in the message. The frontend will send a
375+
PasswordMessage with the first part of the SASL data stream in
376+
response to this. If further messages are needed, the server will
377+
respond with AuthenticationSASLContinue.
378+
</para>
379+
</listitem>
380+
381+
</varlistentry>
382+
<varlistentry>
383+
<term>AuthenticationSASLContinue</term>
384+
<listitem>
385+
<para>
386+
This message contains the response data from the previous step
387+
of SASL negotiation (AuthenticationSASL, or a previous
388+
AuthenticationSASLContinue). If the SASL data in this message
389+
indicates more data is needed to complete the authentication,
390+
the frontend must send that data as another PasswordMessage. If
391+
SASL authentication is completed by this message, the server
392+
will next send AuthenticationOk to indicate successful authentication
393+
or ErrorResponse to indicate failure.
394+
</para>
395+
</listitem>
396+
</varlistentry>
397+
369398
</variablelist>
370399
</para>
371400

@@ -2578,6 +2607,114 @@ AuthenticationGSSContinue (B)
25782607
</listitem>
25792608
</varlistentry>
25802609

2610+
<varlistentry>
2611+
<term>
2612+
AuthenticationSASL (B)
2613+
</term>
2614+
<listitem>
2615+
<para>
2616+
2617+
<variablelist>
2618+
<varlistentry>
2619+
<term>
2620+
Byte1('R')
2621+
</term>
2622+
<listitem>
2623+
<para>
2624+
Identifies the message as an authentication request.
2625+
</para>
2626+
</listitem>
2627+
</varlistentry>
2628+
<varlistentry>
2629+
<term>
2630+
Int32
2631+
</term>
2632+
<listitem>
2633+
<para>
2634+
Length of message contents in bytes, including self.
2635+
</para>
2636+
</listitem>
2637+
</varlistentry>
2638+
<varlistentry>
2639+
<term>
2640+
Int32(10)
2641+
</term>
2642+
<listitem>
2643+
<para>
2644+
Specifies that SASL authentication is started.
2645+
</para>
2646+
</listitem>
2647+
</varlistentry>
2648+
<varlistentry>
2649+
<term>
2650+
String
2651+
</term>
2652+
<listitem>
2653+
<para>
2654+
Name of a SASL authentication mechanism.
2655+
</para>
2656+
</listitem>
2657+
</varlistentry>
2658+
</variablelist>
2659+
2660+
</para>
2661+
</listitem>
2662+
</varlistentry>
2663+
2664+
<varlistentry>
2665+
<term>
2666+
AuthenticationSASLContinue (B)
2667+
</term>
2668+
<listitem>
2669+
<para>
2670+
2671+
<variablelist>
2672+
<varlistentry>
2673+
<term>
2674+
Byte1('R')
2675+
</term>
2676+
<listitem>
2677+
<para>
2678+
Identifies the message as an authentication request.
2679+
</para>
2680+
</listitem>
2681+
</varlistentry>
2682+
<varlistentry>
2683+
<term>
2684+
Int32
2685+
</term>
2686+
<listitem>
2687+
<para>
2688+
Length of message contents in bytes, including self.
2689+
</para>
2690+
</listitem>
2691+
</varlistentry>
2692+
<varlistentry>
2693+
<term>
2694+
Int32(11)
2695+
</term>
2696+
<listitem>
2697+
<para>
2698+
Specifies that this message contains SASL-mechanism specific
2699+
data.
2700+
</para>
2701+
</listitem>
2702+
</varlistentry>
2703+
<varlistentry>
2704+
<term>
2705+
Byte<replaceable>n</replaceable>
2706+
</term>
2707+
<listitem>
2708+
<para>
2709+
SASL data, specific to the SASL mechanism being used.
2710+
</para>
2711+
</listitem>
2712+
</varlistentry>
2713+
</variablelist>
2714+
2715+
</para>
2716+
</listitem>
2717+
</varlistentry>
25812718

25822719
<varlistentry>
25832720
<term>
@@ -4340,7 +4477,7 @@ PasswordMessage (F)
43404477
<listitem>
43414478
<para>
43424479
Identifies the message as a password response. Note that
4343-
this is also used for GSSAPI and SSPI response messages
4480+
this is also used for GSSAPI, SSPI and SASL response messages
43444481
(which is really a design error, since the contained data
43454482
is not a null-terminated string in that case, but can be
43464483
arbitrary binary data).

doc/src/sgml/ref/create_role.sgml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,16 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
229229
encrypted in the system catalogs. (If neither is specified,
230230
the default behavior is determined by the configuration
231231
parameter <xref linkend="guc-password-encryption">.) If the
232-
presented password string is already in MD5-encrypted format,
233-
then it is stored encrypted as-is, regardless of whether
234-
<literal>ENCRYPTED</> or <literal>UNENCRYPTED</> is specified
235-
(since the system cannot decrypt the specified encrypted
236-
password string). This allows reloading of encrypted
237-
passwords during dump/restore.
232+
presented password string is already in MD5-encrypted or
233+
SCRAM-encrypted format, then it is stored encrypted as-is,
234+
regardless of whether <literal>ENCRYPTED</> or <literal>UNENCRYPTED</>
235+
is specified (since the system cannot decrypt the specified encrypted
236+
password string). This allows reloading of encrypted passwords
237+
during dump/restore.
238238
</para>
239239

240240
<para>
241-
Note that older clients might lack support for the MD5
241+
Note that older clients might lack support for the MD5 or SCRAM
242242
authentication mechanism that is needed to work with passwords
243243
that are stored encrypted.
244244
</para>
@@ -254,10 +254,11 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
254254
attribute, but you can nonetheless define one for roles without it.)
255255
If you do not plan to use password authentication you can omit this
256256
option. The protocols supported are <literal>md5</> to enforce
257-
a password to be MD5-encrypted, and <literal>plain</> to use an
258-
unencrypted password. If the password string is already in
259-
MD5-encrypted format, then it is stored encrypted even if
260-
<literal>plain</> is specified.
257+
a password to be MD5-encrypted, <literal>scram</> to enforce a password
258+
to be encrypted with SCRAM-SHA-256, and <literal>plain</> to use
259+
an unencrypted password. If the password string is already in
260+
MD5-encrypted or SCRAM-SHA-256 format, then it is stored encrypted
261+
even if another protocol is specified.
261262
</para>
262263
</listitem>
263264
</varlistentry>

0 commit comments

Comments
 (0)