[tarantool-patches] [PATCH] security: Use system views instead of system spaces

Georgy Kirichenko georgy at tarantool.org
Mon Jun 4 19:02:21 MSK 2018


From: Ilya Markov <imarkov at tarantool.org>

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







More information about the Tarantool-patches mailing list