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 62E7322774 for ; Wed, 16 May 2018 08:37:48 -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 BCc1kiSVubvS for ; Wed, 16 May 2018 08:37:48 -0400 (EDT) Received: from smtp14.mail.ru (smtp14.mail.ru [94.100.181.95]) (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 A65B2226BF for ; Wed, 16 May 2018 08:37:47 -0400 (EDT) From: Ilya Markov Subject: [tarantool-patches] [security 1/2] security: Refactor reads from systems spaces Date: Wed, 16 May 2018 15:37:26 +0300 Message-Id: <391cb156f0f321ea7c2b987669798c3e6846c3f5.1526474053.git.imarkov@tarantool.org> In-Reply-To: References: In-Reply-To: References: 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: georgy@tarantool.org Cc: kostja@tarantool.org, tarantool-patches@freelists.org Replace reads from systems spaces with reads from corresponding system views. After this patch some error messages are changed: * Accessing to objects that are not accessible for current user raises the error claiming these objects don't exists. * Attempt to add in transaction such methods as object create, drop raises an multi-engine transaction error instead of multi-statement transaction error. In scope of #3250 --- src/box/lua/schema.lua | 97 +++++++++++++----------- src/box/sysview_index.c | 86 +++++++++++++--------- test/box/access.result | 155 ++++++++++++++++++++++++++++++++------- test/box/access.test.lua | 69 +++++++++++------ test/box/access_bin.result | 16 ++-- test/box/access_bin.test.lua | 4 +- 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, 368 insertions(+), 151 deletions(-) diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 1a616d5..677325c 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] @@ -1741,12 +1749,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] @@ -1762,12 +1770,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] @@ -1785,13 +1793,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 @@ -1805,7 +1813,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) @@ -1822,12 +1831,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] @@ -1843,12 +1853,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 @@ -2003,8 +2013,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] @@ -2039,7 +2050,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 @@ -2068,32 +2080,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 @@ -2150,8 +2162,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 8bfc39b..c8e9a1d 100644 --- a/src/box/sysview_index.c +++ b/src/box/sysview_index.c @@ -197,23 +197,35 @@ static const struct index_vtab sysview_index_vtab = { /* .end_build = */ generic_index_end_build, }; +const uint32_t PRIV_WRDA = PRIV_W | PRIV_D | PRIV_A | PRIV_R; + + +/* + * System view filters. + * Filter must give read access to object, if: + * 1. User has modification or read access to universe. + * 2. User has read access to according system space. + * 3. User has modification or read access to object. + * 4. User is an owner of the object. + * 5. Other specific conditions of the object of object type. + */ 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 */ - if (PRIV_R & source->access[cr->auth_token].effective) - return true; /* read access to _space space */ - + /* If user has global alter, drop privilege she may access all spaces. */ + if (cr->universal_access & PRIV_WRDA) + return true; + if (source->access[cr->auth_token].effective & PRIV_R) + return true; uint32_t space_id; if (tuple_field_u32(tuple, BOX_SPACE_FIELD_ID, &space_id) != 0) return false; struct space *space = space_cache_find(space_id); if (space == NULL) return false; - user_access_t effective = space->access[cr->auth_token].effective; - return ((PRIV_R | PRIV_W) & (cr->universal_access | effective) || + uint32_t effective = space->access[cr->auth_token].effective; + return (PRIV_WRDA & effective || space->def->uid == cr->uid); } @@ -221,10 +233,11 @@ 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 */ - if (PRIV_R & source->access[cr->auth_token].effective) - return true; /* read access to _user space */ + /* If user has global alter, drop privilege she may access all users. */ + if (cr->universal_access & PRIV_WRDA) + return true; + if (source->access[cr->auth_token].effective & PRIV_R) + return true; /* read access to _user space. */ uint32_t uid; if (tuple_field_u32(tuple, BOX_USER_FIELD_ID, &uid) != 0) @@ -232,16 +245,19 @@ 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; + 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 */ - if (PRIV_R & source->access[cr->auth_token].effective) + /* If user has global alter, drop privilege + * she may access all privileges + */ + if (cr->universal_access & PRIV_WRDA) + return true; + if (source->access[cr->auth_token].effective & PRIV_R) return true; /* read access to _priv space */ uint32_t grantor_id; @@ -250,37 +266,43 @@ 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; - return grantor_id == cr->uid || grantee_id == cr->uid; + const char *type; + uint32_t obj_id; + if ((type = tuple_field_cstr(tuple, BOX_PRIV_FIELD_OBJECT_TYPE)) == NULL || + tuple_field_u32(tuple, BOX_PRIV_FIELD_OBJECT_ID, &obj_id) != 0) + return false; + return grantor_id == cr->uid || grantee_id == cr->uid || + (strncmp(type, "role", 4) == 0 && obj_id == PUBLIC); } 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 */ - if (PRIV_R & source->access[cr->auth_token].effective) + if (cr->universal_access & (PRIV_WRDA | PRIV_X)) + return true; + if (source->access[cr->auth_token].effective & PRIV_R) 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; + uint32_t effective = func->access[cr->auth_token].effective; + 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 */ - if (PRIV_R & source->access[cr->auth_token].effective) + if (cr->universal_access & PRIV_WRDA) + return true; + if (source->access[cr->auth_token].effective & PRIV_R) return true; /* read access to _sequence space */ uint32_t id; @@ -289,13 +311,11 @@ vsequence_filter(struct space *source, struct tuple *tuple) struct sequence *sequence = sequence_by_id(id); 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; + uint32_t effective = sequence->access[cr->auth_token].effective; + return sequence->def->uid == cr->uid || + (PRIV_WRDA & 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 5c39bc9..476e594 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') --- @@ -1133,6 +1134,9 @@ s = box.schema.space.create("admin_space") box.schema.user.grant('guest', 'super') --- ... +box.schema.user.grant('guest', 'read', "universe") +--- +... box.session.su('guest') --- ... @@ -1173,15 +1177,18 @@ box.schema.space.create('test') ... box.schema.user.create('test') --- -- error: Read access to space '_user' is denied for user 'guest' +- error: Write access to space '_user' is denied for user 'guest' ... box.schema.func.create('test') --- -- error: Read access to space '_func' is denied for user 'guest' +- error: Write access to space '_func' is denied for user 'guest' ... box.session.su('admin') --- ... +box.schema.user.revoke('guest', 'read', "universe") +--- +... -- -- gh-2911 on_access_denied trigger -- @@ -1357,28 +1364,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 +1425,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 +1464,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 +1490,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 +1565,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 501c766..81f5ed1 100644 --- a/test/box/access.test.lua +++ b/test/box/access.test.lua @@ -438,6 +438,7 @@ s:drop() -- s = box.schema.space.create("admin_space") box.schema.user.grant('guest', 'super') +box.schema.user.grant('guest', 'read', "universe") box.session.su('guest') _ = box.schema.space.create('test') box.space.test:drop() @@ -455,6 +456,7 @@ box.schema.space.create('test') box.schema.user.create('test') box.schema.func.create('test') box.session.su('admin') +box.schema.user.revoke('guest', 'read', "universe") -- -- gh-2911 on_access_denied trigger @@ -509,14 +511,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 +536,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 +559,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 +602,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 b81279c..ce09299 100644 --- a/test/box/access_bin.result +++ b/test/box/access_bin.result @@ -50,19 +50,22 @@ box.schema.func.create('setuid_func') box.schema.user.grant('guest', 'execute', 'function', 'setuid_func') --- ... +box.schema.user.grant('guest', 'read', 'universe') +--- +... c = remote.connect(box.cfg.listen) --- ... c:call("setuid_func") --- -- error: Read access to space 'setuid_space' is denied for user 'guest' +- error: Write access to space 'setuid_space' is denied for user 'guest' ... session.su('guest') --- ... setuid_func() --- -- error: Read access to space 'setuid_space' is denied for user 'guest' +- error: Write access to space 'setuid_space' is denied for user 'guest' ... session.su('admin') --- @@ -85,7 +88,7 @@ session.su('guest') ... setuid_func() --- -- error: Read access to space 'setuid_space' is denied for user 'guest' +- error: Write access to space 'setuid_space' is denied for user 'guest' ... session.su('admin') --- @@ -122,7 +125,7 @@ session.su('guest') ... setuid_func() --- -- error: Read access to space 'setuid_space' is denied for user 'guest' +- error: Write access to space 'setuid_space' is denied for user 'guest' ... session.su('admin') --- @@ -296,6 +299,9 @@ test:drop() box.schema.user.grant('guest', 'execute', 'universe') --- ... +box.schema.user.revoke('guest', 'read', 'universe') +--- +... function f1() return box.space._func:get(1)[4] end --- ... @@ -344,7 +350,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 cb3a50c..b4f5f64 100644 --- a/test/box/access_bin.test.lua +++ b/test/box/access_bin.test.lua @@ -20,6 +20,7 @@ index = setuid_space:create_index('primary') setuid_func = function() return box.space.setuid_space:auto_increment{} end box.schema.func.create('setuid_func') box.schema.user.grant('guest', 'execute', 'function', 'setuid_func') +box.schema.user.grant('guest', 'read', 'universe') c = remote.connect(box.cfg.listen) c:call("setuid_func") session.su('guest') @@ -112,6 +113,7 @@ test:drop() -- -- notice that guest can execute stuff, but can't read space _func box.schema.user.grant('guest', 'execute', 'universe') +box.schema.user.revoke('guest', 'read', 'universe') function f1() return box.space._func:get(1)[4] end function f2() return box.space._func:get(2)[4] end box.schema.func.create('f1') @@ -131,5 +133,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 3a56a4c..8bf99f2 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 cf6447e..27064c4 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 340ed21..20efd2b 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 7955ffc..4cc5611 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 f249f8f..15faa9a 100644 --- a/test/box/ddl.result +++ b/test/box/ddl.result @@ -565,6 +565,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 6029c6e..93501bd 100644 --- a/test/box/ddl.test.lua +++ b/test/box/ddl.test.lua @@ -226,6 +226,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 a961df1..8c52e12 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 736ec85..806cea9 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 0580331..2fb1abf 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 ca6de44..14d1a69 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 423ed0b..ae14c43 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 d440efa..dc2ad79 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.7.4