*
* 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
*
<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>
| 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>
<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>
| 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>
| 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> [, ...]
| 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> [, ...]
</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
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>
| 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> [, ...]
<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>
</listitem>
</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>
</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>
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? */
{
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,
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)
{
/* 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);
}
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? */
{
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)
{
/* 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;
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);
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;
* 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);
* 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,
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'");
}
/*
{
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.
*
* 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)
/*
* 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
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;
}
}
| 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
{
/*
* 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}
};
{
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);
/* 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");
{
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);
/* 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");
{"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}
};
createrole = TRI_DEFAULT,
inherit = TRI_DEFAULT,
login = TRI_DEFAULT,
- replication = TRI_DEFAULT,
- encrypted = TRI_DEFAULT;
+ replication = TRI_DEFAULT;
PQExpBufferData sql;
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)
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;
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");
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"));
#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
{
* 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";
/*
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.
# 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);
}
-- 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:
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
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
--
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
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