diff options
-rw-r--r-- | contrib/passwordcheck/passwordcheck.c | 4 | ||||
-rw-r--r-- | doc/src/sgml/config.sgml | 18 | ||||
-rw-r--r-- | doc/src/sgml/ref/alter_role.sgml | 6 | ||||
-rw-r--r-- | doc/src/sgml/ref/alter_user.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_group.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_role.sgml | 34 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_user.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/createuser.sgml | 21 | ||||
-rw-r--r-- | src/backend/commands/user.c | 34 | ||||
-rw-r--r-- | src/backend/libpq/auth-scram.c | 20 | ||||
-rw-r--r-- | src/backend/libpq/auth.c | 26 | ||||
-rw-r--r-- | src/backend/libpq/crypt.c | 126 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 14 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 10 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.c | 25 | ||||
-rw-r--r-- | src/bin/scripts/createuser.c | 46 | ||||
-rw-r--r-- | src/include/libpq/crypt.h | 9 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 3 | ||||
-rw-r--r-- | src/test/authentication/t/001_password.pl | 10 | ||||
-rw-r--r-- | src/test/regress/expected/password.out | 59 | ||||
-rw-r--r-- | src/test/regress/sql/password.sql | 37 |
21 files changed, 177 insertions, 331 deletions
diff --git a/contrib/passwordcheck/passwordcheck.c b/contrib/passwordcheck/passwordcheck.c index c988bf5169b..59f73a1e6ba 100644 --- a/contrib/passwordcheck/passwordcheck.c +++ b/contrib/passwordcheck/passwordcheck.c @@ -39,8 +39,8 @@ extern void _PG_init(void); * * username: name of role being created or changed * password: new password (possibly already encrypted) - * password_type: PASSWORD_TYPE_PLAINTEXT or PASSWORD_TYPE_MD5 (there - * could be other encryption schemes in future) + * password_type: PASSWORD_TYPE_* code, to indicate if the password is + * in plaintext or encrypted form. * validuntil_time: password expiration time, as a timestamptz Datum * validuntil_null: true if password expiration time is NULL * diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 0b9e3002fb6..20bc3c61b12 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -1188,14 +1188,16 @@ include_dir 'conf.d' <listitem> <para> When a password is specified in <xref linkend="sql-createrole"> or - <xref linkend="sql-alterrole"> without writing either <literal>ENCRYPTED</> - or <literal>UNENCRYPTED</>, this parameter determines whether the - password is to be encrypted. The default value is <literal>md5</>, which - stores the password as an MD5 hash. Setting this to <literal>plain</> stores - it in plaintext. <literal>on</> and <literal>off</> are also accepted, as - aliases for <literal>md5</> and <literal>plain</>, respectively. Setting - this parameter to <literal>scram-sha-256</> will encrypt the password - with SCRAM-SHA-256. + <xref linkend="sql-alterrole">, this parameter determines the algorithm + to use to encrypt the password. The default value is <literal>md5</>, + which stores the password as an MD5 hash (<literal>on</> is also + accepted, as alias for <literal>md5</>). Setting this parameter to + <literal>scram-sha-256</> will encrypt the password with SCRAM-SHA-256. + </para> + <para> + Note that older clients might lack support for the SCRAM authentication + mechanism, and hence not work with passwords encrypted with + SCRAM-SHA-256. </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index 37fcfb926c1..8cd8602bc4f 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -33,7 +33,7 @@ ALTER ROLE <replaceable class="PARAMETER">role_specification</replaceable> [ WIT | REPLICATION | NOREPLICATION | BYPASSRLS | NOBYPASSRLS | 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>' 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>NOBYPASSRLS</literal></term> <term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term> - <term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> - <term><literal>ENCRYPTED</></term> - <term><literal>UNENCRYPTED</></term> + <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> <term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term> <listitem> <para> diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 5962a8e166c..9b8a39b3768 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -33,7 +33,7 @@ ALTER USER <replaceable class="PARAMETER">role_specification</replaceable> [ WIT | REPLICATION | NOREPLICATION | BYPASSRLS | NOBYPASSRLS | 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>' ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> diff --git a/doc/src/sgml/ref/create_group.sgml b/doc/src/sgml/ref/create_group.sgml index 1d5cc9b5969..158617cb939 100644 --- a/doc/src/sgml/ref/create_group.sgml +++ b/doc/src/sgml/ref/create_group.sgml @@ -30,7 +30,7 @@ CREATE GROUP <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <repla | CREATEROLE | NOCREATEROLE | INHERIT | NOINHERIT | LOGIN | NOLOGIN - | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' + | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>' | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>' | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...] diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml index 99d1c8336c4..43f2303b481 100644 --- a/doc/src/sgml/ref/create_role.sgml +++ b/doc/src/sgml/ref/create_role.sgml @@ -33,7 +33,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac | REPLICATION | NOREPLICATION | BYPASSRLS | NOBYPASSRLS | 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>' | IN ROLE <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> - <term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> + <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term> <listitem> <para> 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 <literal>PASSWORD NULL</literal>. </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>ENCRYPTED</></term> - <term><literal>UNENCRYPTED</></term> - <listitem> <para> - These key words control whether the password is stored - encrypted in the system catalogs. (If neither is specified, - the default behavior is determined by the configuration - parameter <xref linkend="guc-password-encryption">.) If the - presented password string is already in MD5-encrypted or - SCRAM-encrypted format, then it is stored encrypted as-is, - regardless of whether <literal>ENCRYPTED</> or <literal>UNENCRYPTED</> - is specified (since the system cannot decrypt the specified encrypted - password string). This allows reloading of encrypted passwords + The password is always stored encrypted in the system catalogs. The + <literal>ENCRYPTED</> keyword has no effect, but is accepted for + backwards compatibility. The method of encryption is determined + by the configuration parameter <xref linkend="guc-password-encryption">. + If the presented password string is already in MD5-encrypted or + SCRAM-encrypted format, then it is stored as-is regardless of + <varname>password_encryption</> (since the system cannot decrypt + the specified encrypted password string, to encrypt it in a + different format). This allows reloading of encrypted passwords during dump/restore. </para> - - <para> - Note that older clients might lack support for the SCRAM - authentication mechanism. - </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml index 574604f796d..8a596eec9f2 100644 --- a/doc/src/sgml/ref/create_user.sgml +++ b/doc/src/sgml/ref/create_user.sgml @@ -33,7 +33,7 @@ CREATE USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac | REPLICATION | NOREPLICATION | BYPASSRLS | NOBYPASSRLS | 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>' | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...] | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...] diff --git a/doc/src/sgml/ref/createuser.sgml b/doc/src/sgml/ref/createuser.sgml index 4332008c68b..fda77976ff2 100644 --- a/doc/src/sgml/ref/createuser.sgml +++ b/doc/src/sgml/ref/createuser.sgml @@ -124,8 +124,8 @@ PostgreSQL documentation <term><option>--encrypted</></term> <listitem> <para> - Encrypts the user's password stored in the database. If not - specified, the default password behavior is used. + This option is obsolete but still accepted for backward + compatibility. </para> </listitem> </varlistentry> @@ -205,17 +205,6 @@ PostgreSQL documentation </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> <term><option>-P</></term> <term><option>--pwprompt</></term> <listitem> @@ -481,11 +470,7 @@ PostgreSQL documentation </screen> 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 - encrypted before it is sent to the client. If the option <option>--unencrypted</option> - 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. + encrypted before it is sent to the client. </para> </refsect1> diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index c719682274d..36d5f40f062 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -80,7 +80,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) ListCell *item; ListCell *option; char *password = NULL; /* user password */ - int password_type = Password_encryption; bool issuper = false; /* Make the user a superuser? */ bool inherit = true; /* Auto inherit privileges? */ bool createrole = false; /* Can this user create roles? */ @@ -128,9 +127,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) { DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "password") == 0 || - strcmp(defel->defname, "encryptedPassword") == 0 || - strcmp(defel->defname, "unencryptedPassword") == 0) + if (strcmp(defel->defname, "password") == 0) { if (dpassword) ereport(ERROR, @@ -138,15 +135,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); 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) { @@ -400,7 +388,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) /* Encrypt the password to the requested format. */ 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] = CStringGetTextDatum(shadow_pass); } @@ -503,7 +492,6 @@ AlterRole(AlterRoleStmt *stmt) ListCell *option; char *rolename = NULL; char *password = NULL; /* user password */ - int password_type = Password_encryption; int issuper = -1; /* Make the user a superuser? */ int inherit = -1; /* Auto inherit privileges? */ int createrole = -1; /* Can this user create roles? */ @@ -537,24 +525,13 @@ AlterRole(AlterRoleStmt *stmt) { DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "password") == 0 || - strcmp(defel->defname, "encryptedPassword") == 0 || - strcmp(defel->defname, "unencryptedPassword") == 0) + if (strcmp(defel->defname, "password") == 0) { if (dpassword) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); 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) { @@ -809,7 +786,8 @@ AlterRole(AlterRoleStmt *stmt) /* Encrypt the password to the requested format. */ 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] = CStringGetTextDatum(shadow_pass); new_record_repl[Anum_pg_authid_rolpassword - 1] = true; diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 3acc2acfe41..99feb0ce947 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -199,27 +199,11 @@ pg_be_scram_init(const char *username, const char *shadow_pass) 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 { /* - * The user doesn't have SCRAM verifier, nor could we generate - * one. (You cannot do SCRAM authentication with an MD5 hash.) + * The user doesn't have SCRAM verifier. (You cannot do SCRAM + * authentication with an MD5 hash.) */ state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."), state->username); diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index ab4be219431..6d3ff68607d 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -754,17 +754,13 @@ CheckPWChallengeAuth(Port *port, char **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 - * motions of authentication, to avoid revealing to the client that the - * user didn't exist. If 'md5' is allowed, we choose whether to use 'md5' - * or 'scram-sha-256' authentication based on current password_encryption - * setting. The idea is that most genuine users probably have a password - * of that type, if we pretend that 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 the user does not exist, or has no password or it's expired, we + * still go through the motions of authentication, to avoid revealing to + * the client that the user didn't exist. If 'md5' is allowed, we choose + * whether to use 'md5' or 'scram-sha-256' authentication based on + * current password_encryption setting. The idea is that most genuine + * users probably have a password of that type, and if we pretend that + * this user had a password of that type, too, it "blends in" best. */ if (!shadow_pass) pwtype = Password_encryption; @@ -775,21 +771,15 @@ CheckPWChallengeAuth(Port *port, char **logdetail) * If 'md5' authentication is allowed, decide whether to perform 'md5' or * '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 - * a SCRAM verifier, we must do SCRAM authentication. If it's stored in - * plaintext, we could do either one, so we opt for the more secure - * mechanism, SCRAM. + * a SCRAM verifier, we must do SCRAM authentication. * * If MD5 authentication is not allowed, always use SCRAM. If the user * had an MD5 password, CheckSCRAMAuth() will fail. */ if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5) - { auth_result = CheckMD5Auth(port, shadow_pass, logdetail); - } else - { auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail); - } if (shadow_pass) pfree(shadow_pass); diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 9fe79b48946..e7a6b04fb5a 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -109,9 +109,8 @@ get_password_type(const char *shadow_pass) * Given a user-supplied password, convert it into a verifier of * 'target_type' kind. * - * If the password looks like a valid MD5 hash, it is stored as it is. - * We cannot reverse the hash, so even if the caller requested a plaintext - * plaintext password, the MD5 hash is returned. + * If the password is already in encrypted form, we cannot reverse the + * hash, so it is stored as it is regardless of the requested type. */ char * encrypt_password(PasswordType target_type, const char *role, @@ -120,54 +119,30 @@ encrypt_password(PasswordType target_type, const char *role, PasswordType guessed_type = get_password_type(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 - * store the password as it was, whether it was hashed or not. - */ - return pstrdup(password); + /* + * Cannot convert an already-encrypted password from one + * format to another, so return it as it is. + */ + return pstrdup(password); + } + switch (target_type) + { case PASSWORD_TYPE_MD5: - switch (guessed_type) - { - case PASSWORD_TYPE_PLAINTEXT: - encrypted_password = palloc(MD5_PASSWD_LEN + 1); - - if (!pg_md5_encrypt(password, role, strlen(role), - encrypted_password)) - elog(ERROR, "password encryption failed"); - return encrypted_password; + encrypted_password = palloc(MD5_PASSWD_LEN + 1); - 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; + if (!pg_md5_encrypt(password, role, strlen(role), + encrypted_password)) + elog(ERROR, "password encryption failed"); + return encrypted_password; case PASSWORD_TYPE_SCRAM_SHA_256: - switch (guessed_type) - { - case PASSWORD_TYPE_PLAINTEXT: - return pg_be_scram_build_verifier(password); - - case PASSWORD_TYPE_MD5: + return pg_be_scram_build_verifier(password); - /* - * 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; + case PASSWORD_TYPE_PLAINTEXT: + elog(ERROR, "cannot encrypt password with 'plaintext'"); } /* @@ -197,10 +172,17 @@ md5_crypt_verify(const char *role, const char *shadow_pass, { int retval; char crypt_pwd[MD5_PASSWD_LEN + 1]; - char crypt_pwd2[MD5_PASSWD_LEN + 1]; 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. * @@ -208,40 +190,12 @@ md5_crypt_verify(const char *role, const char *shadow_pass, * 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. */ - switch (get_password_type(shadow_pass)) + /* stored password already encrypted, only do salt */ + if (!pg_md5_encrypt(shadow_pass + strlen("md5"), + md5_salt, md5_salt_len, + crypt_pwd)) { - case PASSWORD_TYPE_MD5: - /* stored password already encrypted, only do salt */ - if (!pg_md5_encrypt(shadow_pass + strlen("md5"), - md5_salt, md5_salt_len, - crypt_pwd)) - { - 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; + return STATUS_ERROR; } if (strcmp(client_pass, crypt_pwd) == 0) @@ -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. * - * 'shadow_pass' is the user's correct password or password hash, as stored - * in pg_authid.rolpassword. + * 'shadow_pass' is the user's correct password hash, as stored in + * pg_authid.rolpassword. * 'client_pass' is the password given by the remote user. * * 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; case PASSWORD_TYPE_PLAINTEXT: - if (strcmp(client_pass, shadow_pass) == 0) - return STATUS_OK; - else - { - *logdetail = psprintf(_("Password does not match for user \"%s\"."), - role); - return STATUS_ERROR; - } + /* + * We never store passwords in plaintext, so this shouldn't + * happen. + */ break; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 818d2c29d49..2cad8b25b8a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -994,13 +994,21 @@ AlterOptRoleElem: } | 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); } | UNENCRYPTED PASSWORD Sconst { - $$ = makeDefElem("unencryptedPassword", - (Node *)makeString($3), @1); + ereport(ERROR, + (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 { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 587fbce147f..cb4e621c848 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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 - * 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[] = { - {"plain", PASSWORD_TYPE_PLAINTEXT, false}, {"md5", PASSWORD_TYPE_MD5, false}, {"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false}, - {"off", PASSWORD_TYPE_PLAINTEXT, false}, - {"on", PASSWORD_TYPE_MD5, false}, + {"on", PASSWORD_TYPE_MD5, true}, {"true", PASSWORD_TYPE_MD5, true}, - {"false", PASSWORD_TYPE_PLAINTEXT, true}, {"yes", PASSWORD_TYPE_MD5, true}, - {"no", PASSWORD_TYPE_PLAINTEXT, true}, {"1", PASSWORD_TYPE_MD5, true}, - {"0", PASSWORD_TYPE_PLAINTEXT, true}, {NULL, 0, false} }; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e2a33512104..183fc376296 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1634,10 +1634,10 @@ psql_completion(const char *text, int start, int end) { static const char *const list_ALTERUSER[] = {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", - "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS", + "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", - "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", + "REPLICATION", "RESET", "SET", "SUPERUSER", "VALID UNTIL", "WITH", NULL}; 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. */ static const char *const list_ALTERUSER_WITH[] = {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", - "ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS", + "ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO", - "REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED", + "REPLICATION", "RESET", "SET", "SUPERUSER", "VALID UNTIL", NULL}; 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 */ else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES")) 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[] = {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", + "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", - "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED", + "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "VALID UNTIL", "WITH", NULL}; 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. */ static const char *const list_CREATEROLE_WITH[] = {"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", - "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", + "ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS", "NOCREATEDB", "NOCREATEROLE", "NOINHERIT", "NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", - "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED", + "REPLICATION", "ROLE", "SUPERUSER", "SYSID", "VALID UNTIL", NULL}; 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 */ else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN")) COMPLETE_WITH_LIST2("GROUP", "ROLE"); diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index 35a53bf2064..d88093f8b6e 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -48,7 +48,6 @@ main(int argc, char *argv[]) {"connection-limit", required_argument, NULL, 'c'}, {"pwprompt", no_argument, NULL, 'P'}, {"encrypted", no_argument, NULL, 'E'}, - {"unencrypted", no_argument, NULL, 'N'}, {NULL, 0, NULL, 0} }; @@ -75,8 +74,7 @@ main(int argc, char *argv[]) createrole = TRI_DEFAULT, inherit = TRI_DEFAULT, login = TRI_DEFAULT, - replication = TRI_DEFAULT, - encrypted = TRI_DEFAULT; + replication = TRI_DEFAULT; PQExpBufferData sql; @@ -88,7 +86,7 @@ main(int argc, char *argv[]) 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) { switch (c) @@ -153,10 +151,7 @@ main(int argc, char *argv[]) pwprompt = true; break; case 'E': - encrypted = TRI_YES; - break; - case 'N': - encrypted = TRI_NO; + /* no-op, accepted for backward compatibility */ break; case 1: replication = TRI_YES; @@ -264,31 +259,22 @@ main(int argc, char *argv[]) printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser)); if (newpassword) { - if (encrypted == TRI_YES) - appendPQExpBufferStr(&sql, " ENCRYPTED"); - if (encrypted == TRI_NO) - appendPQExpBufferStr(&sql, " UNENCRYPTED"); + char *encrypted_password; + appendPQExpBufferStr(&sql, " PASSWORD "); - if (encrypted != TRI_NO) + encrypted_password = PQencryptPasswordConn(conn, + newpassword, + newuser, + NULL); + if (!encrypted_password) { - char *encrypted_password; - - encrypted_password = PQencryptPasswordConn(conn, - newpassword, - newuser, - NULL); - if (!encrypted_password) - { - fprintf(stderr, _("%s: password encryption failed: %s"), - progname, PQerrorMessage(conn)); - exit(1); - } - appendStringLiteralConn(&sql, encrypted_password, conn); - PQfreemem(encrypted_password); + fprintf(stderr, _("%s: password encryption failed: %s"), + progname, PQerrorMessage(conn)); + exit(1); } - else - appendStringLiteralConn(&sql, newpassword, conn); + appendStringLiteralConn(&sql, encrypted_password, conn); + PQfreemem(encrypted_password); } if (superuser == TRI_YES) appendPQExpBufferStr(&sql, " SUPERUSER"); @@ -361,14 +347,12 @@ help(const char *progname) printf(_(" -d, --createdb role can create new databases\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, --encrypted encrypt stored password\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" " member of (default)\n")); printf(_(" -I, --no-inherit role does not inherit privileges\n")); printf(_(" -l, --login role can login (default)\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(_(" -r, --createrole role can create new roles\n")); printf(_(" -R, --no-createrole role cannot create roles (default)\n")); diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 63724f39ee2..9bad67c8902 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -16,10 +16,13 @@ #include "datatype/timestamp.h" /* - * Types of password hashes or verifiers that can be stored in - * pg_authid.rolpassword. + * Types of password hashes or verifiers. * - * 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 { diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 54acd0f6bf8..f4397afc649 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -1183,8 +1183,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, * send the password in plaintext even if it was "off". */ if (strcmp(algorithm, "on") == 0 || - strcmp(algorithm, "off") == 0 || - strcmp(algorithm, "plain") == 0) + strcmp(algorithm, "off") == 0) algorithm = "md5"; /* diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl index 216bdc031c8..5a21ecd7e66 100644 --- a/src/test/authentication/t/001_password.pl +++ b/src/test/authentication/t/001_password.pl @@ -10,7 +10,7 @@ use strict; use warnings; use PostgresNode; 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 # and then execute a reload to refresh it. @@ -53,32 +53,26 @@ SKIP: # 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='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'; # For "trust" method, all users should be able to connect. reset_pg_hba($node, 'trust'); test_role($node, 'scram_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. reset_pg_hba($node, 'password'); test_role($node, 'scram_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 - # be able to connect. + # For "scram-sha-256" method, user "scram_role" should be able to connect. reset_pg_hba($node, 'scram-sha-256'); test_role($node, 'scram_role', 'scram-sha-256', 0); 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 # authentication will be performed for the user with a scram verifier.) reset_pg_hba($node, 'md5'); test_role($node, 'scram_role', 'md5', 0); test_role($node, 'md5_role', 'md5', 0); - test_role($node, 'plain_role', 'md5', 0); } diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out index 5b0b955b29b..bb25ad0c2cf 100644 --- a/src/test/regress/expected/password.out +++ b/src/test/regress/expected/password.out @@ -4,22 +4,18 @@ -- Tests for GUC password_encryption SET password_encryption = 'novalue'; -- error 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 = 'md5'; -- ok -SET password_encryption = 'plain'; -- ok SET password_encryption = 'scram-sha-256'; -- ok -- consistency of password entries -SET password_encryption = 'plain'; -CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1'; SET password_encryption = 'md5'; -CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; +CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1'; SET password_encryption = 'on'; -CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; +CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; SET password_encryption = 'scram-sha-256'; -CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; -SET password_encryption = 'plain'; -CREATE ROLE regress_passwd5 PASSWORD NULL; +CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; +CREATE ROLE regress_passwd4 PASSWORD NULL; -- check list of created entries -- -- 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; rolname | rolpassword_masked -----------------+--------------------------------------------------- - regress_passwd1 | role_pwd1 + regress_passwd1 | md5783277baca28003b33453252be4dbb34 regress_passwd2 | md54044304ba511dd062133eb5b4b84a2a3 - regress_passwd3 | md50e5699b6911d87f17a08b8d76a21e8b8 - regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> - regress_passwd5 | -(5 rows) + regress_passwd3 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> + regress_passwd4 | +(4 rows) -- 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 -- md5 entry should have been removed SELECT rolname, rolpassword FROM pg_authid - WHERE rolname LIKE 'regress_passwd3_new' + WHERE rolname LIKE 'regress_passwd2_new' ORDER BY rolname, rolpassword; rolname | rolpassword ---------------------+------------- - regress_passwd3_new | + regress_passwd2_new | (1 row) -ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3; --- ENCRYPTED and UNENCRYPTED passwords -ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted -ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5 +ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2; +-- Change passwords with ALTER USER. With plaintext or already-encrypted +-- passwords. 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'; -ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier -CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is +-- create SCRAM verifier +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 FROM pg_authid WHERE rolname LIKE 'regress_passwd%' ORDER BY rolname, rolpassword; rolname | rolpassword_masked -----------------+--------------------------------------------------- - regress_passwd1 | foo + regress_passwd1 | md5cd3578025fe2c3d7ed1b9a9b26238b70 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_passwd5 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey> - regress_passwd6 | md53725413363ab045e20521bf36b8d8d7f -(6 rows) + regress_passwd5 | md5e73a4b11df52a6068f8b39f90be36023 +(5 rows) DROP ROLE regress_passwd1; DROP ROLE regress_passwd2; DROP ROLE regress_passwd3; DROP ROLE regress_passwd4; DROP ROLE regress_passwd5; -DROP ROLE regress_passwd6; -- all entries should have been removed SELECT rolname, rolpassword FROM pg_authid diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql index d2e9eea79d2..f1682437254 100644 --- a/src/test/regress/sql/password.sql +++ b/src/test/regress/sql/password.sql @@ -6,20 +6,16 @@ SET password_encryption = 'novalue'; -- error SET password_encryption = true; -- ok SET password_encryption = 'md5'; -- ok -SET password_encryption = 'plain'; -- ok SET password_encryption = 'scram-sha-256'; -- ok -- consistency of password entries -SET password_encryption = 'plain'; -CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1'; SET password_encryption = 'md5'; -CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; +CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1'; SET password_encryption = 'on'; -CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; +CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2'; SET password_encryption = 'scram-sha-256'; -CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4'; -SET password_encryption = 'plain'; -CREATE ROLE regress_passwd5 PASSWORD NULL; +CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3'; +CREATE ROLE regress_passwd4 PASSWORD NULL; -- 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; -- 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 SELECT rolname, rolpassword FROM pg_authid - WHERE rolname LIKE 'regress_passwd3_new' + WHERE rolname LIKE 'regress_passwd2_new' 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 -ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted -ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5 +-- Change passwords with ALTER USER. With plaintext or already-encrypted +-- passwords. 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'; -ALTER ROLE regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier -CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is +-- create SCRAM verifier +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 FROM pg_authid @@ -64,7 +64,6 @@ DROP ROLE regress_passwd2; DROP ROLE regress_passwd3; DROP ROLE regress_passwd4; DROP ROLE regress_passwd5; -DROP ROLE regress_passwd6; -- all entries should have been removed SELECT rolname, rolpassword |