server/test/unittest_security.py
changeset 0 b97547f5f1fa
child 321 247947250382
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """functional tests for server'security
       
     2 """
       
     3 import sys
       
     4 
       
     5 from logilab.common.testlib import unittest_main, TestCase
       
     6 from cubicweb.devtools.apptest import RepositoryBasedTC
       
     7 
       
     8 from cubicweb import Unauthorized, ValidationError
       
     9 from cubicweb.server.querier import check_read_access
       
    10 
       
    11 class BaseSecurityTC(RepositoryBasedTC):
       
    12 
       
    13     def setUp(self):
       
    14         RepositoryBasedTC.setUp(self)
       
    15         self.create_user('iaminusersgrouponly')
       
    16         self.readoriggroups = self.schema['Personne'].get_groups('read')
       
    17         self.addoriggroups = self.schema['Personne'].get_groups('add')
       
    18         
       
    19     def tearDown(self):
       
    20         RepositoryBasedTC.tearDown(self)
       
    21         self.schema['Personne'].set_groups('read', self.readoriggroups)
       
    22         self.schema['Personne'].set_groups('add', self.addoriggroups)
       
    23 
       
    24         
       
    25 class LowLevelSecurityFunctionTC(BaseSecurityTC):
       
    26     
       
    27     def test_check_read_access(self):
       
    28         rql = u'Personne U where U nom "managers"'
       
    29         rqlst = self.repo.querier._rqlhelper.parse(rql).children[0]
       
    30         origgroups = self.schema['Personne'].get_groups('read')
       
    31         self.schema['Personne'].set_groups('read', ('users', 'managers'))
       
    32         self.repo.querier._rqlhelper.compute_solutions(rqlst)
       
    33         solution = rqlst.solutions[0]
       
    34         check_read_access(self.schema, self.session.user, rqlst, solution)
       
    35         cnx = self.login('anon')
       
    36         cu = cnx.cursor()
       
    37         self.assertRaises(Unauthorized,
       
    38                           check_read_access,
       
    39                           self.schema, cnx.user(self.current_session()), rqlst, solution)
       
    40         self.assertRaises(Unauthorized, cu.execute, rql)
       
    41             
       
    42     def test_upassword_not_selectable(self):
       
    43         self.assertRaises(Unauthorized,
       
    44                           self.execute, 'Any X,P WHERE X is EUser, X upassword P')
       
    45         self.rollback()
       
    46         cnx = self.login('iaminusersgrouponly')
       
    47         cu = cnx.cursor()
       
    48         self.assertRaises(Unauthorized,
       
    49                           cu.execute, 'Any X,P WHERE X is EUser, X upassword P')
       
    50         
       
    51     
       
    52 class SecurityTC(BaseSecurityTC):
       
    53     
       
    54     def setUp(self):
       
    55         BaseSecurityTC.setUp(self)
       
    56         # implicitly test manager can add some entities
       
    57         self.execute("INSERT Affaire X: X sujet 'cool'")
       
    58         self.execute("INSERT Societe X: X nom 'logilab'")
       
    59         self.execute("INSERT Personne X: X nom 'bidule'")
       
    60         self.execute('INSERT EGroup X: X name "staff"')
       
    61         self.commit()
       
    62 
       
    63     def test_insert_security(self):
       
    64         cnx = self.login('anon')
       
    65         cu = cnx.cursor()
       
    66         cu.execute("INSERT Personne X: X nom 'bidule'")
       
    67         self.assertRaises(Unauthorized, cnx.commit)
       
    68         self.assertEquals(cu.execute('Personne X').rowcount, 1)
       
    69         
       
    70     def test_insert_rql_permission(self):
       
    71         # test user can only add une affaire related to a societe he owns
       
    72         cnx = self.login('iaminusersgrouponly')
       
    73         cu = cnx.cursor()
       
    74         cu.execute("INSERT Affaire X: X sujet 'cool'")
       
    75         self.assertRaises(Unauthorized, cnx.commit)
       
    76         # test nothing has actually been inserted
       
    77         self.restore_connection()
       
    78         self.assertEquals(self.execute('Affaire X').rowcount, 1)
       
    79         cnx = self.login('iaminusersgrouponly')
       
    80         cu = cnx.cursor()
       
    81         cu.execute("INSERT Affaire X: X sujet 'cool'")
       
    82         cu.execute("INSERT Societe X: X nom 'chouette'")
       
    83         cu.execute("SET A concerne S WHERE A sujet 'cool', S nom 'chouette'")
       
    84         cnx.commit()
       
    85         
       
    86     def test_update_security_1(self):
       
    87         cnx = self.login('anon')
       
    88         cu = cnx.cursor()
       
    89         # local security check
       
    90         cu.execute( "SET X nom 'bidulechouette' WHERE X is Personne")
       
    91         self.assertRaises(Unauthorized, cnx.commit)
       
    92         self.restore_connection()
       
    93         self.assertEquals(self.execute('Personne X WHERE X nom "bidulechouette"').rowcount, 0)
       
    94         
       
    95     def test_update_security_2(self):
       
    96         cnx = self.login('anon')
       
    97         cu = cnx.cursor()
       
    98         self.repo.schema['Personne'].set_groups('read', ('users', 'managers'))
       
    99         self.repo.schema['Personne'].set_groups('add', ('guests', 'users', 'managers'))
       
   100         self.assertRaises(Unauthorized, cu.execute, "SET X nom 'bidulechouette' WHERE X is Personne")
       
   101         #self.assertRaises(Unauthorized, cnx.commit)
       
   102         # test nothing has actually been inserted
       
   103         self.restore_connection()
       
   104         self.assertEquals(self.execute('Personne X WHERE X nom "bidulechouette"').rowcount, 0)
       
   105 
       
   106     def test_update_security_3(self):
       
   107         cnx = self.login('iaminusersgrouponly')
       
   108         cu = cnx.cursor()
       
   109         cu.execute("INSERT Personne X: X nom 'biduuule'")
       
   110         cu.execute("INSERT Societe X: X nom 'looogilab'")
       
   111         cu.execute("SET X travaille S WHERE X nom 'biduuule', S nom 'looogilab'")
       
   112         
       
   113     def test_update_rql_permission(self):
       
   114         self.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   115         self.commit()
       
   116         # test user can only update une affaire related to a societe he owns
       
   117         cnx = self.login('iaminusersgrouponly')
       
   118         cu = cnx.cursor()
       
   119         cu.execute("SET X sujet 'pascool' WHERE X is Affaire")
       
   120         # this won't actually do anything since the selection query won't return anything
       
   121         cnx.commit()
       
   122         # to actually get Unauthorized exception, try to update an entity we can read
       
   123         cu.execute("SET X nom 'toto' WHERE X is Societe")
       
   124         self.assertRaises(Unauthorized, cnx.commit)        
       
   125         cu.execute("INSERT Affaire X: X sujet 'pascool'")
       
   126         cu.execute("INSERT Societe X: X nom 'chouette'")
       
   127         cu.execute("SET A concerne S WHERE A sujet 'pascool', S nom 'chouette'")
       
   128         cu.execute("SET X sujet 'habahsicestcool' WHERE X sujet 'pascool'")
       
   129         cnx.commit()
       
   130     
       
   131     def test_delete_security(self):
       
   132         # FIXME: sample below fails because we don't detect "owner" can't delete
       
   133         # user anyway, and since no user with login == 'bidule' exists, no
       
   134         # exception is raised
       
   135         #user._groups = {'guests':1}
       
   136         #self.assertRaises(Unauthorized,
       
   137         #                  self.o.execute, user, "DELETE EUser X WHERE X login 'bidule'")
       
   138         # check local security
       
   139         cnx = self.login('iaminusersgrouponly')
       
   140         cu = cnx.cursor()
       
   141         self.assertRaises(Unauthorized, cu.execute, "DELETE EGroup Y WHERE Y name 'staff'")
       
   142         
       
   143     def test_delete_rql_permission(self):
       
   144         self.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   145         self.commit()
       
   146         # test user can only dele une affaire related to a societe he owns
       
   147         cnx = self.login('iaminusersgrouponly')
       
   148         cu = cnx.cursor()
       
   149         # this won't actually do anything since the selection query won't return anything        
       
   150         cu.execute("DELETE Affaire X")
       
   151         cnx.commit()
       
   152         # to actually get Unauthorized exception, try to delete an entity we can read
       
   153         self.assertRaises(Unauthorized, cu.execute, "DELETE Societe S")
       
   154         cu.execute("INSERT Affaire X: X sujet 'pascool'")
       
   155         cu.execute("INSERT Societe X: X nom 'chouette'")
       
   156         cu.execute("SET A concerne S WHERE A sujet 'pascool', S nom 'chouette'")
       
   157         cnx.commit()
       
   158 ##         # this one should fail since it will try to delete two affaires, one authorized
       
   159 ##         # and the other not
       
   160 ##         self.assertRaises(Unauthorized, cu.execute, "DELETE Affaire X")
       
   161         cu.execute("DELETE Affaire X WHERE X sujet 'pascool'")
       
   162         cnx.commit()
       
   163 
       
   164 
       
   165     def test_insert_relation_rql_permission(self):
       
   166         cnx = self.login('iaminusersgrouponly')
       
   167         session = self.current_session()
       
   168         cu = cnx.cursor(session)
       
   169         cu.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   170         # should raise Unauthorized since user don't own S
       
   171         # though this won't actually do anything since the selection query won't return anything
       
   172         cnx.commit()
       
   173         # to actually get Unauthorized exception, try to insert a relation were we can read both entities
       
   174         rset = cu.execute('Personne P')
       
   175         self.assertEquals(len(rset), 1)
       
   176         ent = rset.get_entity(0, 0)
       
   177         session.set_pool() # necessary
       
   178         self.assertRaises(Unauthorized,
       
   179                           ent.e_schema.check_perm, session, 'update', ent.eid)
       
   180         self.assertRaises(Unauthorized,
       
   181                           cu.execute, "SET P travaille S WHERE P is Personne, S is Societe")
       
   182         # test nothing has actually been inserted:
       
   183         self.assertEquals(cu.execute('Any P,S WHERE P travaille S,P is Personne, S is Societe').rowcount, 0)
       
   184         cu.execute("INSERT Societe X: X nom 'chouette'")
       
   185         cu.execute("SET A concerne S WHERE A is Affaire, S nom 'chouette'")
       
   186         cnx.commit()
       
   187 
       
   188     def test_delete_relation_rql_permission(self):
       
   189         self.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   190         self.commit()
       
   191         cnx = self.login('iaminusersgrouponly')
       
   192         cu = cnx.cursor()
       
   193         # this won't actually do anything since the selection query won't return anything
       
   194         cu.execute("DELETE A concerne S")
       
   195         cnx.commit()
       
   196         # to actually get Unauthorized exception, try to delete a relation we can read
       
   197         self.restore_connection()
       
   198         eid = self.execute("INSERT Affaire X: X sujet 'pascool'")[0][0]
       
   199         self.execute('SET X owned_by U WHERE X eid %(x)s, U login "iaminusersgrouponly"', {'x': eid}, 'x')
       
   200         self.execute("SET A concerne S WHERE A sujet 'pascool', S is Societe")
       
   201         self.commit()
       
   202         cnx = self.login('iaminusersgrouponly')
       
   203         cu = cnx.cursor()
       
   204         self.assertRaises(Unauthorized, cu.execute, "DELETE A concerne S")
       
   205         cu.execute("INSERT Societe X: X nom 'chouette'")
       
   206         cu.execute("SET A concerne S WHERE A is Affaire, S nom 'chouette'")
       
   207         cnx.commit()
       
   208         cu.execute("DELETE A concerne S WHERE S nom 'chouette'")
       
   209 
       
   210 
       
   211     def test_user_can_change_its_upassword(self):
       
   212         ueid = self.create_user('user')
       
   213         cnx = self.login('user')
       
   214         cu = cnx.cursor()
       
   215         cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
       
   216                    {'x': ueid, 'passwd': 'newpwd'}, 'x')
       
   217         cnx.commit()
       
   218         cnx.close()
       
   219         cnx = self.login('user', 'newpwd')
       
   220 
       
   221     def test_user_cant_change_other_upassword(self):
       
   222         ueid = self.create_user('otheruser')
       
   223         cnx = self.login('iaminusersgrouponly')
       
   224         cu = cnx.cursor()
       
   225         cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
       
   226                    {'x': ueid, 'passwd': 'newpwd'}, 'x')
       
   227         self.assertRaises(Unauthorized, cnx.commit)
       
   228 
       
   229     # read security test
       
   230     
       
   231     def test_read_base(self):
       
   232         self.schema['Personne'].set_groups('read', ('users', 'managers'))
       
   233         cnx = self.login('anon')
       
   234         cu = cnx.cursor()
       
   235         self.assertRaises(Unauthorized,
       
   236                           cu.execute, 'Personne U where U nom "managers"')
       
   237 
       
   238     def test_read_erqlexpr(self):
       
   239         eid = self.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
       
   240         self.commit()
       
   241         cnx = self.login('iaminusersgrouponly')
       
   242         cu = cnx.cursor()
       
   243         rset = cu.execute('Affaire X')
       
   244         self.assertEquals(rset.rows, [])
       
   245         self.assertRaises(Unauthorized, cu.execute, 'Any X WHERE X eid %(x)s', {'x': eid}, 'x')
       
   246         #  cache test
       
   247         self.assertRaises(Unauthorized, cu.execute, 'Any X WHERE X eid %(x)s', {'x': eid}, 'x')
       
   248         aff2 = cu.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
       
   249         soc1 = cu.execute("INSERT Societe X: X nom 'chouette'")[0][0]
       
   250         cu.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   251         cnx.commit()
       
   252         rset = cu.execute('Any X WHERE X eid %(x)s', {'x': aff2}, 'x')
       
   253         self.assertEquals(rset.rows, [[aff2]])
       
   254         
       
   255     def test_read_erqlexpr_has_text1(self):
       
   256         aff1 = self.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
       
   257         card1 = self.execute("INSERT Card X: X title 'cool'")[0][0]
       
   258         self.execute('SET X owned_by U WHERE X eid %(x)s, U login "iaminusersgrouponly"', {'x': card1}, 'x')
       
   259         self.commit()
       
   260         cnx = self.login('iaminusersgrouponly')
       
   261         cu = cnx.cursor()
       
   262         aff2 = cu.execute("INSERT Affaire X: X sujet 'cool', X in_state S WHERE S name 'pitetre'")[0][0]
       
   263         soc1 = cu.execute("INSERT Societe X: X nom 'chouette'")[0][0]
       
   264         cu.execute("SET A concerne S WHERE A eid %(a)s, S eid %(s)s", {'a': aff2, 's': soc1},
       
   265                    ('a', 's'))
       
   266         cnx.commit()
       
   267         self.assertRaises(Unauthorized, cu.execute, 'Any X WHERE X eid %(x)s', {'x':aff1}, 'x')
       
   268         self.failUnless(cu.execute('Any X WHERE X eid %(x)s', {'x':aff2}, 'x'))
       
   269         self.failUnless(cu.execute('Any X WHERE X eid %(x)s', {'x':card1}, 'x'))
       
   270         rset = cu.execute("Any X WHERE X has_text 'cool'")
       
   271         self.assertEquals(sorted(eid for eid, in rset.rows),
       
   272                           [card1, aff2])
       
   273 
       
   274     def test_read_erqlexpr_has_text2(self):
       
   275         self.execute("INSERT Personne X: X nom 'bidule'")
       
   276         self.execute("INSERT Societe X: X nom 'bidule'")
       
   277         self.commit()
       
   278         self.schema['Personne'].set_groups('read', ('managers',))
       
   279         cnx = self.login('iaminusersgrouponly')
       
   280         cu = cnx.cursor()
       
   281         rset = cu.execute('Any N WHERE N has_text "bidule"')
       
   282         self.assertEquals(len(rset.rows), 1, rset.rows)
       
   283         rset = cu.execute('Any N WITH N BEING (Any N WHERE N has_text "bidule")')
       
   284         self.assertEquals(len(rset.rows), 1, rset.rows)        
       
   285 
       
   286     def test_read_erqlexpr_optional_rel(self):
       
   287         self.execute("INSERT Personne X: X nom 'bidule'")
       
   288         self.execute("INSERT Societe X: X nom 'bidule'")
       
   289         self.commit()
       
   290         self.schema['Personne'].set_groups('read', ('managers',))
       
   291         cnx = self.login('anon')
       
   292         cu = cnx.cursor()
       
   293         rset = cu.execute('Any N,U WHERE N has_text "bidule", N owned_by U?')
       
   294         self.assertEquals(len(rset.rows), 1, rset.rows)
       
   295 
       
   296     def test_read_erqlexpr_aggregat(self):
       
   297         self.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
       
   298         self.commit()
       
   299         cnx = self.login('iaminusersgrouponly')
       
   300         cu = cnx.cursor()
       
   301         rset = cu.execute('Any COUNT(X) WHERE X is Affaire')
       
   302         self.assertEquals(rset.rows, [[0]])        
       
   303         cu = cnx.cursor()
       
   304         aff2 = cu.execute("INSERT Affaire X: X sujet 'cool'")[0][0]
       
   305         soc1 = cu.execute("INSERT Societe X: X nom 'chouette'")[0][0]
       
   306         cu.execute("SET A concerne S WHERE A is Affaire, S is Societe")
       
   307         cnx.commit()
       
   308         rset = cu.execute('Any COUNT(X) WHERE X is Affaire')
       
   309         self.assertEquals(rset.rows, [[1]])
       
   310         rset = cu.execute('Any ETN, COUNT(X) GROUPBY ETN WHERE X is ET, ET name ETN')
       
   311         values = dict(rset)
       
   312         self.assertEquals(values['Affaire'], 1)
       
   313         self.assertEquals(values['Societe'], 2)
       
   314         rset = cu.execute('Any ETN, COUNT(X) GROUPBY ETN WHERE X is ET, ET name ETN WITH X BEING ((Affaire X) UNION (Societe X))')
       
   315         self.assertEquals(len(rset), 2)
       
   316         values = dict(rset)
       
   317         self.assertEquals(values['Affaire'], 1)
       
   318         self.assertEquals(values['Societe'], 2)
       
   319         
       
   320 
       
   321     def test_attribute_security(self):
       
   322         # only managers should be able to edit the 'test' attribute of Personne entities
       
   323         eid = self.execute("INSERT Personne X: X nom 'bidule', X web 'http://www.debian.org', X test TRUE")[0][0]
       
   324         self.commit()
       
   325         self.execute('SET X test FALSE WHERE X eid %(x)s', {'x': eid}, 'x')
       
   326         self.commit()
       
   327         cnx = self.login('iaminusersgrouponly')
       
   328         cu = cnx.cursor()
       
   329         cu.execute("INSERT Personne X: X nom 'bidule', X web 'http://www.debian.org', X test TRUE")
       
   330         self.assertRaises(Unauthorized, cnx.commit)
       
   331         cu.execute("INSERT Personne X: X nom 'bidule', X web 'http://www.debian.org', X test FALSE")
       
   332         self.assertRaises(Unauthorized, cnx.commit)
       
   333         eid = cu.execute("INSERT Personne X: X nom 'bidule', X web 'http://www.debian.org'")[0][0]
       
   334         cnx.commit()
       
   335         cu.execute('SET X test FALSE WHERE X eid %(x)s', {'x': eid}, 'x')
       
   336         self.assertRaises(Unauthorized, cnx.commit)
       
   337         cu.execute('SET X test TRUE WHERE X eid %(x)s', {'x': eid}, 'x')
       
   338         self.assertRaises(Unauthorized, cnx.commit)
       
   339         cu.execute('SET X web "http://www.logilab.org" WHERE X eid %(x)s', {'x': eid}, 'x')
       
   340         cnx.commit()
       
   341         cnx.close()
       
   342         
       
   343     def test_attribute_security_rqlexpr(self):
       
   344         # Note.para attribute editable by managers or if the note is in "todo" state
       
   345         eid = self.execute("INSERT Note X: X para 'bidule', X in_state S WHERE S name 'done'")[0][0]
       
   346         self.commit()
       
   347         self.execute('SET X para "truc" WHERE X eid %(x)s', {'x': eid}, 'x')
       
   348         self.commit()
       
   349         cnx = self.login('iaminusersgrouponly')
       
   350         cu = cnx.cursor()
       
   351         cu.execute("SET X para 'chouette' WHERE X eid %(x)s", {'x': eid}, 'x')
       
   352         self.assertRaises(Unauthorized, cnx.commit)
       
   353         eid2 = cu.execute("INSERT Note X: X para 'bidule'")[0][0]
       
   354         cnx.commit()
       
   355         cu.execute("SET X in_state S WHERE X eid %(x)s, S name 'done'", {'x': eid2}, 'x')
       
   356         cnx.commit()
       
   357         self.assertEquals(len(cu.execute('Any X WHERE X in_state S, S name "todo", X eid %(x)s', {'x': eid2}, 'x')),
       
   358                           0)
       
   359         cu.execute("SET X para 'chouette' WHERE X eid %(x)s", {'x': eid2}, 'x')
       
   360         self.assertRaises(Unauthorized, cnx.commit)
       
   361         cu.execute("SET X in_state S WHERE X eid %(x)s, S name 'todo'", {'x': eid2}, 'x')
       
   362         cnx.commit()
       
   363         cu.execute("SET X para 'chouette' WHERE X eid %(x)s", {'x': eid2}, 'x')
       
   364         cnx.commit()
       
   365 
       
   366     def test_attribute_read_security(self):
       
   367         # anon not allowed to see users'login, but they can see users
       
   368         self.repo.schema['EUser'].set_groups('read', ('guests', 'users', 'managers'))
       
   369         self.repo.schema['login'].set_groups('read', ('users', 'managers'))
       
   370         cnx = self.login('anon')
       
   371         cu = cnx.cursor()
       
   372         rset = cu.execute('EUser X')
       
   373         self.failUnless(rset)
       
   374         x = rset.get_entity(0, 0)
       
   375         self.assertEquals(x.login, None)
       
   376         self.failUnless(x.creation_date)
       
   377         x = rset.get_entity(1, 0)
       
   378         x.complete()
       
   379         self.assertEquals(x.login, None)
       
   380         self.failUnless(x.creation_date)
       
   381         cnx.rollback()
       
   382 
       
   383         
       
   384 class BaseSchemaSecurityTC(BaseSecurityTC):
       
   385     """tests related to the base schema permission configuration"""
       
   386         
       
   387     def test_user_can_delete_object_he_created(self):
       
   388         # even if some other user have changed object'state
       
   389         cnx = self.login('iaminusersgrouponly')
       
   390         cu = cnx.cursor()
       
   391         # due to security test, affaire has to concerne a societe the user owns
       
   392         cu.execute('INSERT Societe X: X nom "ARCTIA"')
       
   393         cu.execute('INSERT Affaire X: X ref "ARCT01", X concerne S WHERE S nom "ARCTIA"')
       
   394         cnx.commit()
       
   395         self.restore_connection()
       
   396         self.execute('SET X in_state S WHERE X ref "ARCT01", S name "ben non"')
       
   397         self.commit()
       
   398         self.assertEquals(len(self.execute('TrInfo X WHERE X wf_info_for A, A ref "ARCT01"')),
       
   399                           2) 
       
   400         self.assertEquals(len(self.execute('TrInfo X WHERE X wf_info_for A, A ref "ARCT01",'
       
   401                                            'X owned_by U, U login "admin"')),
       
   402                           1) # TrInfo at the above state change
       
   403         self.assertEquals(len(self.execute('TrInfo X WHERE X wf_info_for A, A ref "ARCT01",'
       
   404                                            'X owned_by U, U login "iaminusersgrouponly"')),
       
   405                           1) # TrInfo created at creation time
       
   406         cnx = self.login('iaminusersgrouponly')
       
   407         cu = cnx.cursor()
       
   408         cu.execute('DELETE Affaire X WHERE X ref "ARCT01"')
       
   409         cnx.commit()
       
   410         self.failIf(cu.execute('Affaire X'))
       
   411 
       
   412     def test_users_and_groups_non_readable_by_guests(self):
       
   413         cnx = self.login('anon')
       
   414         anon = cnx.user(self.current_session())
       
   415         cu = cnx.cursor()
       
   416         # anonymous user can only read itself
       
   417         rset = cu.execute('Any L WHERE X owned_by U, U login L')
       
   418         self.assertEquals(rset.rows, [['anon']])
       
   419         rset = cu.execute('EUser X')
       
   420         self.assertEquals(rset.rows, [[anon.eid]])
       
   421         # anonymous user can read groups (necessary to check allowed transitions for instance)
       
   422         self.assert_(cu.execute('EGroup X'))
       
   423         # should only be able to read the anonymous user, not another one
       
   424         origuser = self.session.user
       
   425         self.assertRaises(Unauthorized, 
       
   426                           cu.execute, 'EUser X WHERE X eid %(x)s', {'x': origuser.eid}, 'x')
       
   427         # nothing selected, nothing updated, no exception raised
       
   428         #self.assertRaises(Unauthorized,
       
   429         #                  cu.execute, 'SET X login "toto" WHERE X eid %(x)s',
       
   430         #                  {'x': self.user.eid})
       
   431         
       
   432         rset = cu.execute('EUser X WHERE X eid %(x)s', {'x': anon.eid}, 'x')
       
   433         self.assertEquals(rset.rows, [[anon.eid]])
       
   434         # but can't modify it
       
   435         cu.execute('SET X login "toto" WHERE X eid %(x)s', {'x': anon.eid})
       
   436         self.assertRaises(Unauthorized, cnx.commit)
       
   437     
       
   438     def test_in_group_relation(self):
       
   439         cnx = self.login('iaminusersgrouponly')
       
   440         cu = cnx.cursor()
       
   441         rql = u"DELETE U in_group G WHERE U login 'admin'"
       
   442         self.assertRaises(Unauthorized, cu.execute, rql)
       
   443         rql = u"SET U in_group G WHERE U login 'admin', G name 'users'"
       
   444         self.assertRaises(Unauthorized, cu.execute, rql)
       
   445 
       
   446     def test_owned_by(self):
       
   447         self.execute("INSERT Personne X: X nom 'bidule'")
       
   448         self.commit()
       
   449         cnx = self.login('iaminusersgrouponly')
       
   450         cu = cnx.cursor()
       
   451         rql = u"SET X owned_by U WHERE U login 'iaminusersgrouponly', X is Personne"
       
   452         self.assertRaises(Unauthorized, cu.execute, rql)
       
   453         
       
   454     def test_bookmarked_by_guests_security(self):
       
   455         beid1 = self.execute('INSERT Bookmark B: B path "?vid=manage", B title "manage"')[0][0]
       
   456         beid2 = self.execute('INSERT Bookmark B: B path "?vid=index", B title "index", B bookmarked_by U WHERE U login "anon"')[0][0]
       
   457         self.commit()
       
   458         cnx = self.login('anon')
       
   459         cu = cnx.cursor()
       
   460         anoneid = self.current_session().user.eid
       
   461         self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,'
       
   462                                      'B bookmarked_by U, U eid %s' % anoneid).rows,
       
   463                           [['index', '?vid=index']])
       
   464         self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,'
       
   465                                      'B bookmarked_by U, U eid %(x)s', {'x': anoneid}).rows,
       
   466                           [['index', '?vid=index']])
       
   467         # can read others bookmarks as well
       
   468         self.assertEquals(cu.execute('Any B where B is Bookmark, NOT B bookmarked_by U').rows,
       
   469                           [[beid1]])
       
   470         self.assertRaises(Unauthorized, cu.execute,'DELETE B bookmarked_by U')
       
   471         self.assertRaises(Unauthorized,
       
   472                           cu.execute, 'SET B bookmarked_by U WHERE U eid %(x)s, B eid %(b)s',
       
   473                           {'x': anoneid, 'b': beid1}, 'x')
       
   474         
       
   475 
       
   476     def test_ambigous_ordered(self):
       
   477         cnx = self.login('anon')
       
   478         cu = cnx.cursor()
       
   479         names = [t for t, in cu.execute('Any N ORDERBY lower(N) WHERE X name N')]
       
   480         self.assertEquals(names, sorted(names, key=lambda x: x.lower()))
       
   481 
       
   482     def test_in_state_without_update_perm(self):
       
   483         """check a user change in_state without having update permission on the
       
   484         subject
       
   485         """
       
   486         eid = self.execute('INSERT Affaire X: X ref "ARCT01"')[0][0]
       
   487         self.commit()
       
   488         cnx = self.login('iaminusersgrouponly')
       
   489         session = self.current_session()
       
   490         # needed to avoid check_perm error
       
   491         session.set_pool()
       
   492         # needed to remove rql expr granting update perm to the user
       
   493         self.schema['Affaire'].set_rqlexprs('update', ()) 
       
   494         self.assertRaises(Unauthorized,
       
   495                           self.schema['Affaire'].check_perm, session, 'update', eid)
       
   496         cu = cnx.cursor()
       
   497         cu.execute('SET X in_state S WHERE X ref "ARCT01", S name "abort"')
       
   498         cnx.commit()
       
   499         # though changing a user state (even logged user) is reserved to managers
       
   500         rql = u"SET X in_state S WHERE X eid %(x)s, S name 'deactivated'"
       
   501         # XXX wether it should raise Unauthorized or ValidationError is not clear
       
   502         # the best would probably ValidationError if the transition doesn't exist
       
   503         # from the current state but Unauthorized if it exists but user can't pass it
       
   504         self.assertRaises(ValidationError, cu.execute, rql, {'x': cnx.user(self.current_session()).eid}, 'x')
       
   505         
       
   506 if __name__ == '__main__':
       
   507     unittest_main()