From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 2EB9C25C67 for ; Mon, 4 Jun 2018 12:02:28 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3x5W6VSMkXX1 for ; Mon, 4 Jun 2018 12:02:28 -0400 (EDT) Received: from smtp46.i.mail.ru (smtp46.i.mail.ru [94.100.177.106]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 41C8425C3C for ; Mon, 4 Jun 2018 12:02:27 -0400 (EDT) From: Georgy Kirichenko Subject: [tarantool-patches] [PATCH] security: Use system views instead of system spaces Date: Mon, 4 Jun 2018 19:02:21 +0300 Message-Id: <5aec875966ff843a32b03cf9d0e7c85e4fec7f20.1528128037.git.georgy@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Ilya Markov From: Ilya Markov System views are used instead of direct reads of corresponding system spaces to explore all accessible objects such as spaces, functions, users and e.g. An operation with an inaccessible object produces a 'not found' error even if the object exists. In scope of #3250 Includes up fixes from Georgy --- Branch: https://github.com/tarantool/tarantool/tree/gh-3250-use-system-views src/box/lua/schema.lua | 97 ++++++++++++--------- src/box/sysview_index.c | 83 +++++++++++++----- test/box/access.result | 145 ++++++++++++++++++++++++++----- test/box/access.test.lua | 67 +++++++++----- test/box/access_bin.result | 2 +- test/box/access_bin.test.lua | 2 +- test/box/access_misc.result | 14 +++ test/box/access_misc.test.lua | 9 +- test/box/access_sysview.result | 11 +-- test/box/access_sysview.test.lua | 6 +- test/box/ddl.result | 4 + test/box/ddl.test.lua | 2 + test/box/on_replace.result | 8 +- test/box/role.result | 2 +- test/box/transaction.result | 18 +++- test/box/transaction.test.lua | 4 + test/engine/iterator.result | 2 +- test/engine/savepoint.result | 12 +-- 18 files changed, 353 insertions(+), 135 deletions(-) diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 0b7849fa9..d6d39170f 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -104,12 +104,12 @@ ffi.cdef[[ ]] local function user_or_role_resolve(user) - local _user = box.space[box.schema.VUSER_ID] + local _vuser = box.space[box.schema.VUSER_ID] local tuple if type(user) == 'string' then - tuple = _user.index.name:get{user} + tuple = _vuser.index.name:get{user} else - tuple = _user:get{user} + tuple = _vuser:get{user} end if tuple == nil then return nil @@ -118,12 +118,12 @@ local function user_or_role_resolve(user) end local function role_resolve(name_or_id) - local _user = box.space[box.schema.USER_ID] + local _vuser = box.space[box.schema.VUSER_ID] local tuple if type(name_or_id) == 'string' then - tuple = _user.index.name:get{name_or_id} + tuple = _vuser.index.name:get{name_or_id} elseif type(name_or_id) ~= 'nil' then - tuple = _user:get{name_or_id} + tuple = _vuser:get{name_or_id} end if tuple == nil or tuple[4] ~= 'role' then return nil @@ -133,12 +133,12 @@ local function role_resolve(name_or_id) end local function user_resolve(name_or_id) - local _user = box.space[box.schema.USER_ID] + local _vuser = box.space[box.schema.VUSER_ID] local tuple if type(name_or_id) == 'string' then - tuple = _user.index.name:get{name_or_id} + tuple = _vuser.index.name:get{name_or_id} elseif type(name_or_id) ~= 'nil' then - tuple = _user:get{name_or_id} + tuple = _vuser:get{name_or_id} end if tuple == nil or tuple[4] ~= 'user' then return nil @@ -148,12 +148,12 @@ local function user_resolve(name_or_id) end local function sequence_resolve(name_or_id) - local _sequence = box.space[box.schema.SEQUENCE_ID] + local _vsequence = box.space[box.schema.VSEQUENCE_ID] local tuple if type(name_or_id) == 'string' then - tuple = _sequence.index.name:get{name_or_id} + tuple = _vsequence.index.name:get{name_or_id} elseif type(name_or_id) ~= 'nil' then - tuple = _sequence:get{name_or_id} + tuple = _vsequence:get{name_or_id} end if tuple ~= nil then return tuple[1], tuple @@ -164,8 +164,9 @@ end -- Revoke all privileges associated with the given object. local function revoke_object_privs(object_type, object_id) + local _vpriv = box.space[box.schema.VPRIV_ID] local _priv = box.space[box.schema.PRIV_ID] - local privs = _priv.index.object:select{object_type, object_id} + local privs = _vpriv.index.object:select{object_type, object_id} for k, tuple in pairs(privs) do local uid = tuple[2] _priv:delete{uid, object_type, object_id} @@ -431,10 +432,15 @@ end -- space format - the metadata about space fields function box.schema.space.format(id, format) local _space = box.space._space + local _vspace = box.space._vspace check_param(id, 'id', 'number') if format == nil then - return _space:get(id)[7] + local tuple = _vspace:get(id) + if tuple == nil then + box.error(box.error.NO_SUCH_SPACE, '#' .. tostring(id)) + end + return tuple[7] else check_param(format, 'format', 'table') format = update_format(format) @@ -450,6 +456,7 @@ box.schema.space.drop = function(space_id, space_name, opts) check_param_table(opts, { if_exists = 'boolean' }) local _space = box.space[box.schema.SPACE_ID] local _index = box.space[box.schema.INDEX_ID] + local _vindex = box.space[box.schema.VINDEX_ID] local _truncate = box.space[box.schema.TRUNCATE_ID] local _space_sequence = box.space[box.schema.SPACE_SEQUENCE_ID] local sequence_tuple = _space_sequence:delete{space_id} @@ -457,7 +464,7 @@ box.schema.space.drop = function(space_id, space_name, opts) -- Delete automatically generated sequence. box.schema.sequence.drop(sequence_tuple[2]) end - local keys = _index:select(space_id) + local keys = _vindex:select(space_id) for i = #keys, 1, -1 do local v = keys[i] _index:delete{v[1], v[2]} @@ -695,7 +702,8 @@ box.schema.index.create = function(space_id, name, options) options = update_param_table(options, options_defaults) local _index = box.space[box.schema.INDEX_ID] - if _index.index.name:get{space_id, name} then + local _vindex = box.space[box.schema.VINDEX_ID] + if _vindex.index.name:get{space_id, name} then if options.if_not_exists then return space.index[name], "not created" else @@ -708,7 +716,7 @@ box.schema.index.create = function(space_id, name, options) iid = options.id else -- max - local tuple = _index.index[0] + local tuple = _vindex.index[0] :select(space_id, { limit = 1, iterator = 'LE' })[1] if tuple then local id = tuple[1] @@ -1745,12 +1753,12 @@ local function object_resolve(object_type, object_name) return space.id end if object_type == 'function' then - local _func = box.space[box.schema.FUNC_ID] + local _vfunc = box.space[box.schema.VFUNC_ID] local func if type(object_name) == 'string' then - func = _func.index.name:get{object_name} + func = _vfunc.index.name:get{object_name} else - func = _func:get{object_name} + func = _vfunc:get{object_name} end if func then return func[1] @@ -1766,12 +1774,12 @@ local function object_resolve(object_type, object_name) return seq end if object_type == 'role' then - local _user = box.space[box.schema.USER_ID] + local _vuser = box.space[box.schema.VUSER_ID] local role if type(object_name) == 'string' then - role = _user.index.name:get{object_name} + role = _vuser.index.name:get{object_name} else - role = _user:get{object_name} + role = _vuser:get{object_name} end if role and role[4] == 'role' then return role[1] @@ -1789,13 +1797,13 @@ local function object_name(object_type, object_id) end local space if object_type == 'space' then - space = box.space._space + space = box.space._vspace elseif object_type == 'sequence' then space = box.space._sequence elseif object_type == 'function' then - space = box.space._func + space = box.space._vfunc elseif object_type == 'role' or object_type == 'user' then - space = box.space._user + space = box.space._vuser else box.error(box.error.UNKNOWN_SCHEMA_OBJECT, object_type) end @@ -1809,7 +1817,8 @@ box.schema.func.create = function(name, opts) if_not_exists = 'boolean', language = 'string'}) local _func = box.space[box.schema.FUNC_ID] - local func = _func.index.name:get{name} + local _vfunc = box.space[box.schema.VFUNC_ID] + local func = _vfunc.index.name:get{name} if func then if not opts.if_not_exists then box.error(box.error.FUNCTION_EXISTS, name) @@ -1826,12 +1835,13 @@ box.schema.func.drop = function(name, opts) opts = opts or {} check_param_table(opts, { if_exists = 'boolean' }) local _func = box.space[box.schema.FUNC_ID] + local _vfunc = box.space[box.schema.VFUNC_ID] local fid local tuple if type(name) == 'string' then - tuple = _func.index.name:get{name} + tuple = _vfunc.index.name:get{name} else - tuple = _func:get{name} + tuple = _vfunc:get{name} end if tuple then fid = tuple[1] @@ -1847,12 +1857,12 @@ box.schema.func.drop = function(name, opts) end function box.schema.func.exists(name_or_id) - local _func = box.space[box.schema.VFUNC_ID] + local _vfunc = box.space[box.schema.VFUNC_ID] local tuple = nil if type(name_or_id) == 'string' then - tuple = _func.index.name:get{name_or_id} + tuple = _vfunc.index.name:get{name_or_id} elseif type(name_or_id) == 'number' then - tuple = _func:get{name_or_id} + tuple = _vfunc:get{name_or_id} end return tuple ~= nil end @@ -2007,8 +2017,9 @@ local function grant(uid, name, privilege, object_type, options.grantor = user_or_role_resolve(options.grantor) end local _priv = box.space[box.schema.PRIV_ID] + local _vpriv = box.space[box.schema.VPRIV_ID] -- add the granted privilege to the current set - local tuple = _priv:get{uid, object_type, oid} + local tuple = _vpriv:get{uid, object_type, oid} local old_privilege if tuple ~= nil then old_privilege = tuple[5] @@ -2043,7 +2054,8 @@ local function revoke(uid, name, privilege, object_type, object_name, options) options = options or {} local oid = object_resolve(object_type, object_name) local _priv = box.space[box.schema.PRIV_ID] - local tuple = _priv:get{uid, object_type, oid} + local _vpriv = box.space[box.schema.VPRIV_ID] + local tuple = _vpriv:get{uid, object_type, oid} -- system privileges of admin and guest can't be revoked if tuple == nil then if options.if_exists then @@ -2072,32 +2084,32 @@ end local function drop(uid, opts) -- recursive delete of user data - local _priv = box.space[box.schema.PRIV_ID] - local spaces = box.space[box.schema.SPACE_ID].index.owner:select{uid} + local _vpriv = box.space[box.schema.VPRIV_ID] + local spaces = box.space[box.schema.VSPACE_ID].index.owner:select{uid} for k, tuple in pairs(spaces) do box.space[tuple[1]]:drop() end - local funcs = box.space[box.schema.FUNC_ID].index.owner:select{uid} + local funcs = box.space[box.schema.VFUNC_ID].index.owner:select{uid} for k, tuple in pairs(funcs) do box.schema.func.drop(tuple[1]) end -- if this is a role, revoke this role from whoever it was granted to - local grants = _priv.index.object:select{'role', uid} + local grants = _vpriv.index.object:select{'role', uid} for k, tuple in pairs(grants) do revoke(tuple[2], tuple[2], uid) end - local sequences = box.space[box.schema.SEQUENCE_ID].index.owner:select{uid} + local sequences = box.space[box.schema.VSEQUENCE_ID].index.owner:select{uid} for k, tuple in pairs(sequences) do box.schema.sequence.drop(tuple[1]) end -- xxx: hack, we have to revoke session and usage privileges -- of a user using a setuid function in absence of create/drop -- privileges and grant option - if box.space._user:get{uid}[4] == 'user' then + if box.space._vuser:get{uid}[4] == 'user' then box.session.su('admin', box.schema.user.revoke, uid, 'session,usage', 'universe', nil, {if_exists = true}) end - local privs = _priv.index.primary:select{uid} + local privs = _vpriv.index.primary:select{uid} for k, tuple in pairs(privs) do revoke(uid, uid, tuple[5], tuple[3], tuple[4]) end @@ -2154,8 +2166,7 @@ box.schema.user.drop = function(name, opts) end local function info(id) - local _priv = box.space._priv - local _user = box.space._priv + local _priv = box.space._vpriv local privs = {} for _, v in pairs(_priv:select{id}) do table.insert( diff --git a/src/box/sysview_index.c b/src/box/sysview_index.c index 51bd63ac8..f1dfbefe5 100644 --- a/src/box/sysview_index.c +++ b/src/box/sysview_index.c @@ -198,15 +198,32 @@ static const struct index_vtab sysview_index_vtab = { /* .end_build = */ generic_index_end_build, }; +/* + * System view filters. + * Filter gives access to an object, if one of the following conditions is true: + * 1. User has read, write, drop or alter access to universe. + * 2. User has read access to according system space. + * 3. User has read, write, drop or alter access to the object. + * 4. User is a owner of the object. + * 5. User is grantor or grantee for the privilege. + * 6. User has execute for the function or the sequence. + * 7. User is parent for the user/role. + */ + +const uint32_t PRIV_WRDA = PRIV_W | PRIV_D | PRIV_A | PRIV_R; + static bool vspace_filter(struct space *source, struct tuple *tuple) { struct credentials *cr = effective_user(); - if (PRIV_R & cr->universal_access) - return true; /* read access to universe */ + /* + * Allow access for a user with read, write, + * drop or alter privileges for universe. + */ + if (PRIV_WRDA & cr->universal_access) + return true; if (PRIV_R & source->access[cr->auth_token].effective) return true; /* read access to _space space */ - uint32_t space_id; if (tuple_field_u32(tuple, BOX_SPACE_FIELD_ID, &space_id) != 0) return false; @@ -214,16 +231,24 @@ vspace_filter(struct space *source, struct tuple *tuple) if (space == NULL) return false; user_access_t effective = space->access[cr->auth_token].effective; - return ((PRIV_R | PRIV_W) & (cr->universal_access | effective) || - space->def->uid == cr->uid); + /* + * Allow access for space owners and users with any + * privilege for the space. + */ + return (PRIV_WRDA & effective || + space->def->uid == cr->uid); } static bool vuser_filter(struct space *source, struct tuple *tuple) { struct credentials *cr = effective_user(); - if (PRIV_R & cr->universal_access) - return true; /* read access to universe */ + /* + * Allow access for a user with read, write, + * drop or alter privileges for universe. + */ + if (PRIV_WRDA & cr->universal_access) + return true; if (PRIV_R & source->access[cr->auth_token].effective) return true; /* read access to _user space */ @@ -233,15 +258,20 @@ vuser_filter(struct space *source, struct tuple *tuple) uint32_t owner_id; if (tuple_field_u32(tuple, BOX_USER_FIELD_UID, &owner_id) != 0) return false; - return uid == cr->uid || owner_id == cr->uid; + /* Allow access for self, childs or public user. */ + return uid == cr->uid || owner_id == cr->uid || uid == PUBLIC; } static bool vpriv_filter(struct space *source, struct tuple *tuple) { struct credentials *cr = effective_user(); - if (PRIV_R & cr->universal_access) - return true; /* read access to universe */ + /* + * Allow access for a user with read, write, + * drop or alter privileges for universe. + */ + if (PRIV_WRDA & cr->universal_access) + return true; if (PRIV_R & source->access[cr->auth_token].effective) return true; /* read access to _priv space */ @@ -251,6 +281,7 @@ vpriv_filter(struct space *source, struct tuple *tuple) uint32_t grantee_id; if (tuple_field_u32(tuple, BOX_PRIV_FIELD_UID, &grantee_id) != 0) return false; + /* Allow access for privilege grantor or grantee. */ return grantor_id == cr->uid || grantee_id == cr->uid; } @@ -258,29 +289,37 @@ static bool vfunc_filter(struct space *source, struct tuple *tuple) { struct credentials *cr = effective_user(); - if ((PRIV_R | PRIV_X) & cr->universal_access) - return true; /* read or execute access to universe */ + /* + * Allow access for a user with read, write, + * drop, alter or execute privileges for universe. + */ + if ((PRIV_WRDA | PRIV_X) & cr->universal_access) + return true; if (PRIV_R & source->access[cr->auth_token].effective) return true; /* read access to _func space */ - const char *name = tuple_field_cstr(tuple, BOX_FUNC_FIELD_NAME); + uint32_t name_len; + const char *name = tuple_field_str(tuple, BOX_FUNC_FIELD_NAME, + &name_len); if (name == NULL) return false; - uint32_t name_len = strlen(name); struct func *func = func_by_name(name, name_len); assert(func != NULL); user_access_t effective = func->access[cr->auth_token].effective; - if (func->def->uid == cr->uid || (PRIV_X & effective)) - return true; - return false; + return func->def->uid == cr->uid || + ((PRIV_WRDA | PRIV_X) & effective); } static bool vsequence_filter(struct space *source, struct tuple *tuple) { struct credentials *cr = effective_user(); - if ((PRIV_R | PRIV_X) & cr->universal_access) - return true; /* read or execute access to universe */ + /* + * Allow access for a user with read, write, + * drop, alter or execute privileges for universe. + */ + if ((PRIV_WRDA | PRIV_X) & cr->universal_access) + return true; if (PRIV_R & source->access[cr->auth_token].effective) return true; /* read access to _sequence space */ @@ -291,12 +330,10 @@ vsequence_filter(struct space *source, struct tuple *tuple) if (sequence == NULL) return false; user_access_t effective = sequence->access[cr->auth_token].effective; - if (sequence->def->uid == cr->uid || ((PRIV_W | PRIV_R) & effective)) - return true; - return false; + return sequence->def->uid == cr->uid || + ((PRIV_WRDA | PRIV_X) & effective); } - struct sysview_index * sysview_index_new(struct sysview_engine *sysview, struct index_def *def, const char *space_name) diff --git a/test/box/access.result b/test/box/access.result index 5c39bc97e..131a21510 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -386,7 +386,8 @@ session.su('grantee') -- fails - can't suicide - ask the creator to kill you box.schema.user.drop('grantee') --- -- error: Read access to space '_user' is denied for user 'grantee' +- error: 'Failed to drop user or role ''grantee'': the user is active in the current + session' ... session.su('grantor') --- @@ -471,7 +472,7 @@ session.su('user1') -- permission denied box.schema.user.passwd('admin', 'xxx') --- -- error: Read access to space '_user' is denied for user 'user1' +- error: User 'admin' is not found ... session.su('admin') --- @@ -1048,7 +1049,7 @@ session.su("test1") ... box.schema.user.disable("test") --- -- error: Read access to space '_user' is denied for user 'test1' +- error: User 'test' is not found ... session.su("admin") --- @@ -1080,7 +1081,7 @@ session.su("test1") ... box.schema.user.grant("test", "usage", "universe") --- -- error: Read access to space '_user' is denied for user 'test1' +- error: User 'test' is not found ... session.su('admin') --- @@ -1357,28 +1358,59 @@ box.schema.user.create("tester") s = box.schema.space.create("test") --- ... +_ = s:create_index("primary") +--- +... +seq = box.schema.sequence.create("test") +--- +... u = box.schema.user.create("test") --- ... f = box.schema.func.create("test") --- ... -box.schema.user.grant("tester", "read,execute", "universe") +-- failed create, auto_increment requires read. +box.session.su("tester") +--- +... +box.schema.space.create("test_space") +--- +- error: Write access to space '_schema' is denied for user 'tester' +... +box.schema.user.create('test_user') +--- +- error: Read access to space '_user' is denied for user 'tester' +... +box.schema.func.create('test_func') +--- +- error: Read access to space '_func' is denied for user 'tester' +... +box.session.su("admin") +--- +... +box.schema.user.grant("tester", "read", "universe") --- ... -- failed create -box.session.su("tester", box.schema.space.create, "test_space") +box.session.su("tester") +--- +... +box.schema.space.create("test_space") --- - error: Write access to space '_schema' is denied for user 'tester' ... -box.session.su("tester", box.schema.user.create, 'test_user') +box.schema.user.create('test_user') --- - error: Write access to space '_user' is denied for user 'tester' ... -box.session.su("tester", box.schema.func.create, 'test_func') +box.schema.func.create('test_func') --- - error: Write access to space '_func' is denied for user 'tester' ... +box.session.su("admin") +--- +... -- -- FIXME 2.0: we still need to grant 'write' on universe -- explicitly since we still use process_rw to write to system @@ -1387,24 +1419,36 @@ box.session.su("tester", box.schema.func.create, 'test_func') box.schema.user.grant("tester", "create,write", "universe") --- ... +box.session.su("tester") +--- +... -- successful create -s1 = box.session.su("tester", box.schema.space.create, "test_space") +s1 = box.schema.space.create("test_space") --- ... -_ = box.session.su("tester", box.schema.user.create, 'test_user') +_ = s1:create_index("primary") --- ... -_ = box.session.su("tester", box.schema.func.create, 'test_func') +_ = box.schema.user.create('test_user') +--- +... +_ = box.schema.func.create('test_func') +--- +... +seq1 = box.schema.sequence.create('test_seq') --- ... -- successful drop of owned objects -_ = box.session.su("tester", s1.drop, s1) +s1:drop() --- ... -_ = box.session.su("tester", box.schema.user.drop, 'test_user') +seq1:drop() --- ... -_ = box.session.su("tester", box.schema.func.drop, 'test_func') +box.schema.user.drop('test_user') +--- +... +box.schema.func.drop('test_func') --- ... -- failed alter @@ -1414,22 +1458,24 @@ _ = box.session.su("tester", box.schema.func.drop, 'test_func') -- box.session.su("tester", s.format, s, {name="id", type="unsigned"}) -- failed drop -- box.session.su("tester", s.drop, s) --- can't use here sudo --- because drop use sudo inside --- and currently sudo can't be performed nested -box.session.su("tester") +s:drop() --- +- error: Drop access to space 'test' is denied for user 'tester' +... +seq:drop() +--- +- error: Drop access to sequence 'test' is denied for user 'tester' ... box.schema.user.drop("test") --- - error: Revoke access to role 'public' is denied for user 'tester' ... -box.session.su("admin") +box.schema.func.drop("test") --- +- error: Drop access to function 'test' is denied for user 'tester' ... -box.session.su("tester", box.schema.func.drop, "test") +box.session.su("admin") --- -- error: Drop access to function 'test' is denied for user 'tester' ... box.schema.user.grant("tester", "drop", "universe") --- @@ -1438,6 +1484,9 @@ box.schema.user.grant("tester", "drop", "universe") box.session.su("tester", s.drop, s) --- ... +box.session.su("tester", seq.drop, seq) +--- +... box.session.su("tester", box.schema.user.drop, "test") --- ... @@ -1510,36 +1559,86 @@ box.schema.func.exists('test') --- - false ... +box.space._vspace.index.name:get{"test"} ~= nil +--- +- false +... +box.space._vsequence.index.name:get{"test"} ~= nil +--- +- false +... -- --- create an object, but 'guest' still has no access to it +-- create an objects, but 'guest' still has no access to them -- box.session.su('admin', box.schema.func.create, 'test') --- ... +s = box.session.su('admin', box.schema.space.create, 'test') +--- +... +_ = box.session.su('admin', box.schema.sequence.create, 'test') +--- +... box.schema.func.exists('test') --- - false ... +box.space._vspace.index.name:get{"test"} ~= nil +--- +- false +... +box.space._vsequence.index.name:get{"test"} ~= nil +--- +- false +... -- -- grant access, the object should become visible to guest -- box.session.su('admin', box.schema.user.grant, 'guest', 'execute', 'function', 'test') --- ... +box.session.su('admin', box.schema.user.grant, 'guest', 'read', 'space', 'test') +--- +... +box.session.su('admin', box.schema.user.grant, 'guest', 'read', 'sequence', 'test') +--- +... box.schema.func.exists('test') --- - true ... +box.space._vspace.index.name:get{"test"} ~= nil +--- +- true +... +box.space._vsequence.index.name:get{"test"} ~= nil +--- +- true +... -- --- drop object +-- drop objects -- box.session.su('admin', box.schema.func.drop, 'test') --- ... +box.session.su('admin', s.drop, s) +--- +... +box.session.su('admin', box.schema.sequence.drop, 'test') +--- +... box.schema.func.exists('test') --- - false ... +box.space._vspace.index.name:get{"test"} ~= nil +--- +- false +... +box.space._vsequence.index.name:get{"test"} ~= nil +--- +- false +... -- -- restore -- diff --git a/test/box/access.test.lua b/test/box/access.test.lua index 501c766ae..4bd34e45d 100644 --- a/test/box/access.test.lua +++ b/test/box/access.test.lua @@ -509,14 +509,24 @@ s:drop() -- box.schema.user.create("tester") s = box.schema.space.create("test") +_ = s:create_index("primary") +seq = box.schema.sequence.create("test") u = box.schema.user.create("test") f = box.schema.func.create("test") -box.schema.user.grant("tester", "read,execute", "universe") +-- failed create, auto_increment requires read. +box.session.su("tester") +box.schema.space.create("test_space") +box.schema.user.create('test_user') +box.schema.func.create('test_func') +box.session.su("admin") +box.schema.user.grant("tester", "read", "universe") -- failed create -box.session.su("tester", box.schema.space.create, "test_space") -box.session.su("tester", box.schema.user.create, 'test_user') -box.session.su("tester", box.schema.func.create, 'test_func') +box.session.su("tester") +box.schema.space.create("test_space") +box.schema.user.create('test_user') +box.schema.func.create('test_func') +box.session.su("admin") -- -- FIXME 2.0: we still need to grant 'write' on universe @@ -524,15 +534,19 @@ box.session.su("tester", box.schema.func.create, 'test_func') -- tables from ddl -- box.schema.user.grant("tester", "create,write", "universe") +box.session.su("tester") -- successful create -s1 = box.session.su("tester", box.schema.space.create, "test_space") -_ = box.session.su("tester", box.schema.user.create, 'test_user') -_ = box.session.su("tester", box.schema.func.create, 'test_func') +s1 = box.schema.space.create("test_space") +_ = s1:create_index("primary") +_ = box.schema.user.create('test_user') +_ = box.schema.func.create('test_func') +seq1 = box.schema.sequence.create('test_seq') -- successful drop of owned objects -_ = box.session.su("tester", s1.drop, s1) -_ = box.session.su("tester", box.schema.user.drop, 'test_user') -_ = box.session.su("tester", box.schema.func.drop, 'test_func') +s1:drop() +seq1:drop() +box.schema.user.drop('test_user') +box.schema.func.drop('test_func') -- failed alter -- box.session.su("tester", s.format, s, {name="id", type="unsigned"}) @@ -543,19 +557,16 @@ _ = box.session.su("tester", box.schema.func.drop, 'test_func') -- failed drop -- box.session.su("tester", s.drop, s) - --- can't use here sudo --- because drop use sudo inside --- and currently sudo can't be performed nested -box.session.su("tester") +s:drop() +seq:drop() box.schema.user.drop("test") -box.session.su("admin") - -box.session.su("tester", box.schema.func.drop, "test") +box.schema.func.drop("test") +box.session.su("admin") box.schema.user.grant("tester", "drop", "universe") -- successful drop box.session.su("tester", s.drop, s) +box.session.su("tester", seq.drop, seq) box.session.su("tester", box.schema.user.drop, "test") box.session.su("tester", box.schema.func.drop, "test") @@ -589,22 +600,36 @@ box.session.su('guest') -- has no access to the function -- box.schema.func.exists('test') +box.space._vspace.index.name:get{"test"} ~= nil +box.space._vsequence.index.name:get{"test"} ~= nil -- --- create an object, but 'guest' still has no access to it +-- create an objects, but 'guest' still has no access to them -- box.session.su('admin', box.schema.func.create, 'test') +s = box.session.su('admin', box.schema.space.create, 'test') +_ = box.session.su('admin', box.schema.sequence.create, 'test') box.schema.func.exists('test') +box.space._vspace.index.name:get{"test"} ~= nil +box.space._vsequence.index.name:get{"test"} ~= nil -- -- grant access, the object should become visible to guest -- box.session.su('admin', box.schema.user.grant, 'guest', 'execute', 'function', 'test') +box.session.su('admin', box.schema.user.grant, 'guest', 'read', 'space', 'test') +box.session.su('admin', box.schema.user.grant, 'guest', 'read', 'sequence', 'test') box.schema.func.exists('test') +box.space._vspace.index.name:get{"test"} ~= nil +box.space._vsequence.index.name:get{"test"} ~= nil -- --- drop object +-- drop objects -- box.session.su('admin', box.schema.func.drop, 'test') +box.session.su('admin', s.drop, s) +box.session.su('admin', box.schema.sequence.drop, 'test') box.schema.func.exists('test') +box.space._vspace.index.name:get{"test"} ~= nil +box.space._vsequence.index.name:get{"test"} ~= nil -- -- restore -- -box.session.su('admin') +box.session.su('admin') \ No newline at end of file diff --git a/test/box/access_bin.result b/test/box/access_bin.result index b81279cfe..7b30d11f2 100644 --- a/test/box/access_bin.result +++ b/test/box/access_bin.result @@ -344,7 +344,7 @@ box.session.su('admin', box.session.user()) --- - error: 'bad argument #2 to ''?'' (function expected, got string)' ... --- clenaup +-- cleanup box.session.su('admin') --- ... diff --git a/test/box/access_bin.test.lua b/test/box/access_bin.test.lua index cb3a50c68..4c7a6d08f 100644 --- a/test/box/access_bin.test.lua +++ b/test/box/access_bin.test.lua @@ -131,5 +131,5 @@ box.schema.func.drop('f2') -- box.session.su('admin', box.session.user) box.session.su('admin', box.session.user()) --- clenaup +-- cleanup box.session.su('admin') diff --git a/test/box/access_misc.result b/test/box/access_misc.result index 3a56a4cb2..8bf99f2e7 100644 --- a/test/box/access_misc.result +++ b/test/box/access_misc.result @@ -175,6 +175,17 @@ gs = box.schema.space.create('guest_space') --- - error: Write access to space '_schema' is denied for user 'guest' ... +-- +-- FIXME: object create calls system space auto_increment, which requires +-- read and write privileges. Create privilege must solve this. +-- +box.schema.func.create('guest_func') +--- +- error: Read access to space '_func' is denied for user 'guest' +... +session.su('admin', box.schema.user.grant, "guest", "read", "universe") +--- +... box.schema.func.create('guest_func') --- - error: Read access to space '_func' is denied for user 'guest' @@ -182,6 +193,9 @@ box.schema.func.create('guest_func') session.su('admin') --- ... +box.schema.user.revoke("guest", "read", "universe") +--- +... s:select() --- - - [2] diff --git a/test/box/access_misc.test.lua b/test/box/access_misc.test.lua index cf6447ea6..27064c491 100644 --- a/test/box/access_misc.test.lua +++ b/test/box/access_misc.test.lua @@ -70,9 +70,16 @@ s:insert({4}) s:delete({3}) s:drop() gs = box.schema.space.create('guest_space') +-- +-- FIXME: object create calls system space auto_increment, which requires +-- read and write privileges. Create privilege must solve this. +-- +box.schema.func.create('guest_func') +session.su('admin', box.schema.user.grant, "guest", "read", "universe") box.schema.func.create('guest_func') - session.su('admin') +box.schema.user.revoke("guest", "read", "universe") + s:select() -- -- Create user with universe read&write grants diff --git a/test/box/access_sysview.result b/test/box/access_sysview.result index 340ed2164..20efd2bbc 100644 --- a/test/box/access_sysview.result +++ b/test/box/access_sysview.result @@ -266,11 +266,11 @@ box.session.su('guest') ... #box.space._vuser:select{} --- -- 1 +- 5 ... #box.space._vpriv:select{} --- -- 2 +- 15 ... #box.space._vfunc:select{} --- @@ -343,7 +343,7 @@ box.session.su('guest') -- _vuser -- -- a guest user can read information about itself -t = box.space._vuser:select(); return #t == 1 and t[1][3] == 'guest' +t = box.space._vuser:select(); for i = 1, #t do if t[i][3] == 'guest' then return true end end return false --- - true ... @@ -526,8 +526,9 @@ box.schema.user.grant('guest', 'execute', 'function', 'test') box.session.su('guest') --- ... -#box.space._vfunc:select{} = cnt + 1 +#box.space._vfunc:select{} == func_cnt --- +- true ... box.session.su('admin') --- @@ -551,7 +552,7 @@ box.schema.user.grant('guest', 'execute', 'universe') box.session.su('guest') --- ... -#box.space._vfunc:select{} == cnt + 1 +#box.space._vfunc:select{} == func_cnt --- - true ... diff --git a/test/box/access_sysview.test.lua b/test/box/access_sysview.test.lua index 7955ffc98..4cc5611a6 100644 --- a/test/box/access_sysview.test.lua +++ b/test/box/access_sysview.test.lua @@ -134,7 +134,7 @@ box.session.su('guest') -- -- a guest user can read information about itself -t = box.space._vuser:select(); return #t == 1 and t[1][3] == 'guest' +t = box.space._vuser:select(); for i = 1, #t do if t[i][3] == 'guest' then return true end end return false -- read access to original space also allow to read a view box.session.su('admin') @@ -218,7 +218,7 @@ box.session.su('admin') box.schema.user.grant('guest', 'execute', 'function', 'test') box.session.su('guest') -#box.space._vfunc:select{} = cnt + 1 +#box.space._vfunc:select{} == func_cnt box.session.su('admin') box.schema.user.revoke('guest', 'execute', 'function', 'test') @@ -230,7 +230,7 @@ box.session.su('admin') box.schema.user.grant('guest', 'execute', 'universe') box.session.su('guest') -#box.space._vfunc:select{} == cnt + 1 +#box.space._vfunc:select{} == func_cnt box.session.su('admin') box.schema.user.revoke('guest', 'execute', 'universe') diff --git a/test/box/ddl.result b/test/box/ddl.result index 30f0cf7ec..f84a4dc50 100644 --- a/test/box/ddl.result +++ b/test/box/ddl.result @@ -580,6 +580,10 @@ test_run:cmd("setopt delimiter ''"); --- - true ... +-- finish transaction +box.rollback() +--- +... _ = c:get() --- ... diff --git a/test/box/ddl.test.lua b/test/box/ddl.test.lua index ebbefe77b..ba028361d 100644 --- a/test/box/ddl.test.lua +++ b/test/box/ddl.test.lua @@ -234,6 +234,8 @@ test_latch:create_index("sec2", {unique = true, parts = {2, 'unsigned'}}) box.commit(); test_run:cmd("setopt delimiter ''"); +-- finish transaction +box.rollback() _ = c:get() test_latch:drop() -- this is where everything stops diff --git a/test/box/on_replace.result b/test/box/on_replace.result index a961df192..8c52e1282 100644 --- a/test/box/on_replace.result +++ b/test/box/on_replace.result @@ -471,7 +471,7 @@ t = s:on_replace(function () s:create_index('sec') end, t) ... s:replace({2, 3}) --- -- error: Space _index does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... t = s:on_replace(function () box.schema.user.create('newu') end, t) --- @@ -506,21 +506,21 @@ t = s:on_replace(function () s:drop() end, t) ... s:replace({5, 6}) --- -- error: DDL does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... t = s:on_replace(function () box.schema.func.create('newf') end, t) --- ... s:replace({6, 7}) --- -- error: Space _func does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... t = s:on_replace(function () box.schema.user.grant('guest', 'read,write', 'space', 'test_on_repl_ddl') end, t) --- ... s:replace({7, 8}) --- -- error: Space _priv does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... t = s:on_replace(function () s:rename('newname') end, t) --- diff --git a/test/box/role.result b/test/box/role.result index 736ec85f9..806cea90b 100644 --- a/test/box/role.result +++ b/test/box/role.result @@ -662,7 +662,7 @@ box.session.su('john') -- error box.schema.user.grant('grantee', 'role') --- -- error: Read access to space '_user' is denied for user 'john' +- error: User 'grantee' is not found ... -- box.session.su('admin') diff --git a/test/box/transaction.result b/test/box/transaction.result index 05803316d..2fb1abf7c 100644 --- a/test/box/transaction.result +++ b/test/box/transaction.result @@ -69,7 +69,7 @@ box.rollback(); ... box.begin() box.schema.func.create('test'); --- -- error: Space _func does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... box.rollback(); --- @@ -83,7 +83,7 @@ box.rollback(); ... box.begin() box.schema.user.grant('guest', 'read', 'space', '_priv'); --- -- error: Space _priv does not support multi-statement transactions +- error: A multi-statement transaction can not use multiple storage engines ... box.rollback(); --- @@ -95,6 +95,20 @@ box.begin() box.space._user:delete{box.schema.GUEST_ID}; box.rollback(); --- ... +box.begin() box.space._space:delete{box.schema.CLUSTER_ID}; +--- +- error: DDL does not support multi-statement transactions +... +box.rollback(); +--- +... +box.begin() box.space._sequence:insert{1, 1, 'test', 1, 1, 2, 1, 0, false}; +--- +- error: Space _sequence does not support multi-statement transactions +... +box.rollback(); +--- +... box.begin() box.space._schema:insert{'test'}; --- - error: Space _schema does not support multi-statement transactions diff --git a/test/box/transaction.test.lua b/test/box/transaction.test.lua index ca6de44a3..14d1a690d 100644 --- a/test/box/transaction.test.lua +++ b/test/box/transaction.test.lua @@ -38,6 +38,10 @@ box.begin() box.schema.user.grant('guest', 'read', 'space', '_priv'); box.rollback(); box.begin() box.space._user:delete{box.schema.GUEST_ID}; box.rollback(); +box.begin() box.space._space:delete{box.schema.CLUSTER_ID}; +box.rollback(); +box.begin() box.space._sequence:insert{1, 1, 'test', 1, 1, 2, 1, 0, false}; +box.rollback(); box.begin() box.space._schema:insert{'test'}; box.rollback(); box.begin() box.space._cluster:insert{123456789, 'abc'}; diff --git a/test/engine/iterator.result b/test/engine/iterator.result index 423ed0b7b..ae14c4320 100644 --- a/test/engine/iterator.result +++ b/test/engine/iterator.result @@ -4211,7 +4211,7 @@ s:replace{35} ... state, value = gen(param,state) --- -- error: 'builtin/box/schema.lua:985: usage: next(param, state)' +- error: 'builtin/box/schema.lua:993: usage: next(param, state)' ... value --- diff --git a/test/engine/savepoint.result b/test/engine/savepoint.result index d440efa6b..dc2ad7986 100644 --- a/test/engine/savepoint.result +++ b/test/engine/savepoint.result @@ -14,7 +14,7 @@ s1 = box.savepoint() ... box.rollback_to_savepoint(s1) --- -- error: 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- error: 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... box.begin() s1 = box.savepoint() --- @@ -323,27 +323,27 @@ test_run:cmd("setopt delimiter ''"); ok1, errmsg1 --- - false -- 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... ok2, errmsg2 --- - false -- 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... ok3, errmsg3 --- - false -- 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... ok4, errmsg4 --- - false -- 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... ok5, errmsg5 --- - false -- 'builtin/box/schema.lua:300: Usage: box.rollback_to_savepoint(savepoint)' +- 'builtin/box/schema.lua:301: Usage: box.rollback_to_savepoint(savepoint)' ... s:select{} --- -- 2.17.1