diff --git a/extra/schema_fill.lua b/extra/schema_fill.lua index 698c40bd1cd050bd2eadbeb49cbb58a9fae997fd..4259202028f01a34f9d9588a41699d4d90f0f975 100644 --- a/extra/schema_fill.lua +++ b/extra/schema_fill.lua @@ -1,6 +1,7 @@ -- Super User ID GUEST = 0 ADMIN = 1 +PUBLIC = 2 _schema = box.space[box.schema.SCHEMA_ID] _space = box.space[box.schema.SPACE_ID] _index = box.space[box.schema.INDEX_ID] @@ -58,5 +59,6 @@ _index:insert{_cluster.id, 1, 'uuid', 'tree', 1, 1, 1, 'str'} -- -- Pre-create user and grants -_user:insert{GUEST, ADMIN, 'guest'} -_user:insert{ADMIN, ADMIN, 'admin'} +_user:insert{GUEST, ADMIN, 'guest', 'user'} +_user:insert{ADMIN, ADMIN, 'admin', 'user'} +_user:insert{PUBLIC, ADMIN, 'public', 'role'} diff --git a/src/box/access.cc b/src/box/access.cc index ca79d99417f4732ab9dd75b604e6798bf4fc893d..d4437c94a16c2047925d796fcdc4b535a8851c5f 100644 --- a/src/box/access.cc +++ b/src/box/access.cc @@ -131,7 +131,8 @@ struct user * user_by_name(const char *name, uint32_t len) { uint32_t uid = schema_find_id(SC_USER_ID, 2, name, len); - return user_cache_find(uid); + struct user *user = user_cache_find(uid); + return user && user->type == SC_USER ? user : NULL; } void @@ -151,6 +152,7 @@ user_cache_init() memset(&guest, 0, sizeof(guest)); snprintf(guest.name, sizeof(guest.name), "guest"); guest.owner = ADMIN; + guest.type = SC_USER; user_cache_replace(&guest); /* 0 is the auth token and user id by default. */ assert(guest.auth_token == GUEST && @@ -161,6 +163,7 @@ user_cache_init() memset(&admin, 0, sizeof(admin)); snprintf(admin.name, sizeof(admin.name), "admin"); admin.uid = admin.owner = ADMIN; + admin.type = SC_USER; user_cache_replace(&admin); /* ADMIN is both the auth token and user id for 'admin' user. */ assert(admin.auth_token == ADMIN && diff --git a/src/box/access.h b/src/box/access.h index 179c8de591ba5a87b98d183075a849b9efa1f7e8..a101afaf882092bdded6daf893882ee612459a03 100644 --- a/src/box/access.h +++ b/src/box/access.h @@ -59,6 +59,8 @@ struct user { uint32_t uid; /** Creator of the user */ uint32_t owner; + /** 'user' or 'role' */ + enum schema_object_type type; /** User password - hash2 */ char hash2[SCRAMBLE_SIZE]; /** User name - for error messages and debugging */ diff --git a/src/box/alter.cc b/src/box/alter.cc index 647621d4171607ae10d64791292f14b9b3cf99fe..784e6c8948b5df0f3abdd052b68ba8f6566867b7 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -54,7 +54,8 @@ #define INDEX_PART_COUNT 5 /** _user columns */ -#define AUTH_DATA 3 +#define USER_TYPE 3 +#define AUTH_MECH_LIST 4 /** _priv columns */ #define PRIV_OBJECT_TYPE 2 @@ -1170,6 +1171,8 @@ user_create_from_tuple(struct user *user, struct tuple *tuple) memset(user, 0, sizeof(*user)); user->uid = tuple_field_u32(tuple, ID); user->owner = tuple_field_u32(tuple, UID); + const char *user_type = tuple_field_cstr(tuple, USER_TYPE); + user->type= schema_object_type(user_type); const char *name = tuple_field_cstr(tuple, NAME); uint32_t len = snprintf(user->name, sizeof(user->name), "%s", name); if (len >= sizeof(user->name)) { @@ -1184,8 +1187,13 @@ user_create_from_tuple(struct user *user, struct tuple *tuple) * Check for trivial errors when a plain text * password is saved in this field instead. */ - if (tuple_field_count(tuple) > AUTH_DATA) { - const char *auth_data = tuple_field(tuple, AUTH_DATA); + if (tuple_field_count(tuple) > AUTH_MECH_LIST) { + const char *auth_data = tuple_field(tuple, AUTH_MECH_LIST); + if (user->type == SC_ROLE && strlen(auth_data)) { + tnt_raise(ClientError, ER_CREATE_USER, + "authentication data can not be set for " + "a role"); + } user_fill_auth_data(user, auth_data); } } @@ -1235,7 +1243,7 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event) } else if (new_tuple == NULL) { /* DELETE */ access_check_ddl(old_user->owner); /* Can't drop guest or super user */ - if (uid == GUEST || uid == ADMIN) { + if (uid == GUEST || uid == ADMIN || uid == PUBLIC) { tnt_raise(ClientError, ER_DROP_USER, old_user->name, "the user is a system user"); diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index 01826679a3620c1593c8ccb4aee510b82da0835d..2f2f16c8511d20055c95cb475077546cfb78fd45 100644 Binary files a/src/box/bootstrap.snap and b/src/box/bootstrap.snap differ diff --git a/src/box/key_def.cc b/src/box/key_def.cc index e0f68b910133d7991afdca7e29e38a71e1cdf5a2..66f4fd4f3c9c7904625b7671edae0a91adfe27f8 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -51,9 +51,10 @@ schema_object_type(const char *name) * here too. */ static const char *strs[] = { - "unknown", "universe", "space", "function" }; - int index = strindex(strs, name, 4); - return (enum schema_object_type) (index == 4 ? 0 : index); + "unknown", "universe", "space", "function", "user", "role" }; + int n_strs = sizeof(strs)/sizeof(*strs); + int index = strindex(strs, name, n_strs); + return (enum schema_object_type) (index == n_strs ? 0 : index); } struct key_def * diff --git a/src/box/key_def.h b/src/box/key_def.h index 30826ce21aeabef39d0d707e8f895200695f352f..bdbd9d87a4a4b0051cbbfafdb574c9d30bc1e7cc 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -62,7 +62,8 @@ enum { * even when there are more object types in the future. */ enum schema_object_type { - SC_UNKNOWN = 0, SC_UNIVERSE = 1, SC_SPACE = 2, SC_FUNCTION = 3 + SC_UNKNOWN = 0, SC_UNIVERSE = 1, SC_SPACE = 2, SC_FUNCTION = 3, + SC_USER = 4, SC_ROLE = 5 }; enum schema_object_type diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 77f964344de2d5098ca85881fc2683a0e0e6e28c..a4a62510d170242e4c0f57d6193ab3e5fff0e978 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -650,6 +650,22 @@ local function object_resolve(object_type, object_name) "Function '"..object_name.."' does not exist") end end + if object_type == 'role' then + local _user = box.space[box.schema.USER_ID] + local role + if type(object_name) == 'string' then + role = _user.index['name']:get{object_name} + else + role = _user.index['primary']:get{object_name} + end + if role then + return role[1] + else + box.raise(box.error.NO_SUCH_USER, + "Role '"..object_name.."' does not exist") + end + end + box.raise(box.error.UNKNOWN_SCHEMA_OBJECT, "Unknown object type '"..object_type.."'") end @@ -692,7 +708,7 @@ box.schema.user.passwd = function(new_password) local _user = box.space[box.schema.USER_ID] auth_mech_list = {} auth_mech_list["chap-sha1"] = box.schema.user.password(new_password) - _user:update({uid}, {"=", 3, auth_mech_list}) + _user:update({uid}, {"=", 4, auth_mech_list}) end box.schema.user.create = function(name, opts) @@ -709,7 +725,7 @@ box.schema.user.create = function(name, opts) auth_mech_list["chap-sha1"] = box.schema.user.password(opts.password) end local _user = box.space[box.schema.USER_ID] - _user:auto_increment{session.uid(), name, auth_mech_list} + _user:auto_increment{session.uid(), name, 'user', auth_mech_list} end box.schema.user.drop = function(name) @@ -775,3 +791,19 @@ box.schema.user.revoke = function(user_name, privilege, object_type, object_name end end +box.schema.role = {} + +box.schema.role.create = function(name) + local uid = user_resolve(name) + if uid then + box.raise(box.error.USER_EXISTS, + "Role '"..name.."' already exists") + end + local _user = box.space[box.schema.USER_ID] + _user:auto_increment{session.uid(), name, 'role'} +end + +box.schema.role.drop = function(name) + return box.schema.user.drop(name) +end + diff --git a/src/session.h b/src/session.h index b2efcbe95998efa7effc0ac04a2fa8d4375ca398..ab0e620ba1311d7bace4338913799f57479056b4 100644 --- a/src/session.h +++ b/src/session.h @@ -34,7 +34,7 @@ enum { SESSION_SEED_SIZE = 32, SESSION_DELIM_SIZE = 16 }; /** Predefined user ids. */ -enum { GUEST = 0, ADMIN = 1 }; +enum { GUEST = 0, ADMIN = 1, PUBLIC = 2 /* role */ }; /** * Abstraction of a single user session: diff --git a/test/box/access.result b/test/box/access.result index adc661c7b16e79d212433fcc7953b7ceaef1d927..dc7d676afed5ba6e7def0f015e0c770aa59c2335 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -119,7 +119,7 @@ box.schema.user.revoke('rich', 'read,write', 'universe') ... box.space['_user']:delete{uid} --- -- [3, 1, 'rich', []] +- [3, 1, 'rich', 'user', []] ... box.schema.user.drop('test') --- diff --git a/test/box/auth_access.result b/test/box/auth_access.result index dfef0f528db76ecd2a9d4191f6515ffd0f04fedf..83c9802e3d40303cd3eadf8b99d5df66bb42e9b6 100644 --- a/test/box/auth_access.result +++ b/test/box/auth_access.result @@ -247,7 +247,7 @@ box.space.admin_space:select() ... box.space._user:select(1) --- -- - [1, 1, 'admin'] +- - [1, 1, 'admin', 'user'] ... box.space._space:select(280) --- @@ -332,20 +332,20 @@ box.space._user:select(1) --- - error: Read access denied for user 'testuser' to space '_user' ... -box.space._user:insert{3, session.uid(), 'someone'} +box.space._user:insert{3, session.uid(), 'someone', 'user'} --- -- [3, 2, 'someone'] +- [3, 2, 'someone', 'user'] ... box.space._user:delete(3) --- -- [3, 2, 'someone'] +- [3, 2, 'someone', 'user'] ... session.su('admin') --- ... box.space._user:select(1) --- -- - [1, 1, 'admin'] +- - [1, 1, 'admin', 'user'] ... box.space._user:delete(3) --- @@ -368,9 +368,9 @@ box.space._user:delete(2) ... box.space._user:select(1) --- -- - [1, 1, 'admin'] +- - [1, 1, 'admin', 'user'] ... -box.space._user:insert{4,'','someone2'} +box.space._user:insert{4,session.uid(),'someone2', 'user'} --- - error: Write access denied for user 'testuser' to space '_user' ... @@ -555,9 +555,9 @@ s:drop() ... box.space._user:select() --- -- - [0, 1, 'guest'] - - [1, 1, 'admin'] - - [2, 1, 'testuser', []] +- - [0, 1, 'guest', 'user'] + - [1, 1, 'admin', 'user'] + - [2, 1, 'testuser', 'user', []] ... box.space._space:select() --- diff --git a/test/box/auth_access.test.lua b/test/box/auth_access.test.lua index 55b12055e7c212bd6189ddee9ee13f909bb4cc7e..b0e397e95fe008c7cdfd8e36facd13b8f57c856f 100644 --- a/test/box/auth_access.test.lua +++ b/test/box/auth_access.test.lua @@ -139,7 +139,7 @@ box.schema.user.grant('testuser', 'write', 'space', '_user') session.su('testuser') box.space._user:delete(2) box.space._user:select(1) -box.space._user:insert{3, session.uid(), 'someone'} +box.space._user:insert{3, session.uid(), 'someone', 'user'} box.space._user:delete(3) session.su('admin') @@ -153,7 +153,7 @@ box.schema.user.grant('testuser', 'read', 'space', '_user') session.su('testuser') box.space._user:delete(2) box.space._user:select(1) -box.space._user:insert{4,'','someone2'} +box.space._user:insert{4,session.uid(),'someone2', 'user'} session.su('admin') --