Skip to content

Commit 72cc686

Browse files
author
Kristofer Pettersson
committed
Bug#24670738 SHOW CREATE USER DOESN'T SHOW DEFAULT ROLE
This patch introduce a new syntax for CREATE USER for setting the preferred default roles. SHOW CREATE USER is changed to include default roles in the result set.
1 parent 50b32fd commit 72cc686

File tree

9 files changed

+224
-3
lines changed

9 files changed

+224
-3
lines changed

mysql-test/r/roles.result

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,3 +1177,51 @@ baseuser@%
11771177
DROP USER baseuser, admin1, admin2, r1, r2;
11781178
SET @@global.check_proxy_users = OFF;
11791179
SET @@global.mysql_native_password_proxy_users = OFF;
1180+
#
1181+
# SHOW CREATE USER DOESN'T SHOW DEFAULT ROLE
1182+
#
1183+
CREATE USER u1 IDENTIFIED BY 'foo' DEFAULT ROLE a,a@localhost,`b`,`b`@local,`c c`,`aaa`, `a`@`a`;
1184+
SHOW CREATE USER u1;
1185+
CREATE USER for u1@%
1186+
CREATE USER 'u1'@'%' IDENTIFIED WITH 'mysql_native_password' AS '<hash>' DEFAULT ROLE `a`@`%`,`a`@`a`,`a`@`localhost`,`aaa`@`%`,`b`@`%`,`b`@`local`,`c c`@`%` REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1187+
CREATE USER u1;
1188+
ERROR HY000: Operation CREATE USER failed for 'u1'@'%'
1189+
# Same as before and don't crash.
1190+
SHOW CREATE USER u1;
1191+
CREATE USER for u1@%
1192+
CREATE USER 'u1'@'%' IDENTIFIED WITH 'mysql_native_password' AS '<hash>' DEFAULT ROLE `a`@`%`,`a`@`a`,`a`@`localhost`,`aaa`@`%`,`b`@`%`,`b`@`local`,`c c`@`%` REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1193+
# check that we can combine different properties with default roles.
1194+
CREATE USER u2 DEFAULT ROLE r1 REQUIRE SSL ACCOUNT LOCK;
1195+
SHOW CREATE USER u2;
1196+
CREATE USER for u2@%
1197+
CREATE USER 'u2'@'%' IDENTIFIED WITH 'mysql_native_password' DEFAULT ROLE `r1`@`%` REQUIRE SSL PASSWORD EXPIRE DEFAULT ACCOUNT LOCK
1198+
SELECT user,host FROM mysql.user;
1199+
user host
1200+
u1 %
1201+
u2 %
1202+
mysql.session localhost
1203+
mysql.sys localhost
1204+
root localhost
1205+
SELECT * FROM mysql.default_roles;
1206+
HOST USER DEFAULT_ROLE_HOST DEFAULT_ROLE_USER
1207+
% u1 % a
1208+
% u1 % aaa
1209+
% u1 % b
1210+
% u1 % c c
1211+
% u1 a a
1212+
% u1 local b
1213+
% u1 localhost a
1214+
% u2 % r1
1215+
DROP USER u1,u2;
1216+
CREATE USER u1;
1217+
# If I alter user this will show up in show create user
1218+
ALTER USER u1 DEFAULT ROLE r1;
1219+
SHOW CREATE USER u1;
1220+
CREATE USER for u1@%
1221+
CREATE USER 'u1'@'%' IDENTIFIED WITH 'mysql_native_password' DEFAULT ROLE `r1`@`%` REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1222+
SELECT * FROM mysql.default_roles;
1223+
HOST USER DEFAULT_ROLE_HOST DEFAULT_ROLE_USER
1224+
% u1 % r1
1225+
DROP USER u1;
1226+
SELECT * FROM mysql.default_roles;
1227+
HOST USER DEFAULT_ROLE_HOST DEFAULT_ROLE_USER

mysql-test/t/roles.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,3 +932,30 @@ CONNECTION default;
932932
DROP USER baseuser, admin1, admin2, r1, r2;
933933
SET @@global.check_proxy_users = OFF;
934934
SET @@global.mysql_native_password_proxy_users = OFF;
935+
936+
--echo #
937+
--echo # SHOW CREATE USER DOESN'T SHOW DEFAULT ROLE
938+
--echo #
939+
CREATE USER u1 IDENTIFIED BY 'foo' DEFAULT ROLE a,a@localhost,`b`,`b`@local,`c c`,`aaa`, `a`@`a`;
940+
--replace_regex /AS '(.*)'/AS '<hash>'/
941+
SHOW CREATE USER u1;
942+
--error ER_CANNOT_USER
943+
CREATE USER u1;
944+
--echo # Same as before and don't crash.
945+
--replace_regex /AS '(.*)'/AS '<hash>'/
946+
SHOW CREATE USER u1;
947+
--echo # check that we can combine different properties with default roles.
948+
CREATE USER u2 DEFAULT ROLE r1 REQUIRE SSL ACCOUNT LOCK;
949+
SHOW CREATE USER u2;
950+
SELECT user,host FROM mysql.user;
951+
SELECT * FROM mysql.default_roles;
952+
DROP USER u1,u2;
953+
CREATE USER u1;
954+
--echo # If I alter user this will show up in show create user
955+
ALTER USER u1 DEFAULT ROLE r1;
956+
SHOW CREATE USER u1;
957+
SELECT * FROM mysql.default_roles;
958+
DROP USER u1;
959+
SELECT * FROM mysql.default_roles;
960+
961+

sql/auth/auth_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,6 @@ void create_role_vertex(ACL_USER *role_acl_user);
362362
void activate_all_granted_and_mandatory_roles(const ACL_USER *acl_user,
363363
Security_context *sctx);
364364
extern std::vector<std::string> builtin_auth_plugins;
365+
bool alter_user_set_default_roles(THD *thd, TABLE *table, LEX_USER *user,
366+
const List_of_auth_id_refs &new_auth_ids);
365367
#endif /* AUTH_INTERNAL_INCLUDED */

sql/auth/sql_authorization.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6587,6 +6587,19 @@ bool mysql_alter_user_set_default_roles_all(THD *thd, LEX_USER *user)
65876587
return errors;
65886588
}
65896589

6590+
6591+
/**
6592+
Set the default roles for a particular user.
6593+
6594+
@param thd Thread handle
6595+
@param table Table handle to an open table
6596+
@param user AST component for the user for which we set def roles
6597+
@param new_auth_ids Default roles to set
6598+
@return
6599+
@retval true Operation failed
6600+
@retval false Operation was successful.
6601+
*/
6602+
65906603
bool alter_user_set_default_roles(THD *thd, TABLE *table, LEX_USER *user,
65916604
const List_of_auth_id_refs &new_auth_ids)
65926605
{

sql/auth/sql_user.cc

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ bool mysql_show_create_user(THD *thd, LEX_USER *user_name)
302302
List<Item> field_list;
303303
String sql_text(buff,sizeof(buff),system_charset_info);
304304
LEX_ALTER alter_info;
305+
List_of_auth_id_refs default_roles;
306+
List<LEX_USER> *old_default_roles= lex->default_roles;
305307

306308
DBUG_ENTER("mysql_show_create_user");
307309
Acl_cache_lock_guard acl_cache_lock(thd, Acl_cache_lock_mode::READ_MODE);
@@ -384,6 +386,44 @@ bool mysql_show_create_user(THD *thd, LEX_USER *user_name)
384386
goto err;
385387
}
386388
sql_text.length(0);
389+
if (lex->sql_command == SQLCOM_SHOW_CREATE_USER ||
390+
lex->sql_command == SQLCOM_CREATE_USER)
391+
{
392+
/*
393+
Recreate LEX for default roles given an ACL_USER. This will later be used
394+
by rewrite_default_roles() called from mysql_rewrite_create_alter_user()
395+
below.
396+
*/
397+
get_default_roles(create_authid_from(acl_user), &default_roles);
398+
if (default_roles.size() > 0)
399+
{
400+
LEX_STRING *tmp_user;
401+
LEX_STRING *tmp_host;
402+
/*
403+
Make sure we reallocate the default_roles list when using it outside of
404+
parser code so it has the same mem root as its items.
405+
*/
406+
lex->default_roles= new (thd->mem_root) List<LEX_USER>;
407+
for (auto &&role : default_roles)
408+
{
409+
if (!(tmp_user= thd->make_lex_string(tmp_user, role.first.str,
410+
role.first.length, true)) ||
411+
!(tmp_host= thd->make_lex_string(tmp_host, role.second.str,
412+
role.second.length, true)))
413+
{
414+
error= 1;
415+
goto err;
416+
}
417+
LEX_USER *lex_role= LEX_USER::alloc(thd, tmp_user, tmp_host);
418+
if (lex_role == 0)
419+
{
420+
error= 1;
421+
goto err;
422+
}
423+
lex->default_roles->push_back(lex_role);
424+
}
425+
}
426+
}
387427
lex->users_list.push_back(user_name);
388428
mysql_rewrite_create_alter_user(thd, &sql_text);
389429
/* send the result row to client */
@@ -396,6 +436,7 @@ bool mysql_show_create_user(THD *thd, LEX_USER *user_name)
396436
}
397437

398438
err:
439+
lex->default_roles= old_default_roles;
399440
/* restore user resources, ssl and password expire attributes */
400441
lex->mqh= tmp_user_resource;
401442
lex->ssl_type= ssl_type;
@@ -2045,6 +2086,27 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool if_not_exists, bool
20452086

20462087
continue;
20472088
}
2089+
2090+
/*
2091+
Update default roles if any were specified. The roles don't have to
2092+
exist and won't be granted to the user.
2093+
*/
2094+
if (thd->lex->default_roles != 0 &&
2095+
thd->lex->sql_command == SQLCOM_CREATE_USER)
2096+
{
2097+
List_of_auth_id_refs default_roles;
2098+
List_iterator<LEX_USER> role_it(*(thd->lex->default_roles));
2099+
LEX_USER *role;
2100+
while ((role= role_it++))
2101+
{
2102+
default_roles.push_back(create_authid_from(role));
2103+
}
2104+
alter_user_set_default_roles(thd,
2105+
tables[ACL_TABLES::TABLE_DEFAULT_ROLES].table,
2106+
tmp_user_name,
2107+
default_roles);
2108+
}
2109+
20482110
} // END while tmp_user_name= user_lists++
20492111
/* In case of SE error, we would have raised error before reaching here. */
20502112
if (result && !thd->is_error())

sql/sql_lex.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3498,6 +3498,7 @@ void LEX::clear_privileges()
34983498
alter_password.cleanup();
34993499
memset(&mqh, 0, sizeof(mqh));
35003500
dynamic_privileges.empty();
3501+
default_roles= 0;
35013502
}
35023503

35033504

sql/sql_lex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3526,6 +3526,7 @@ struct LEX: public Query_tables_list
35263526
List<LEX_USER> users_list;
35273527
List<LEX_COLUMN> columns;
35283528
List<LEX_CSTRING> dynamic_privileges;
3529+
List<LEX_USER> *default_roles;
35293530

35303531
ulonglong bulk_insert_row_cnt;
35313532

sql/sql_rewrite.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
#include "sql/table.h"
9595
#include "sql_string.h" // String
9696
#include "violite.h"
97+
#include "auth_internal.h"
9798

9899
#ifndef DBUG_OFF
99100
#define HASH_STRING_WITH_QUOTE \
@@ -174,6 +175,56 @@ static bool append_str(String *str, bool comma, const char *key,
174175
return comma;
175176
}
176177

178+
/**
179+
Used with List<>::sort for alphabetic sorting of LEX_USER records
180+
using user,host as keys.
181+
182+
@param n1 A LEX_USER element
183+
@param n2 A LEX_USER element
184+
@param arg Not used
185+
186+
@return
187+
@retval 1 if n1 &gt; n2
188+
@retval 0 if n1 &lt;= n2
189+
*/
190+
static int lex_user_comp(void *n1, void *n2, void *arg MY_ATTRIBUTE((unused)))
191+
{
192+
LEX_USER *l1= (LEX_USER *)n1;
193+
LEX_USER *l2= (LEX_USER *)n2;
194+
size_t length= std::min(l1->user.length,l2->user.length);
195+
int key= memcmp(l1->user.str, l2->user.str, length);
196+
if (key == 0 && l1->user.length == l2->user.length)
197+
{
198+
length= std::min(l1->host.length,l2->host.length);
199+
key= memcmp(l1->host.str, l2->host.str, length);
200+
if (key == 0 && l1->host.length == l2->host.length)
201+
return 0;
202+
}
203+
if (key == 0)
204+
return (l1->user.length > l2->user.length ? 1 : 0);
205+
else
206+
return (key > 0 ? 1 : 0);
207+
}
208+
209+
static void rewrite_default_roles(LEX *lex, String *rlb)
210+
{
211+
bool comma= false;
212+
if (lex->default_roles && lex->default_roles->elements > 0)
213+
{
214+
rlb->append(" DEFAULT ROLE ");
215+
lex->default_roles->sort(&lex_user_comp, 0);
216+
List_iterator<LEX_USER> role_it(*(lex->default_roles));
217+
LEX_USER *role;
218+
while ((role= role_it++))
219+
{
220+
if (comma)
221+
rlb->append(',');
222+
rlb->append(create_authid_str_from(role).c_str());
223+
comma= true;
224+
}
225+
}
226+
}
227+
177228
static void rewrite_ssl_properties(LEX *lex, String *rlb)
178229
{
179230
if (lex->ssl_type != SSL_TYPE_NOT_SPECIFIED)
@@ -546,6 +597,8 @@ void mysql_rewrite_create_alter_user(THD *thd, String *rlb,
546597
}
547598
}
548599

600+
if (thd->lex->sql_command == SQLCOM_SHOW_CREATE_USER)
601+
rewrite_default_roles(lex, rlb);
549602
rewrite_ssl_properties(lex, rlb);
550603
rewrite_user_resources(lex, rlb);
551604

sql/sql_yacc.yy

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, YYLTYPE **c, ulong *yystacksize);
15901590

15911591
%type <join_type> outer_join_type natural_join_type inner_join_type
15921592

1593-
%type <user_list> user_list role_list opt_except_role_list
1593+
%type <user_list> user_list role_list default_role_clause opt_except_role_list
15941594

15951595
%type <alter_instance_action> alter_instance_action
15961596

@@ -2553,11 +2553,13 @@ create:
25532553
}
25542554
view_or_trigger_or_sp_or_event
25552555
{}
2556-
| CREATE USER opt_if_not_exists grant_list require_clause
2557-
connect_options opt_account_lock_password_expire_options
2556+
| CREATE USER opt_if_not_exists grant_list default_role_clause
2557+
require_clause connect_options
2558+
opt_account_lock_password_expire_options
25582559
{
25592560
LEX *lex=Lex;
25602561
lex->sql_command = SQLCOM_CREATE_USER;
2562+
lex->default_roles= $5;
25612563
Lex->create_info= YYTHD->alloc_typed<HA_CREATE_INFO>();
25622564
if (Lex->create_info == NULL)
25632565
MYSQL_YYABORT; // OOM
@@ -2592,6 +2594,18 @@ create:
25922594
}
25932595
;
25942596

2597+
default_role_clause:
2598+
/* empty */
2599+
{
2600+
$$= 0;
2601+
}
2602+
|
2603+
DEFAULT_SYM ROLE_SYM role_list
2604+
{
2605+
$$= $3;
2606+
}
2607+
;
2608+
25952609
create_index_stmt:
25962610
CREATE opt_unique INDEX_SYM opt_index_name_and_type
25972611
ON_SYM table_ident '(' key_list ')' opt_index_options

0 commit comments

Comments
 (0)