[security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 05 Jul 2010 17:55:41 +0200
branchstable
changeset 5888 3ee80d487f11
parent 5887 3f55f0f10a22
child 5889 014ea69e5200
[security] fix read rql expression insertion: we should not insert rql expr on variables only referenced in neged relation
server/querier.py
server/test/unittest_security.py
--- a/server/querier.py	Mon Jul 05 17:55:37 2010 +0200
+++ b/server/querier.py	Mon Jul 05 17:55:41 2010 +0200
@@ -29,7 +29,7 @@
 from logilab.common.compat import any
 from rql import RQLSyntaxError
 from rql.stmts import Union, Select
-from rql.nodes import Relation, VariableRef, Constant, SubQuery
+from rql.nodes import Relation, VariableRef, Constant, SubQuery, Exists, Not
 
 from cubicweb import Unauthorized, QueryError, UnknownEid, typed_eid
 from cubicweb import server
@@ -112,7 +112,16 @@
                 ex = Unauthorized('read', solution[varname])
                 ex.var = varname
                 raise ex
-            localchecks[varname] = erqlexprs
+            # don't insert security on variable only referenced by 'NOT X relation Y' or
+            # 'NOT EXISTS(X relation Y)'
+            varinfo = rqlst.defined_vars[varname].stinfo
+            if varinfo['selected'] or (
+                len([r for r in varinfo['relations']
+                     if (not schema.rschema(r.r_type).final
+                         and ((isinstance(r.parent, Exists) and r.parent.neged(strict=True))
+                              or isinstance(r.parent, Not)))])
+                != len(varinfo['relations'])):
+                localchecks[varname] = erqlexprs
     return localchecks
 
 def add_noinvariant(noinvariant, restricted, select, nbtrees):
--- a/server/test/unittest_security.py	Mon Jul 05 17:55:37 2010 +0200
+++ b/server/test/unittest_security.py	Mon Jul 05 17:55:41 2010 +0200
@@ -66,6 +66,27 @@
                           cu.execute, 'Any X,P WHERE X is CWUser, X upassword P')
 
 
+class SecurityRewritingTC(BaseSecurityTC):
+    def hijack_source_execute(self):
+        def syntax_tree_search(*args, **kwargs):
+            self.query = (args, kwargs)
+            return []
+        self.repo.system_source.syntax_tree_search = syntax_tree_search
+
+    def tearDown(self):
+        self.repo.system_source.__dict__.pop('syntax_tree_search', None)
+        BaseSecurityTC.tearDown(self)
+
+    def test_not_relation_read_security(self):
+        cnx = self.login('iaminusersgrouponly')
+        self.hijack_source_execute()
+        self.execute('Any U WHERE NOT A todo_by U, A is Affaire')
+        self.assertEquals(self.query[0][1].as_string(),
+                          'Any U WHERE NOT EXISTS(A todo_by U), A is Affaire')
+        self.execute('Any U WHERE NOT EXISTS(A todo_by U), A is Affaire')
+        self.assertEquals(self.query[0][1].as_string(),
+                          'Any U WHERE NOT EXISTS(A todo_by U), A is Affaire')
+
 class SecurityTC(BaseSecurityTC):
 
     def setUp(self):