Turn password_encryption GUC into an enum.

This makes the parameter easier to extend, to support other password-based
authentication protocols than MD5. (SCRAM is being worked on.)

The GUC still accepts on/off as aliases for "md5" and "plain", although
we may want to remove those once we actually add support for another
password hash type.

Michael Paquier, reviewed by David Steele, with some further edits by me.

Discussion: <CAB7nPqSMXU35g=W9X74HVeQp0uvgJxvYOuA4A-A3M+0wfEBv-w@mail.gmail.com>
This commit is contained in:
Heikki Linnakangas 2016-09-28 12:22:44 +03:00
parent 72daabc7a3
commit babe05bc2b
5 changed files with 62 additions and 34 deletions

View File

@ -1163,21 +1163,22 @@ include_dir 'conf.d'
</varlistentry> </varlistentry>
<varlistentry id="guc-password-encryption" xreflabel="password_encryption"> <varlistentry id="guc-password-encryption" xreflabel="password_encryption">
<term><varname>password_encryption</varname> (<type>boolean</type>) <term><varname>password_encryption</varname> (<type>enum</type>)
<indexterm> <indexterm>
<primary><varname>password_encryption</> configuration parameter</primary> <primary><varname>password_encryption</> configuration parameter</primary>
</indexterm> </indexterm>
</term> </term>
<listitem> <listitem>
<para> <para>
When a password is specified in <xref When a password is specified in <xref linkend="sql-createuser"> or
linkend="sql-createuser"> or <xref linkend="sql-alterrole"> without writing either <literal>ENCRYPTED</>
<xref linkend="sql-alterrole"> or <literal>UNENCRYPTED</>, this parameter determines whether the
without writing either <literal>ENCRYPTED</> or password is to be encrypted. The default value is <literal>md5</>, which
<literal>UNENCRYPTED</>, this parameter determines whether the stores the password as an MD5 hash. Setting this to <literal>plain</> stores
password is to be encrypted. The default is <literal>on</> it in plaintext. <literal>on</> and <literal>off</> are also accepted, as
(encrypt the password). aliases for <literal>md5</> and <literal>plain</>, respectively.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -44,7 +44,7 @@ Oid binary_upgrade_next_pg_authid_oid = InvalidOid;
/* GUC parameter */ /* GUC parameter */
extern bool Password_encryption; int Password_encryption = PASSWORD_TYPE_MD5;
/* Hook to check passwords in CreateRole() and AlterRole() */ /* Hook to check passwords in CreateRole() and AlterRole() */
check_password_hook_type check_password_hook = NULL; check_password_hook_type check_password_hook = NULL;
@ -80,7 +80,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
ListCell *item; ListCell *item;
ListCell *option; ListCell *option;
char *password = NULL; /* user password */ char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */ int password_type = Password_encryption;
char encrypted_password[MD5_PASSWD_LEN + 1]; char encrypted_password[MD5_PASSWD_LEN + 1];
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? */
@ -140,9 +140,9 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
parser_errposition(pstate, defel->location))); parser_errposition(pstate, defel->location)));
dpassword = defel; dpassword = defel;
if (strcmp(defel->defname, "encryptedPassword") == 0) if (strcmp(defel->defname, "encryptedPassword") == 0)
encrypt_password = true; password_type = PASSWORD_TYPE_MD5;
else if (strcmp(defel->defname, "unencryptedPassword") == 0) else if (strcmp(defel->defname, "unencryptedPassword") == 0)
encrypt_password = false; password_type = PASSWORD_TYPE_PLAINTEXT;
} }
else if (strcmp(defel->defname, "sysid") == 0) else if (strcmp(defel->defname, "sysid") == 0)
{ {
@ -393,7 +393,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
if (password) if (password)
{ {
if (!encrypt_password || isMD5(password)) if (password_type == PASSWORD_TYPE_PLAINTEXT || isMD5(password))
new_record[Anum_pg_authid_rolpassword - 1] = new_record[Anum_pg_authid_rolpassword - 1] =
CStringGetTextDatum(password); CStringGetTextDatum(password);
else else
@ -505,7 +505,7 @@ AlterRole(AlterRoleStmt *stmt)
ListCell *option; ListCell *option;
char *rolename = NULL; char *rolename = NULL;
char *password = NULL; /* user password */ char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */ int password_type = Password_encryption;
char encrypted_password[MD5_PASSWD_LEN + 1]; char encrypted_password[MD5_PASSWD_LEN + 1];
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? */
@ -550,9 +550,9 @@ AlterRole(AlterRoleStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
dpassword = defel; dpassword = defel;
if (strcmp(defel->defname, "encryptedPassword") == 0) if (strcmp(defel->defname, "encryptedPassword") == 0)
encrypt_password = true; password_type = PASSWORD_TYPE_MD5;
else if (strcmp(defel->defname, "unencryptedPassword") == 0) else if (strcmp(defel->defname, "unencryptedPassword") == 0)
encrypt_password = false; password_type = PASSWORD_TYPE_PLAINTEXT;
} }
else if (strcmp(defel->defname, "superuser") == 0) else if (strcmp(defel->defname, "superuser") == 0)
{ {
@ -804,7 +804,7 @@ AlterRole(AlterRoleStmt *stmt)
/* password */ /* password */
if (password) if (password)
{ {
if (!encrypt_password || isMD5(password)) if (password_type == PASSWORD_TYPE_PLAINTEXT || isMD5(password))
new_record[Anum_pg_authid_rolpassword - 1] = new_record[Anum_pg_authid_rolpassword - 1] =
CStringGetTextDatum(password); CStringGetTextDatum(password);
else else

View File

@ -34,6 +34,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "commands/async.h" #include "commands/async.h"
#include "commands/prepare.h" #include "commands/prepare.h"
#include "commands/user.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "commands/variable.h" #include "commands/variable.h"
#include "commands/trigger.h" #include "commands/trigger.h"
@ -393,6 +394,24 @@ static const struct config_enum_entry force_parallel_mode_options[] = {
{NULL, 0, false} {NULL, 0, false}
}; };
/*
* password_encryption used to be a boolean, so accept all the likely
* variants of "on" and "off", too.
*/
static const struct config_enum_entry password_encryption_options[] = {
{"plain", PASSWORD_TYPE_PLAINTEXT, false},
{"md5", PASSWORD_TYPE_MD5, false},
{"off", PASSWORD_TYPE_PLAINTEXT, false},
{"on", PASSWORD_TYPE_MD5, false},
{"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}
};
/* /*
* Options for enum values stored in other modules * Options for enum values stored in other modules
*/ */
@ -423,8 +442,6 @@ bool check_function_bodies = true;
bool default_with_oids = false; bool default_with_oids = false;
bool SQL_inheritance = true; bool SQL_inheritance = true;
bool Password_encryption = true;
int log_min_error_statement = ERROR; int log_min_error_statement = ERROR;
int log_min_messages = WARNING; int log_min_messages = WARNING;
int client_min_messages = NOTICE; int client_min_messages = NOTICE;
@ -1313,17 +1330,6 @@ static struct config_bool ConfigureNamesBool[] =
true, true,
NULL, NULL, NULL NULL, NULL, NULL
}, },
{
{"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY,
gettext_noop("Encrypt passwords."),
gettext_noop("When a password is specified in CREATE USER or "
"ALTER USER without writing either ENCRYPTED or UNENCRYPTED, "
"this parameter determines whether the password is to be encrypted.")
},
&Password_encryption,
true,
NULL, NULL, NULL
},
{ {
{"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT, {"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT,
gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."), gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."),
@ -3810,6 +3816,18 @@ static struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL NULL, NULL, NULL
}, },
{
{"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY,
gettext_noop("Encrypt passwords."),
gettext_noop("When a password is specified in CREATE USER or "
"ALTER USER without writing either ENCRYPTED or UNENCRYPTED, "
"this parameter determines whether the password is to be encrypted.")
},
&Password_encryption,
PASSWORD_TYPE_MD5, password_encryption_options,
NULL, NULL, NULL
},
/* End-of-list marker */ /* End-of-list marker */
{ {
{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL

View File

@ -85,7 +85,7 @@
#ssl_key_file = 'server.key' # (change requires restart) #ssl_key_file = 'server.key' # (change requires restart)
#ssl_ca_file = '' # (change requires restart) #ssl_ca_file = '' # (change requires restart)
#ssl_crl_file = '' # (change requires restart) #ssl_crl_file = '' # (change requires restart)
#password_encryption = on #password_encryption = md5 # md5 or plain
#db_user_namespace = off #db_user_namespace = off
#row_security = on #row_security = on

View File

@ -16,10 +16,19 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
/* Hook to check passwords in CreateRole() and AlterRole() */ /*
#define PASSWORD_TYPE_PLAINTEXT 0 * Types of password, for Password_encryption GUC and the password_type
#define PASSWORD_TYPE_MD5 1 * argument of the check-password hook.
*/
typedef enum PasswordType
{
PASSWORD_TYPE_PLAINTEXT = 0,
PASSWORD_TYPE_MD5
} PasswordType;
extern int Password_encryption; /* GUC */
/* Hook to check passwords in CreateRole() and AlterRole() */
typedef void (*check_password_hook_type) (const char *username, const char *password, int password_type, Datum validuntil_time, bool validuntil_null); typedef void (*check_password_hook_type) (const char *username, const char *password, int password_type, Datum validuntil_time, bool validuntil_null);
extern PGDLLIMPORT check_password_hook_type check_password_hook; extern PGDLLIMPORT check_password_hook_type check_password_hook;