[repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 27 Apr 2010 18:27:43 +0200
branchstable
changeset 5419 0b7805928a27
parent 5418 4f0047cfecb5
child 5420 09b50d7e5321
[repo security] deal with rewriten constant nodes in check_read_access, necessary when repo is used as an external source
server/querier.py
server/test/unittest_security.py
--- a/server/querier.py	Tue Apr 27 14:25:38 2010 +0200
+++ b/server/querier.py	Tue Apr 27 18:27:43 2010 +0200
@@ -48,7 +48,16 @@
         if 'Password' in solution.itervalues():
             raise Unauthorized('Password selection is not allowed')
 
-def check_read_access(schema, user, rqlst, solution):
+def term_etype(session, term, solution, args):
+    """return the entity type for the given term (a VariableRef or a Constant
+    node)
+    """
+    try:
+        return solution[term.name]
+    except AttributeError:
+        return session.describe(term.eval(args))[0]
+
+def check_read_access(session, rqlst, solution, args):
     """check that the given user has credentials to access data read the
     query
 
@@ -56,6 +65,10 @@
     in the schema), keys are variable names and values associated rql expression
     for the associated variable with the given solution
     """
+    # use `term_etype` since we've to deal with rewritten constants here,
+    # when used as an external source by another repository.
+    # XXX what about local read security w/ those rewritten constants...
+    schema = session.repo.schema
     if rqlst.where is not None:
         for rel in rqlst.where.iget_nodes(Relation):
             # XXX has_text may have specific perm ?
@@ -63,12 +76,15 @@
                 continue
             rschema = schema.rschema(rel.r_type)
             if rschema.final:
-                eschema = schema.eschema(solution[rel.children[0].name])
+                eschema = schema.eschema(term_etype(session, rel.children[0],
+                                                    solution, args))
                 rdef = eschema.rdef(rschema)
             else:
-                rdef = rschema.rdef(solution[rel.children[0].name],
-                                    solution[rel.children[1].children[0].name])
-            if not user.matching_groups(rdef.get_groups('read')):
+                rdef = rschema.rdef(term_etype(session, rel.children[0],
+                                               solution, args),
+                                    term_etype(session, rel.children[1].children[0],
+                                               solution, args))
+            if not session.user.matching_groups(rdef.get_groups('read')):
                 # XXX rqlexpr not allowed
                 raise Unauthorized('read', rel.r_type)
     localchecks = {}
@@ -77,7 +93,7 @@
         eschema = schema.eschema(solution[varname])
         if eschema.final:
             continue
-        if not user.matching_groups(eschema.get_groups('read')):
+        if not session.user.matching_groups(eschema.get_groups('read')):
             erqlexprs = eschema.get_rqlexprs('read')
             if not erqlexprs:
                 ex = Unauthorized('read', solution[varname])
@@ -319,8 +335,6 @@
         note: rqlst should not have been simplified at this point
         """
         session = self.session
-        user = session.user
-        schema = self.schema
         msgs = []
         neweids = session.transaction_data.get('neweids', ())
         varkwargs = {}
@@ -342,10 +356,10 @@
         newsolutions = []
         for solution in rqlst.solutions:
             try:
-                localcheck = check_read_access(schema, user, rqlst, solution)
+                localcheck = check_read_access(session, rqlst, solution, self.args)
             except Unauthorized, ex:
                 msg = 'remove %s from solutions since %s has no %s access to %s'
-                msg %= (solution, user.login, ex.args[0], ex.args[1])
+                msg %= (solution, session.user.login, ex.args[0], ex.args[1])
                 msgs.append(msg)
                 LOGGER.info(msg)
             else:
--- a/server/test/unittest_security.py	Tue Apr 27 14:25:38 2010 +0200
+++ b/server/test/unittest_security.py	Tue Apr 27 18:27:43 2010 +0200
@@ -32,12 +32,12 @@
         self.schema['Personne'].set_action_permissions('read', ('users', 'managers'))
         self.repo.vreg.solutions(self.session, rqlst, None)
         solution = rqlst.solutions[0]
-        check_read_access(self.schema, self.session.user, rqlst, solution)
+        check_read_access(self.session, rqlst, solution, {})
         cnx = self.login('anon')
         cu = cnx.cursor()
         self.assertRaises(Unauthorized,
                           check_read_access,
-                          self.schema, cnx.user(self.session), rqlst, solution)
+                          self.session, rqlst, solution, {})
         self.assertRaises(Unauthorized, cu.execute, rql)
 
     def test_upassword_not_selectable(self):