From 1e1f77a3ffb6ad9014d6cc03bc023016f190f13b Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Mon, 2 Feb 2015 17:57:24 +0300
Subject: [PATCH] Fix #696: Check global READ permissions for replication

---
 src/box/box.cc                   |  6 +++
 test/lib/tarantool-python        |  2 +-
 test/replication/cluster.result  | 31 +++++++++++++++
 test/replication/cluster.test.py | 67 ++++++++++++++++++++++++++++++++
 4 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index f8816e317b..98faad921d 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -344,6 +344,9 @@ box_on_cluster_join(const tt_uuid *server_uuid)
 void
 box_process_join(int fd, struct xrow_header *header)
 {
+	/* Check permissions */
+	access_check_universe(PRIV_R);
+
 	assert(header->type == IPROTO_JOIN);
 	struct tt_uuid server_uuid = uuid_nil;
 	xrow_decode_join(header, &server_uuid);
@@ -357,6 +360,9 @@ box_process_join(int fd, struct xrow_header *header)
 void
 box_process_subscribe(int fd, struct xrow_header *header)
 {
+	/* Check permissions */
+	access_check_universe(PRIV_R);
+
 	/* process SUBSCRIBE request via replication relay */
 	replication_subscribe(fd, header);
 }
diff --git a/test/lib/tarantool-python b/test/lib/tarantool-python
index 0ac9a67edf..cb93bc1111 160000
--- a/test/lib/tarantool-python
+++ b/test/lib/tarantool-python
@@ -1 +1 @@
-Subproject commit 0ac9a67edffc4147cb64e69b02ad4717b1586e6e
+Subproject commit cb93bc11113a106d3b54b92fe15184ded658f393
diff --git a/test/replication/cluster.result b/test/replication/cluster.result
index 230cd06a13..3e85cc24bd 100644
--- a/test/replication/cluster.result
+++ b/test/replication/cluster.result
@@ -1,3 +1,34 @@
+ok - cluster uuid
+-------------------------------------------------------------
+ gh-696: Check global READ permissions for replication
+-------------------------------------------------------------
+ok - join without read permissions to universe
+ok - subscribe without read permissions to universe
+box.schema.user.grant('guest', 'read', 'universe')
+---
+...
+ok - join without write permissions to _cluster
+box.schema.user.grant('guest', 'write', 'space', '_cluster')
+---
+...
+ok - join with granted permissions
+box.schema.user.revoke('guest', 'read', 'universe')
+---
+...
+box.schema.user.revoke('guest', 'write', 'space', '_cluster')
+---
+...
+box.schema.user.grant('guest', 'replication')
+---
+...
+ok - join with granted role
+box.schema.user.revoke('guest', 'replication')
+---
+...
+box.snapshot()
+---
+- ok
+...
 -------------------------------------------------------------
 gh-434: Assertion if replace _cluster tuple
 -------------------------------------------------------------
diff --git a/test/replication/cluster.test.py b/test/replication/cluster.test.py
index 794e15cc8e..37dcab8038 100644
--- a/test/replication/cluster.test.py
+++ b/test/replication/cluster.test.py
@@ -2,8 +2,75 @@ import os
 import sys
 import re
 import yaml
+import uuid
 from lib.tarantool_server import TarantoolServer
 
+## Get cluster uuid
+cluster_uuid = ''
+try:
+    cluster_uuid = yaml.load(server.admin("box.space._schema:get('cluster')",
+        silent = True))[0][1]
+    uuid.UUID('{' + cluster_uuid + '}')
+    print 'ok - cluster uuid'
+except Exception as e:
+    print 'not ok - invalid cluster uuid', e
+
+print '-------------------------------------------------------------'
+print ' gh-696: Check global READ permissions for replication'
+print '-------------------------------------------------------------'
+
+# Generate replica cluster UUID
+replica_uuid = str(uuid.uuid4())
+
+## Universal read permission is required to perform JOIN/SUBSCRIBE
+rows = list(server.sql.py_con.join(replica_uuid))
+print len(rows) == 1 and rows[0].return_message.find('Read access') >= 0 and \
+    'ok' or 'not ok', '-', 'join without read permissions to universe'
+rows = list(server.sql.py_con.subscribe(cluster_uuid, replica_uuid))
+print len(rows) == 1 and rows[0].return_message.find('Read access') >= 0 and \
+    'ok' or 'not ok', '-', 'subscribe without read permissions to universe'
+
+## Write permission to space `_cluster` is required to perform JOIN
+server.admin("box.schema.user.grant('guest', 'read', 'universe')")
+server.sql.py_con.close() # re-connect with new permissions
+rows = list(server.sql.py_con.join(replica_uuid))
+print len(rows) == 1 and rows[0].return_message.find('Write access') >= 0 and \
+    'ok' or 'not ok', '-', 'join without write permissions to _cluster'
+
+def check_join(msg):
+    ok = True
+    for resp in server.sql.py_con.join(replica_uuid):
+        if resp.completion_status != 0:
+            print 'not ok', '-', msg, resp.return_message
+            ok = False
+
+    server.sql.py_con.close() # JOIN brokes protocol
+    if not ok:
+        return
+    tuples = server.sql.py_con.space('_cluster').select(replica_uuid, index = 1)
+    if len(tuples) == 0:
+        print 'not ok', '-', msg, 'missing entry in _cluster'
+        return
+    server_id = tuples[0][0]
+    print 'ok', '-', msg
+    return server_id
+
+## JOIN with permissions
+server.admin("box.schema.user.grant('guest', 'write', 'space', '_cluster')")
+server.sql.py_con.close() # re-connect with new permissions
+server_id = check_join('join with granted permissions')
+server.sql.py_con.space('_cluster').delete(server_id)
+
+# JOIN with granted role
+server.admin("box.schema.user.revoke('guest', 'read', 'universe')")
+server.admin("box.schema.user.revoke('guest', 'write', 'space', '_cluster')")
+server.admin("box.schema.user.grant('guest', 'replication')")
+server.sql.py_con.close() # re-connect with new permissions
+server_id = check_join('join with granted role')
+server.sql.py_con.space('_cluster').delete(server_id)
+server.admin("box.schema.user.revoke('guest', 'replication')")
+server.admin('box.snapshot()')
+
 print '-------------------------------------------------------------'
 print 'gh-434: Assertion if replace _cluster tuple'
 print '-------------------------------------------------------------'
-- 
GitLab