Remove support for password_encryption='off' / 'plain'.

Storing passwords in plaintext hasn't been a good idea for a very long
time, if ever. Now seems like a good time to finally forbid it, since we're
messing with this in PostgreSQL 10 anyway.

Remove the CREATE/ALTER USER UNENCRYPTED PASSSWORD 'foo' syntax, since
storing passwords unencrypted is no longer supported. ENCRYPTED PASSWORD
'foo' is still accepted, but ENCRYPTED is now just a noise-word, it does
the same as just PASSWORD 'foo'.

Likewise, remove the --unencrypted option from createuser, but accept
--encrypted as a no-op for backward compatibility. AFAICS, --encrypted was
a no-op even before this patch, because createuser encrypted the password
before sending it to the server even if --encrypted was not specified. It
added the ENCRYPTED keyword to the SQL command, but since the password was
already in encrypted form, it didn't make any difference. The documentation
was not clear on whether that was intended or not, but it's moot now.

Also, while password_encryption='on' is still accepted as an alias for
'md5', it is now marked as hidden, so that it is not listed as an accepted
value in error hints, for example. That's not directly related to removing
'plain', but it seems better this way.

Reviewed by Michael Paquier

Discussion: https://www.postgresql.org/message-id/16e9b768-fd78-0b12-cfc1-7b6b7f238fde@iki.fi
This commit is contained in:
Heikki Linnakangas 2017-05-08 11:26:07 +03:00
parent 1f30295eab
commit eb61136dc7
21 changed files with 177 additions and 331 deletions

View File

@ -39,8 +39,8 @@ extern void _PG_init(void);
* *
* username: name of role being created or changed * username: name of role being created or changed
* password: new password (possibly already encrypted) * password: new password (possibly already encrypted)
* password_type: PASSWORD_TYPE_PLAINTEXT or PASSWORD_TYPE_MD5 (there * password_type: PASSWORD_TYPE_* code, to indicate if the password is
* could be other encryption schemes in future) * in plaintext or encrypted form.
* validuntil_time: password expiration time, as a timestamptz Datum * validuntil_time: password expiration time, as a timestamptz Datum
* validuntil_null: true if password expiration time is NULL * validuntil_null: true if password expiration time is NULL
* *

View File

@ -1188,14 +1188,16 @@ include_dir 'conf.d'
<listitem> <listitem>
<para> <para>
When a password is specified in <xref linkend="sql-createrole"> or When a password is specified in <xref linkend="sql-createrole"> or
<xref linkend="sql-alterrole"> without writing either <literal>ENCRYPTED</> <xref linkend="sql-alterrole">, this parameter determines the algorithm
or <literal>UNENCRYPTED</>, this parameter determines whether the to use to encrypt the password. The default value is <literal>md5</>,
password is to be encrypted. The default value is <literal>md5</>, which which stores the password as an MD5 hash (<literal>on</> is also
stores the password as an MD5 hash. Setting this to <literal>plain</> stores accepted, as alias for <literal>md5</>). Setting this parameter to
it in plaintext. <literal>on</> and <literal>off</> are also accepted, as <literal>scram-sha-256</> will encrypt the password with SCRAM-SHA-256.
aliases for <literal>md5</> and <literal>plain</>, respectively. Setting </para>
this parameter to <literal>scram-sha-256</> will encrypt the password <para>
with SCRAM-SHA-256. Note that older clients might lack support for the SCRAM authentication
mechanism, and hence not work with passwords encrypted with
SCRAM-SHA-256.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -33,7 +33,7 @@ ALTER ROLE <replaceable class="PARAMETER">role_specification</replaceable> [ WIT
| REPLICATION | NOREPLICATION | REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable> | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
@ -168,9 +168,7 @@ ALTER ROLE { <replaceable class="PARAMETER">role_specification</replaceable> | A
<term><literal>BYPASSRLS</literal></term> <term><literal>BYPASSRLS</literal></term>
<term><literal>NOBYPASSRLS</literal></term> <term><literal>NOBYPASSRLS</literal></term>
<term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term> <term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term>
<term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
<term><literal>ENCRYPTED</></term>
<term><literal>UNENCRYPTED</></term>
<term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term> <term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term>
<listitem> <listitem>
<para> <para>

View File

@ -33,7 +33,7 @@ ALTER USER <replaceable class="PARAMETER">role_specification</replaceable> [ WIT
| REPLICATION | NOREPLICATION | REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable> | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>

View File

@ -30,7 +30,7 @@ CREATE GROUP <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <repla
| CREATEROLE | NOCREATEROLE | CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT | INHERIT | NOINHERIT
| LOGIN | NOLOGIN | LOGIN | NOLOGIN
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
| IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
| IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]

View File

@ -33,7 +33,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
| REPLICATION | NOREPLICATION | REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable> | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
| IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
| IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]
@ -207,7 +207,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
<listitem> <listitem>
<para> <para>
Sets the role's password. (A password is only of use for Sets the role's password. (A password is only of use for
@ -219,30 +219,18 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
user. A null password can optionally be written explicitly as user. A null password can optionally be written explicitly as
<literal>PASSWORD NULL</literal>. <literal>PASSWORD NULL</literal>.
</para> </para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>ENCRYPTED</></term>
<term><literal>UNENCRYPTED</></term>
<listitem>
<para> <para>
These key words control whether the password is stored The password is always stored encrypted in the system catalogs. The
encrypted in the system catalogs. (If neither is specified, <literal>ENCRYPTED</> keyword has no effect, but is accepted for
the default behavior is determined by the configuration backwards compatibility. The method of encryption is determined
parameter <xref linkend="guc-password-encryption">.) If the by the configuration parameter <xref linkend="guc-password-encryption">.
presented password string is already in MD5-encrypted or If the presented password string is already in MD5-encrypted or
SCRAM-encrypted format, then it is stored encrypted as-is, SCRAM-encrypted format, then it is stored as-is regardless of
regardless of whether <literal>ENCRYPTED</> or <literal>UNENCRYPTED</> <varname>password_encryption</> (since the system cannot decrypt
is specified (since the system cannot decrypt the specified encrypted the specified encrypted password string, to encrypt it in a
password string). This allows reloading of encrypted passwords different format). This allows reloading of encrypted passwords
during dump/restore. during dump/restore.
</para> </para>
<para>
Note that older clients might lack support for the SCRAM
authentication mechanism.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -33,7 +33,7 @@ CREATE USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
| REPLICATION | NOREPLICATION | REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable> | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
| IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
| IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]

View File

@ -124,8 +124,8 @@ PostgreSQL documentation
<term><option>--encrypted</></term> <term><option>--encrypted</></term>
<listitem> <listitem>
<para> <para>
Encrypts the user's password stored in the database. If not This option is obsolete but still accepted for backward
specified, the default password behavior is used. compatibility.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -204,17 +204,6 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-N</></term>
<term><option>--unencrypted</></term>
<listitem>
<para>
Does not encrypt the user's password stored in the database. If
not specified, the default password behavior is used.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-P</></term> <term><option>-P</></term>
<term><option>--pwprompt</></term> <term><option>--pwprompt</></term>
@ -481,11 +470,7 @@ PostgreSQL documentation
</screen> </screen>
In the above example, the new password isn't actually echoed when typed, In the above example, the new password isn't actually echoed when typed,
but we show what was typed for clarity. As you see, the password is but we show what was typed for clarity. As you see, the password is
encrypted before it is sent to the client. If the option <option>--unencrypted</option> encrypted before it is sent to the client.
is used, the password <emphasis>will</> appear in the echoed command
(and possibly also in the server log and elsewhere),
so you don't want to use <option>-e</> in that case, if
anyone else can see your screen.
</para> </para>
</refsect1> </refsect1>

View File

@ -80,7 +80,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
ListCell *item; ListCell *item;
ListCell *option; ListCell *option;
char *password = NULL; /* user password */ char *password = NULL; /* user password */
int password_type = Password_encryption;
bool issuper = false; /* Make the user a superuser? */ bool issuper = false; /* Make the user a superuser? */
bool inherit = true; /* Auto inherit privileges? */ bool inherit = true; /* Auto inherit privileges? */
bool createrole = false; /* Can this user create roles? */ bool createrole = false; /* Can this user create roles? */
@ -128,9 +127,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
{ {
DefElem *defel = (DefElem *) lfirst(option); DefElem *defel = (DefElem *) lfirst(option);
if (strcmp(defel->defname, "password") == 0 || if (strcmp(defel->defname, "password") == 0)
strcmp(defel->defname, "encryptedPassword") == 0 ||
strcmp(defel->defname, "unencryptedPassword") == 0)
{ {
if (dpassword) if (dpassword)
ereport(ERROR, ereport(ERROR,
@ -138,15 +135,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
errmsg("conflicting or redundant options"), errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location))); parser_errposition(pstate, defel->location)));
dpassword = defel; dpassword = defel;
if (strcmp(defel->defname, "encryptedPassword") == 0)
{
if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256)
password_type = PASSWORD_TYPE_SCRAM_SHA_256;
else
password_type = PASSWORD_TYPE_MD5;
}
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
password_type = PASSWORD_TYPE_PLAINTEXT;
} }
else if (strcmp(defel->defname, "sysid") == 0) else if (strcmp(defel->defname, "sysid") == 0)
{ {
@ -400,7 +388,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
/* Encrypt the password to the requested format. */ /* Encrypt the password to the requested format. */
char *shadow_pass; char *shadow_pass;
shadow_pass = encrypt_password(password_type, stmt->role, password); shadow_pass = encrypt_password(Password_encryption, stmt->role,
password);
new_record[Anum_pg_authid_rolpassword - 1] = new_record[Anum_pg_authid_rolpassword - 1] =
CStringGetTextDatum(shadow_pass); CStringGetTextDatum(shadow_pass);
} }
@ -503,7 +492,6 @@ AlterRole(AlterRoleStmt *stmt)
ListCell *option; ListCell *option;
char *rolename = NULL; char *rolename = NULL;
char *password = NULL; /* user password */ char *password = NULL; /* user password */
int password_type = Password_encryption;
int issuper = -1; /* Make the user a superuser? */ int issuper = -1; /* Make the user a superuser? */
int inherit = -1; /* Auto inherit privileges? */ int inherit = -1; /* Auto inherit privileges? */
int createrole = -1; /* Can this user create roles? */ int createrole = -1; /* Can this user create roles? */
@ -537,24 +525,13 @@ AlterRole(AlterRoleStmt *stmt)
{ {
DefElem *defel = (DefElem *) lfirst(option); DefElem *defel = (DefElem *) lfirst(option);
if (strcmp(defel->defname, "password") == 0 || if (strcmp(defel->defname, "password") == 0)
strcmp(defel->defname, "encryptedPassword") == 0 ||
strcmp(defel->defname, "unencryptedPassword") == 0)
{ {
if (dpassword) if (dpassword)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
dpassword = defel; dpassword = defel;
if (strcmp(defel->defname, "encryptedPassword") == 0)
{
if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256)
password_type = PASSWORD_TYPE_SCRAM_SHA_256;
else
password_type = PASSWORD_TYPE_MD5;
}
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
password_type = PASSWORD_TYPE_PLAINTEXT;
} }
else if (strcmp(defel->defname, "superuser") == 0) else if (strcmp(defel->defname, "superuser") == 0)
{ {
@ -809,7 +786,8 @@ AlterRole(AlterRoleStmt *stmt)
/* Encrypt the password to the requested format. */ /* Encrypt the password to the requested format. */
char *shadow_pass; char *shadow_pass;
shadow_pass = encrypt_password(password_type, rolename, password); shadow_pass = encrypt_password(Password_encryption, rolename,
password);
new_record[Anum_pg_authid_rolpassword - 1] = new_record[Anum_pg_authid_rolpassword - 1] =
CStringGetTextDatum(shadow_pass); CStringGetTextDatum(shadow_pass);
new_record_repl[Anum_pg_authid_rolpassword - 1] = true; new_record_repl[Anum_pg_authid_rolpassword - 1] = true;

View File

@ -199,27 +199,11 @@ pg_be_scram_init(const char *username, const char *shadow_pass)
got_verifier = false; got_verifier = false;
} }
} }
else if (password_type == PASSWORD_TYPE_PLAINTEXT)
{
/*
* The stored password is in plain format. Generate a fresh SCRAM
* verifier from it, and proceed with that.
*/
char *verifier;
verifier = pg_be_scram_build_verifier(shadow_pass);
(void) parse_scram_verifier(verifier, &state->iterations, &state->salt,
state->StoredKey, state->ServerKey);
pfree(verifier);
got_verifier = true;
}
else else
{ {
/* /*
* The user doesn't have SCRAM verifier, nor could we generate * The user doesn't have SCRAM verifier. (You cannot do SCRAM
* one. (You cannot do SCRAM authentication with an MD5 hash.) * authentication with an MD5 hash.)
*/ */
state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."), state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."),
state->username); state->username);

View File

@ -754,17 +754,13 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
shadow_pass = get_role_password(port->user_name, logdetail); shadow_pass = get_role_password(port->user_name, logdetail);
/* /*
* If the user does not exist, or has no password, we still go through the * If the user does not exist, or has no password or it's expired, we
* motions of authentication, to avoid revealing to the client that the * still go through the motions of authentication, to avoid revealing to
* user didn't exist. If 'md5' is allowed, we choose whether to use 'md5' * the client that the user didn't exist. If 'md5' is allowed, we choose
* or 'scram-sha-256' authentication based on current password_encryption * whether to use 'md5' or 'scram-sha-256' authentication based on
* setting. The idea is that most genuine users probably have a password * current password_encryption setting. The idea is that most genuine
* of that type, if we pretend that this user had a password of that type, * users probably have a password of that type, and if we pretend that
* too, it "blends in" best. * this user had a password of that type, too, it "blends in" best.
*
* If the user had a password, but it was expired, we'll use the details
* of the expired password for the authentication, but report it as
* failure to the client even if correct password was given.
*/ */
if (!shadow_pass) if (!shadow_pass)
pwtype = Password_encryption; pwtype = Password_encryption;
@ -775,21 +771,15 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
* If 'md5' authentication is allowed, decide whether to perform 'md5' or * If 'md5' authentication is allowed, decide whether to perform 'md5' or
* 'scram-sha-256' authentication based on the type of password the user * 'scram-sha-256' authentication based on the type of password the user
* has. If it's an MD5 hash, we must do MD5 authentication, and if it's * has. If it's an MD5 hash, we must do MD5 authentication, and if it's
* a SCRAM verifier, we must do SCRAM authentication. If it's stored in * a SCRAM verifier, we must do SCRAM authentication.
* plaintext, we could do either one, so we opt for the more secure
* mechanism, SCRAM.
* *
* If MD5 authentication is not allowed, always use SCRAM. If the user * If MD5 authentication is not allowed, always use SCRAM. If the user
* had an MD5 password, CheckSCRAMAuth() will fail. * had an MD5 password, CheckSCRAMAuth() will fail.
*/ */
if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5) if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5)
{
auth_result = CheckMD5Auth(port, shadow_pass, logdetail); auth_result = CheckMD5Auth(port, shadow_pass, logdetail);
}
else else
{
auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail); auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail);
}
if (shadow_pass) if (shadow_pass)
pfree(shadow_pass); pfree(shadow_pass);

View File

@ -109,9 +109,8 @@ get_password_type(const char *shadow_pass)
* Given a user-supplied password, convert it into a verifier of * Given a user-supplied password, convert it into a verifier of
* 'target_type' kind. * 'target_type' kind.
* *
* If the password looks like a valid MD5 hash, it is stored as it is. * If the password is already in encrypted form, we cannot reverse the
* We cannot reverse the hash, so even if the caller requested a plaintext * hash, so it is stored as it is regardless of the requested type.
* plaintext password, the MD5 hash is returned.
*/ */
char * char *
encrypt_password(PasswordType target_type, const char *role, encrypt_password(PasswordType target_type, const char *role,
@ -120,20 +119,18 @@ encrypt_password(PasswordType target_type, const char *role,
PasswordType guessed_type = get_password_type(password); PasswordType guessed_type = get_password_type(password);
char *encrypted_password; char *encrypted_password;
switch (target_type) if (guessed_type != PASSWORD_TYPE_PLAINTEXT)
{ {
case PASSWORD_TYPE_PLAINTEXT:
/* /*
* We cannot convert a hashed password back to plaintext, so just * Cannot convert an already-encrypted password from one
* store the password as it was, whether it was hashed or not. * format to another, so return it as it is.
*/ */
return pstrdup(password); return pstrdup(password);
}
case PASSWORD_TYPE_MD5: switch (target_type)
switch (guessed_type)
{ {
case PASSWORD_TYPE_PLAINTEXT: case PASSWORD_TYPE_MD5:
encrypted_password = palloc(MD5_PASSWD_LEN + 1); encrypted_password = palloc(MD5_PASSWD_LEN + 1);
if (!pg_md5_encrypt(password, role, strlen(role), if (!pg_md5_encrypt(password, role, strlen(role),
@ -142,32 +139,10 @@ encrypt_password(PasswordType target_type, const char *role,
return encrypted_password; return encrypted_password;
case PASSWORD_TYPE_SCRAM_SHA_256: case PASSWORD_TYPE_SCRAM_SHA_256:
/*
* cannot convert a SCRAM verifier to an MD5 hash, so fall
* through to save the SCRAM verifier instead.
*/
case PASSWORD_TYPE_MD5:
return pstrdup(password);
}
break;
case PASSWORD_TYPE_SCRAM_SHA_256:
switch (guessed_type)
{
case PASSWORD_TYPE_PLAINTEXT:
return pg_be_scram_build_verifier(password); return pg_be_scram_build_verifier(password);
case PASSWORD_TYPE_MD5: case PASSWORD_TYPE_PLAINTEXT:
elog(ERROR, "cannot encrypt password with 'plaintext'");
/*
* cannot convert an MD5 hash to a SCRAM verifier, so fall
* through to save the MD5 hash instead.
*/
case PASSWORD_TYPE_SCRAM_SHA_256:
return pstrdup(password);
}
break;
} }
/* /*
@ -197,10 +172,17 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
{ {
int retval; int retval;
char crypt_pwd[MD5_PASSWD_LEN + 1]; char crypt_pwd[MD5_PASSWD_LEN + 1];
char crypt_pwd2[MD5_PASSWD_LEN + 1];
Assert(md5_salt_len > 0); Assert(md5_salt_len > 0);
if (get_password_type(shadow_pass) != PASSWORD_TYPE_MD5)
{
/* incompatible password hash format. */
*logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
role);
return STATUS_ERROR;
}
/* /*
* Compute the correct answer for the MD5 challenge. * Compute the correct answer for the MD5 challenge.
* *
@ -208,9 +190,6 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
* below: the only possible error is out-of-memory, which is unlikely, and * below: the only possible error is out-of-memory, which is unlikely, and
* if it did happen adding a psprintf call would only make things worse. * if it did happen adding a psprintf call would only make things worse.
*/ */
switch (get_password_type(shadow_pass))
{
case PASSWORD_TYPE_MD5:
/* stored password already encrypted, only do salt */ /* stored password already encrypted, only do salt */
if (!pg_md5_encrypt(shadow_pass + strlen("md5"), if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
md5_salt, md5_salt_len, md5_salt, md5_salt_len,
@ -218,31 +197,6 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
{ {
return STATUS_ERROR; return STATUS_ERROR;
} }
break;
case PASSWORD_TYPE_PLAINTEXT:
/* stored password is plain, double-encrypt */
if (!pg_md5_encrypt(shadow_pass,
role,
strlen(role),
crypt_pwd2))
{
return STATUS_ERROR;
}
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
md5_salt, md5_salt_len,
crypt_pwd))
{
return STATUS_ERROR;
}
break;
default:
/* unknown password hash format. */
*logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
role);
return STATUS_ERROR;
}
if (strcmp(client_pass, crypt_pwd) == 0) if (strcmp(client_pass, crypt_pwd) == 0)
retval = STATUS_OK; retval = STATUS_OK;
@ -259,8 +213,8 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
/* /*
* Check given password for given user, and return STATUS_OK or STATUS_ERROR. * Check given password for given user, and return STATUS_OK or STATUS_ERROR.
* *
* 'shadow_pass' is the user's correct password or password hash, as stored * 'shadow_pass' is the user's correct password hash, as stored in
* in pg_authid.rolpassword. * pg_authid.rolpassword.
* 'client_pass' is the password given by the remote user. * 'client_pass' is the password given by the remote user.
* *
* In the error case, optionally store a palloc'd string at *logdetail * In the error case, optionally store a palloc'd string at *logdetail
@ -320,14 +274,10 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
break; break;
case PASSWORD_TYPE_PLAINTEXT: case PASSWORD_TYPE_PLAINTEXT:
if (strcmp(client_pass, shadow_pass) == 0) /*
return STATUS_OK; * We never store passwords in plaintext, so this shouldn't
else * happen.
{ */
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
role);
return STATUS_ERROR;
}
break; break;
} }

View File

@ -994,13 +994,21 @@ AlterOptRoleElem:
} }
| ENCRYPTED PASSWORD Sconst | ENCRYPTED PASSWORD Sconst
{ {
$$ = makeDefElem("encryptedPassword", /*
* These days, passwords are always stored in encrypted
* form, so there is no difference between PASSWORD and
* ENCRYPTED PASSWORD.
*/
$$ = makeDefElem("password",
(Node *)makeString($3), @1); (Node *)makeString($3), @1);
} }
| UNENCRYPTED PASSWORD Sconst | UNENCRYPTED PASSWORD Sconst
{ {
$$ = makeDefElem("unencryptedPassword", ereport(ERROR,
(Node *)makeString($3), @1); (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("UNENCRYPTED PASSWORD is no longer supported"),
errhint("Remove UNENCRYPTED to store the password in encrypted form instead."),
parser_errposition(@1)));
} }
| INHERIT | INHERIT
{ {

View File

@ -405,20 +405,16 @@ static const struct config_enum_entry force_parallel_mode_options[] = {
/* /*
* password_encryption used to be a boolean, so accept all the likely * password_encryption used to be a boolean, so accept all the likely
* variants of "on" and "off", too. * variants of "on", too. "off" used to store passwords in plaintext,
* but we don't support that anymore.
*/ */
static const struct config_enum_entry password_encryption_options[] = { static const struct config_enum_entry password_encryption_options[] = {
{"plain", PASSWORD_TYPE_PLAINTEXT, false},
{"md5", PASSWORD_TYPE_MD5, false}, {"md5", PASSWORD_TYPE_MD5, false},
{"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false}, {"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false},
{"off", PASSWORD_TYPE_PLAINTEXT, false}, {"on", PASSWORD_TYPE_MD5, true},
{"on", PASSWORD_TYPE_MD5, false},
{"true", PASSWORD_TYPE_MD5, true}, {"true", PASSWORD_TYPE_MD5, true},
{"false", PASSWORD_TYPE_PLAINTEXT, true},
{"yes", PASSWORD_TYPE_MD5, true}, {"yes", PASSWORD_TYPE_MD5, true},
{"no", PASSWORD_TYPE_PLAINTEXT, true},
{"1", PASSWORD_TYPE_MD5, true}, {"1", PASSWORD_TYPE_MD5, true},
{"0", PASSWORD_TYPE_PLAINTEXT, true},
{NULL, 0, false} {NULL, 0, false}
}; };

View File

@ -1634,10 +1634,10 @@ psql_completion(const char *text, int start, int end)
{ {
static const char *const list_ALTERUSER[] = static const char *const list_ALTERUSER[] =
{"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
"ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS", "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
"NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
"REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", "REPLICATION", "RESET", "SET", "SUPERUSER",
"VALID UNTIL", "WITH", NULL}; "VALID UNTIL", "WITH", NULL};
COMPLETE_WITH_LIST(list_ALTERUSER); COMPLETE_WITH_LIST(list_ALTERUSER);
@ -1649,18 +1649,15 @@ psql_completion(const char *text, int start, int end)
/* Similar to the above, but don't complete "WITH" again. */ /* Similar to the above, but don't complete "WITH" again. */
static const char *const list_ALTERUSER_WITH[] = static const char *const list_ALTERUSER_WITH[] =
{"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
"ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS", "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
"NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
"REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", "REPLICATION", "RESET", "SET", "SUPERUSER",
"VALID UNTIL", NULL}; "VALID UNTIL", NULL};
COMPLETE_WITH_LIST(list_ALTERUSER_WITH); COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
} }
/* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
else if (Matches4("ALTER", "USER|ROLE", MatchAny, "ENCRYPTED|UNENCRYPTED"))
COMPLETE_WITH_CONST("PASSWORD");
/* ALTER DEFAULT PRIVILEGES */ /* ALTER DEFAULT PRIVILEGES */
else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES")) else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES"))
COMPLETE_WITH_LIST2("FOR ROLE", "IN SCHEMA"); COMPLETE_WITH_LIST2("FOR ROLE", "IN SCHEMA");
@ -2502,10 +2499,10 @@ psql_completion(const char *text, int start, int end)
{ {
static const char *const list_CREATEROLE[] = static const char *const list_CREATEROLE[] =
{"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
"NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
"REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED", "REPLICATION", "ROLE", "SUPERUSER", "SYSID",
"VALID UNTIL", "WITH", NULL}; "VALID UNTIL", "WITH", NULL};
COMPLETE_WITH_LIST(list_CREATEROLE); COMPLETE_WITH_LIST(list_CREATEROLE);
@ -2517,21 +2514,15 @@ psql_completion(const char *text, int start, int end)
/* Similar to the above, but don't complete "WITH" again. */ /* Similar to the above, but don't complete "WITH" again. */
static const char *const list_CREATEROLE_WITH[] = static const char *const list_CREATEROLE_WITH[] =
{"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
"NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
"REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED", "REPLICATION", "ROLE", "SUPERUSER", "SYSID",
"VALID UNTIL", NULL}; "VALID UNTIL", NULL};
COMPLETE_WITH_LIST(list_CREATEROLE_WITH); COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
} }
/*
* complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
* PASSWORD
*/
else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "ENCRYPTED|UNENCRYPTED"))
COMPLETE_WITH_CONST("PASSWORD");
/* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */ /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN")) else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN"))
COMPLETE_WITH_LIST2("GROUP", "ROLE"); COMPLETE_WITH_LIST2("GROUP", "ROLE");

View File

@ -48,7 +48,6 @@ main(int argc, char *argv[])
{"connection-limit", required_argument, NULL, 'c'}, {"connection-limit", required_argument, NULL, 'c'},
{"pwprompt", no_argument, NULL, 'P'}, {"pwprompt", no_argument, NULL, 'P'},
{"encrypted", no_argument, NULL, 'E'}, {"encrypted", no_argument, NULL, 'E'},
{"unencrypted", no_argument, NULL, 'N'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
@ -75,8 +74,7 @@ main(int argc, char *argv[])
createrole = TRI_DEFAULT, createrole = TRI_DEFAULT,
inherit = TRI_DEFAULT, inherit = TRI_DEFAULT,
login = TRI_DEFAULT, login = TRI_DEFAULT,
replication = TRI_DEFAULT, replication = TRI_DEFAULT;
encrypted = TRI_DEFAULT;
PQExpBufferData sql; PQExpBufferData sql;
@ -88,7 +86,7 @@ main(int argc, char *argv[])
handle_help_version_opts(argc, argv, "createuser", help); handle_help_version_opts(argc, argv, "createuser", help);
while ((c = getopt_long(argc, argv, "h:p:U:g:wWedDsSaArRiIlLc:PEN", while ((c = getopt_long(argc, argv, "h:p:U:g:wWedDsSaArRiIlLc:PE",
long_options, &optindex)) != -1) long_options, &optindex)) != -1)
{ {
switch (c) switch (c)
@ -153,10 +151,7 @@ main(int argc, char *argv[])
pwprompt = true; pwprompt = true;
break; break;
case 'E': case 'E':
encrypted = TRI_YES; /* no-op, accepted for backward compatibility */
break;
case 'N':
encrypted = TRI_NO;
break; break;
case 1: case 1:
replication = TRI_YES; replication = TRI_YES;
@ -263,17 +258,11 @@ main(int argc, char *argv[])
printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser)); printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
if (newpassword) if (newpassword)
{
if (encrypted == TRI_YES)
appendPQExpBufferStr(&sql, " ENCRYPTED");
if (encrypted == TRI_NO)
appendPQExpBufferStr(&sql, " UNENCRYPTED");
appendPQExpBufferStr(&sql, " PASSWORD ");
if (encrypted != TRI_NO)
{ {
char *encrypted_password; char *encrypted_password;
appendPQExpBufferStr(&sql, " PASSWORD ");
encrypted_password = PQencryptPasswordConn(conn, encrypted_password = PQencryptPasswordConn(conn,
newpassword, newpassword,
newuser, newuser,
@ -287,9 +276,6 @@ main(int argc, char *argv[])
appendStringLiteralConn(&sql, encrypted_password, conn); appendStringLiteralConn(&sql, encrypted_password, conn);
PQfreemem(encrypted_password); PQfreemem(encrypted_password);
} }
else
appendStringLiteralConn(&sql, newpassword, conn);
}
if (superuser == TRI_YES) if (superuser == TRI_YES)
appendPQExpBufferStr(&sql, " SUPERUSER"); appendPQExpBufferStr(&sql, " SUPERUSER");
if (superuser == TRI_NO) if (superuser == TRI_NO)
@ -361,14 +347,12 @@ help(const char *progname)
printf(_(" -d, --createdb role can create new databases\n")); printf(_(" -d, --createdb role can create new databases\n"));
printf(_(" -D, --no-createdb role cannot create databases (default)\n")); printf(_(" -D, --no-createdb role cannot create databases (default)\n"));
printf(_(" -e, --echo show the commands being sent to the server\n")); printf(_(" -e, --echo show the commands being sent to the server\n"));
printf(_(" -E, --encrypted encrypt stored password\n"));
printf(_(" -g, --role=ROLE new role will be a member of this role\n")); printf(_(" -g, --role=ROLE new role will be a member of this role\n"));
printf(_(" -i, --inherit role inherits privileges of roles it is a\n" printf(_(" -i, --inherit role inherits privileges of roles it is a\n"
" member of (default)\n")); " member of (default)\n"));
printf(_(" -I, --no-inherit role does not inherit privileges\n")); printf(_(" -I, --no-inherit role does not inherit privileges\n"));
printf(_(" -l, --login role can login (default)\n")); printf(_(" -l, --login role can login (default)\n"));
printf(_(" -L, --no-login role cannot login\n")); printf(_(" -L, --no-login role cannot login\n"));
printf(_(" -N, --unencrypted do not encrypt stored password\n"));
printf(_(" -P, --pwprompt assign a password to new role\n")); printf(_(" -P, --pwprompt assign a password to new role\n"));
printf(_(" -r, --createrole role can create new roles\n")); printf(_(" -r, --createrole role can create new roles\n"));
printf(_(" -R, --no-createrole role cannot create roles (default)\n")); printf(_(" -R, --no-createrole role cannot create roles (default)\n"));

View File

@ -16,10 +16,13 @@
#include "datatype/timestamp.h" #include "datatype/timestamp.h"
/* /*
* Types of password hashes or verifiers that can be stored in * Types of password hashes or verifiers.
* pg_authid.rolpassword.
* *
* This is also used for the password_encryption GUC. * Plaintext passwords can be passed in by the user, in a CREATE/ALTER USER
* command. They will be encrypted to MD5 or SCRAM-SHA-256 format, before
* storing on-disk, so only MD5 and SCRAM-SHA-256 passwords should appear
* in pg_authid.rolpassword. They are also the allowed values for the
* password_encryption GUC.
*/ */
typedef enum PasswordType typedef enum PasswordType
{ {

View File

@ -1183,8 +1183,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
* send the password in plaintext even if it was "off". * send the password in plaintext even if it was "off".
*/ */
if (strcmp(algorithm, "on") == 0 || if (strcmp(algorithm, "on") == 0 ||
strcmp(algorithm, "off") == 0 || strcmp(algorithm, "off") == 0)
strcmp(algorithm, "plain") == 0)
algorithm = "md5"; algorithm = "md5";
/* /*

View File

@ -10,7 +10,7 @@ use strict;
use warnings; use warnings;
use PostgresNode; use PostgresNode;
use TestLib; use TestLib;
use Test::More tests => 12; use Test::More tests => 8;
# Delete pg_hba.conf from the given node, add a new entry to it # Delete pg_hba.conf from the given node, add a new entry to it
# and then execute a reload to refresh it. # and then execute a reload to refresh it.
@ -53,32 +53,26 @@ SKIP:
# password is used for all of them. # password is used for all of them.
$node->safe_psql('postgres', "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"); $node->safe_psql('postgres', "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';");
$node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';"); $node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';");
$node->safe_psql('postgres', "SET password_encryption='plain'; CREATE ROLE plain_role LOGIN PASSWORD 'pass';");
$ENV{"PGPASSWORD"} = 'pass'; $ENV{"PGPASSWORD"} = 'pass';
# For "trust" method, all users should be able to connect. # For "trust" method, all users should be able to connect.
reset_pg_hba($node, 'trust'); reset_pg_hba($node, 'trust');
test_role($node, 'scram_role', 'trust', 0); test_role($node, 'scram_role', 'trust', 0);
test_role($node, 'md5_role', 'trust', 0); test_role($node, 'md5_role', 'trust', 0);
test_role($node, 'plain_role', 'trust', 0);
# For plain "password" method, all users should also be able to connect. # For plain "password" method, all users should also be able to connect.
reset_pg_hba($node, 'password'); reset_pg_hba($node, 'password');
test_role($node, 'scram_role', 'password', 0); test_role($node, 'scram_role', 'password', 0);
test_role($node, 'md5_role', 'password', 0); test_role($node, 'md5_role', 'password', 0);
test_role($node, 'plain_role', 'password', 0);
# For "scram-sha-256" method, user "plain_role" and "scram_role" should # For "scram-sha-256" method, user "scram_role" should be able to connect.
# be able to connect.
reset_pg_hba($node, 'scram-sha-256'); reset_pg_hba($node, 'scram-sha-256');
test_role($node, 'scram_role', 'scram-sha-256', 0); test_role($node, 'scram_role', 'scram-sha-256', 0);
test_role($node, 'md5_role', 'scram-sha-256', 2); test_role($node, 'md5_role', 'scram-sha-256', 2);
test_role($node, 'plain_role', 'scram-sha-256', 0);
# For "md5" method, all users should be able to connect (SCRAM # For "md5" method, all users should be able to connect (SCRAM
# authentication will be performed for the user with a scram verifier.) # authentication will be performed for the user with a scram verifier.)
reset_pg_hba($node, 'md5'); reset_pg_hba($node, 'md5');
test_role($node, 'scram_role', 'md5', 0); test_role($node, 'scram_role', 'md5', 0);
test_role($node, 'md5_role', 'md5', 0); test_role($node, 'md5_role', 'md5', 0);
test_role($node, 'plain_role', 'md5', 0);
} }

View File

@ -4,22 +4,18 @@
-- Tests for GUC password_encryption -- Tests for GUC password_encryption
SET password_encryption = 'novalue'; -- error SET password_encryption = 'novalue'; -- error
ERROR: invalid value for parameter "password_encryption": "novalue" ERROR: invalid value for parameter "password_encryption": "novalue"
HINT: Available values: plain, md5, scram-sha-256, off, on. HINT: Available values: md5, scram-sha-256.
SET password_encryption = true; -- ok SET password_encryption = true; -- ok
SET password_encryption = 'md5'; -- ok SET password_encryption = 'md5'; -- ok
SET password_encryption = 'plain'; -- ok
SET password_encryption = 'scram-sha-256'; -- ok SET password_encryption = 'scram-sha-256'; -- ok
-- consistency of password entries -- consistency of password entries
SET password_encryption = 'plain';
CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'md5'; SET password_encryption = 'md5';
CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'on'; SET password_encryption = 'on';
CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
SET password_encryption = 'scram-sha-256'; SET password_encryption = 'scram-sha-256';
CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
SET password_encryption = 'plain'; CREATE ROLE regress_passwd4 PASSWORD NULL;
CREATE ROLE regress_passwd5 PASSWORD NULL;
-- check list of created entries -- check list of created entries
-- --
-- The scram verifier will look something like: -- The scram verifier will look something like:
@ -33,56 +29,57 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
ORDER BY rolname, rolpassword; ORDER BY rolname, rolpassword;
rolname | rolpassword_masked rolname | rolpassword_masked
-----------------+--------------------------------------------------- -----------------+---------------------------------------------------
regress_passwd1 | role_pwd1 regress_passwd1 | md5783277baca28003b33453252be4dbb34
regress_passwd2 | md54044304ba511dd062133eb5b4b84a2a3 regress_passwd2 | md54044304ba511dd062133eb5b4b84a2a3
regress_passwd3 | md50e5699b6911d87f17a08b8d76a21e8b8 regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> regress_passwd4 |
regress_passwd5 | (4 rows)
(5 rows)
-- Rename a role -- Rename a role
ALTER ROLE regress_passwd3 RENAME TO regress_passwd3_new; ALTER ROLE regress_passwd2 RENAME TO regress_passwd2_new;
NOTICE: MD5 password cleared because of role rename NOTICE: MD5 password cleared because of role rename
-- md5 entry should have been removed -- md5 entry should have been removed
SELECT rolname, rolpassword SELECT rolname, rolpassword
FROM pg_authid FROM pg_authid
WHERE rolname LIKE 'regress_passwd3_new' WHERE rolname LIKE 'regress_passwd2_new'
ORDER BY rolname, rolpassword; ORDER BY rolname, rolpassword;
rolname | rolpassword rolname | rolpassword
---------------------+------------- ---------------------+-------------
regress_passwd3_new | regress_passwd2_new |
(1 row) (1 row)
ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3; ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2;
-- ENCRYPTED and UNENCRYPTED passwords -- Change passwords with ALTER USER. With plaintext or already-encrypted
ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted -- passwords.
ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5
SET password_encryption = 'md5'; SET password_encryption = 'md5';
ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5 -- encrypt with MD5
ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo='; -- client-supplied SCRAM verifier, use as it is ALTER ROLE regress_passwd2 PASSWORD 'foo';
-- already encrypted, use as they are
ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
ALTER ROLE regress_passwd3 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
SET password_encryption = 'scram-sha-256'; SET password_encryption = 'scram-sha-256';
ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier -- create SCRAM verifier
CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is ALTER ROLE regress_passwd4 PASSWORD 'foo';
-- already encrypted with MD5, use as it is
CREATE ROLE regress_passwd5 PASSWORD 'md5e73a4b11df52a6068f8b39f90be36023';
SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked
FROM pg_authid FROM pg_authid
WHERE rolname LIKE 'regress_passwd%' WHERE rolname LIKE 'regress_passwd%'
ORDER BY rolname, rolpassword; ORDER BY rolname, rolpassword;
rolname | rolpassword_masked rolname | rolpassword_masked
-----------------+--------------------------------------------------- -----------------+---------------------------------------------------
regress_passwd1 | foo regress_passwd1 | md5cd3578025fe2c3d7ed1b9a9b26238b70
regress_passwd2 | md5dfa155cadd5f4ad57860162f3fab9cdb regress_passwd2 | md5dfa155cadd5f4ad57860162f3fab9cdb
regress_passwd3 | md5530de4c298af94b3b9f7d20305d2a1bf regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
regress_passwd5 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> regress_passwd5 | md5e73a4b11df52a6068f8b39f90be36023
regress_passwd6 | md53725413363ab045e20521bf36b8d8d7f (5 rows)
(6 rows)
DROP ROLE regress_passwd1; DROP ROLE regress_passwd1;
DROP ROLE regress_passwd2; DROP ROLE regress_passwd2;
DROP ROLE regress_passwd3; DROP ROLE regress_passwd3;
DROP ROLE regress_passwd4; DROP ROLE regress_passwd4;
DROP ROLE regress_passwd5; DROP ROLE regress_passwd5;
DROP ROLE regress_passwd6;
-- all entries should have been removed -- all entries should have been removed
SELECT rolname, rolpassword SELECT rolname, rolpassword
FROM pg_authid FROM pg_authid

View File

@ -6,20 +6,16 @@
SET password_encryption = 'novalue'; -- error SET password_encryption = 'novalue'; -- error
SET password_encryption = true; -- ok SET password_encryption = true; -- ok
SET password_encryption = 'md5'; -- ok SET password_encryption = 'md5'; -- ok
SET password_encryption = 'plain'; -- ok
SET password_encryption = 'scram-sha-256'; -- ok SET password_encryption = 'scram-sha-256'; -- ok
-- consistency of password entries -- consistency of password entries
SET password_encryption = 'plain';
CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'md5'; SET password_encryption = 'md5';
CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'on'; SET password_encryption = 'on';
CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
SET password_encryption = 'scram-sha-256'; SET password_encryption = 'scram-sha-256';
CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
SET password_encryption = 'plain'; CREATE ROLE regress_passwd4 PASSWORD NULL;
CREATE ROLE regress_passwd5 PASSWORD NULL;
-- check list of created entries -- check list of created entries
-- --
@ -34,25 +30,29 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
ORDER BY rolname, rolpassword; ORDER BY rolname, rolpassword;
-- Rename a role -- Rename a role
ALTER ROLE regress_passwd3 RENAME TO regress_passwd3_new; ALTER ROLE regress_passwd2 RENAME TO regress_passwd2_new;
-- md5 entry should have been removed -- md5 entry should have been removed
SELECT rolname, rolpassword SELECT rolname, rolpassword
FROM pg_authid FROM pg_authid
WHERE rolname LIKE 'regress_passwd3_new' WHERE rolname LIKE 'regress_passwd2_new'
ORDER BY rolname, rolpassword; ORDER BY rolname, rolpassword;
ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3; ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2;
-- ENCRYPTED and UNENCRYPTED passwords -- Change passwords with ALTER USER. With plaintext or already-encrypted
ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted -- passwords.
ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5
SET password_encryption = 'md5'; SET password_encryption = 'md5';
ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5
ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo='; -- client-supplied SCRAM verifier, use as it is -- encrypt with MD5
ALTER ROLE regress_passwd2 PASSWORD 'foo';
-- already encrypted, use as they are
ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
ALTER ROLE regress_passwd3 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
SET password_encryption = 'scram-sha-256'; SET password_encryption = 'scram-sha-256';
ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier -- create SCRAM verifier
CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is ALTER ROLE regress_passwd4 PASSWORD 'foo';
-- already encrypted with MD5, use as it is
CREATE ROLE regress_passwd5 PASSWORD 'md5e73a4b11df52a6068f8b39f90be36023';
SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/=]+)\$([a-zA-Z0-9+=/]+):([a-zA-Z0-9+/=]+)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked
FROM pg_authid FROM pg_authid
@ -64,7 +64,6 @@ DROP ROLE regress_passwd2;
DROP ROLE regress_passwd3; DROP ROLE regress_passwd3;
DROP ROLE regress_passwd4; DROP ROLE regress_passwd4;
DROP ROLE regress_passwd5; DROP ROLE regress_passwd5;
DROP ROLE regress_passwd6;
-- all entries should have been removed -- all entries should have been removed
SELECT rolname, rolpassword SELECT rolname, rolpassword