From 29aa58464b8f3f9c50bd0ae952ea084a4c947812 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 25 Jul 2016 16:00:32 +0900 Subject: [PATCH 7/8] Add clause PASSWORD val USING protocol to CREATE/ALTER ROLE This clause allows users to be able to enforce with which protocol a given password is used with. if the value given is already encrypted, the value is used as-is. --- doc/src/sgml/ref/alter_role.sgml | 2 ++ doc/src/sgml/ref/create_role.sgml | 19 +++++++++++ src/backend/commands/user.c | 72 ++++++++++++++++++++++++++++++++++++--- src/backend/parser/gram.y | 6 ++++ 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index da36ad9..3cae101 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -34,6 +34,7 @@ ALTER ROLE role_specification [ WIT | BYPASSRLS | NOBYPASSRLS | CONNECTION LIMIT connlimit | [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password' + | PASSWORD 'password' USING 'protocol' | VALID UNTIL 'timestamp' ALTER ROLE name RENAME TO new_name @@ -169,6 +170,7 @@ ALTER ROLE { role_specification | A NOBYPASSRLS CONNECTION LIMIT connlimit PASSWORD password + PASSWORD password USING protocol ENCRYPTED UNENCRYPTED VALID UNTIL 'timestamp' diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml index 93f0763..b25d2c0 100644 --- a/doc/src/sgml/ref/create_role.sgml +++ b/doc/src/sgml/ref/create_role.sgml @@ -34,6 +34,7 @@ CREATE ROLE name [ [ WITH ] connlimit | [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password' + | PASSWORD 'password' USING 'protocol' | VALID UNTIL 'timestamp' | IN ROLE role_name [, ...] | IN GROUP role_name [, ...] @@ -245,6 +246,24 @@ CREATE ROLE name [ [ WITH ] + PASSWORD password USING protocol + + + Sets the role's password using the wanted protocol. (A password + is only of use for roles having the LOGIN + attribute, but you can nonetheless define one for roles without it.) + If you do not plan to use password authentication you can omit this + option. The protocols supported are md5 to enforce + a password to be MD5-encrypted, scram to enforce a password + to be encrypted with SCRAM-SHA256, or plain to use + an unencrypted password. If the presented password string is already + in MD5-encrypted or SCRAM-encrypted format, then it is stored encrypted + as-is. + + + + + VALID UNTIL 'timestamp' diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index a079c32..0f71f36 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -178,7 +178,8 @@ CreateRole(CreateRoleStmt *stmt) if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 || - strcmp(defel->defname, "unencryptedPassword") == 0) + strcmp(defel->defname, "unencryptedPassword") == 0 || + strcmp(defel->defname, "protocolPassword") == 0) { if (dpassword) ereport(ERROR, @@ -186,9 +187,41 @@ CreateRole(CreateRoleStmt *stmt) errmsg("conflicting or redundant options"))); dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) + { password_type = PASSWORD_TYPE_MD5; + if (dpassword && dpassword->arg) + password = strVal(dpassword->arg); + } else if (strcmp(defel->defname, "unencryptedPassword") == 0) + { password_type = PASSWORD_TYPE_PLAINTEXT; + if (dpassword && dpassword->arg) + password = strVal(dpassword->arg); + } + else if (strcmp(defel->defname, "protocolPassword") == 0) + { + /* + * This is a list of two elements, the password is first and + * then there is the protocol wanted by caller. + */ + if (dpassword && dpassword->arg) + { + char *protocol = strVal(lsecond((List *) dpassword->arg)); + + password = strVal(linitial((List *) dpassword->arg)); + + if (strcmp(protocol, "md5") == 0) + password_type = PASSWORD_TYPE_MD5; + else if (strcmp(protocol, "plain") == 0) + password_type = PASSWORD_TYPE_PLAINTEXT; + else if (strcmp(protocol, "scram") == 0) + password_type = PASSWORD_TYPE_SCRAM; + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unsupported password protocol %s", protocol))); + } + } } else if (strcmp(defel->defname, "sysid") == 0) { @@ -296,8 +329,6 @@ CreateRole(CreateRoleStmt *stmt) defel->defname); } - if (dpassword && dpassword->arg) - password = strVal(dpassword->arg); if (dissuper) issuper = intVal(dissuper->arg) != 0; if (dinherit) @@ -571,6 +602,7 @@ AlterRole(AlterRoleStmt *stmt) if (strcmp(defel->defname, "password") == 0 || strcmp(defel->defname, "encryptedPassword") == 0 || + strcmp(defel->defname, "protocolPassword") == 0 || strcmp(defel->defname, "unencryptedPassword") == 0) { if (dpassword) @@ -579,9 +611,41 @@ AlterRole(AlterRoleStmt *stmt) errmsg("conflicting or redundant options"))); dpassword = defel; if (strcmp(defel->defname, "encryptedPassword") == 0) + { password_type = PASSWORD_TYPE_MD5; + if (dpassword && dpassword->arg) + password = strVal(dpassword->arg); + } else if (strcmp(defel->defname, "unencryptedPassword") == 0) + { password_type = PASSWORD_TYPE_PLAINTEXT; + if (dpassword && dpassword->arg) + password = strVal(dpassword->arg); + } + else if (strcmp(defel->defname, "protocolPassword") == 0) + { + /* + * This is a list of two elements, the password is first and + * then there is the protocol wanted by caller. + */ + if (dpassword && dpassword->arg) + { + char *protocol = strVal(lsecond((List *) dpassword->arg)); + + if (strcmp(protocol, "md5") == 0) + password_type = PASSWORD_TYPE_MD5; + else if (strcmp(protocol, "plain") == 0) + password_type = PASSWORD_TYPE_PLAINTEXT; + else if (strcmp(protocol, "scram") == 0) + password_type = PASSWORD_TYPE_SCRAM; + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unsupported password protocol %s", protocol))); + + password = strVal(linitial((List *) dpassword->arg)); + } + } } else if (strcmp(defel->defname, "superuser") == 0) { @@ -669,8 +733,6 @@ AlterRole(AlterRoleStmt *stmt) defel->defname); } - if (dpassword && dpassword->arg) - password = strVal(dpassword->arg); if (dissuper) issuper = intVal(dissuper->arg); if (dinherit) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c89ebe3..bdfe383 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -934,6 +934,12 @@ AlterOptRoleElem: { $$ = makeDefElem("password", NULL); } + | PASSWORD Sconst USING Sconst + { + $$ = makeDefElem("protocolPassword", + (Node *)list_make2(makeString($2), + makeString($4))); + } | ENCRYPTED PASSWORD Sconst { $$ = makeDefElem("encryptedPassword", -- 2.9.3