2 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
2 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
3 """ |
3 """ |
4 import sys |
4 import sys |
5 |
5 |
6 from logilab.common.testlib import unittest_main, TestCase |
6 from logilab.common.testlib import unittest_main, TestCase |
7 from cubicweb.devtools.apptest import RepositoryBasedTC |
7 from cubicweb.devtools.testlib import CubicWebTC |
8 |
8 |
9 from cubicweb import Unauthorized, ValidationError |
9 from cubicweb import Unauthorized, ValidationError |
10 from cubicweb.server.querier import check_read_access |
10 from cubicweb.server.querier import check_read_access |
11 |
11 |
12 class BaseSecurityTC(RepositoryBasedTC): |
12 class BaseSecurityTC(CubicWebTC): |
13 |
13 |
14 def setUp(self): |
14 def setUp(self): |
15 RepositoryBasedTC.setUp(self) |
15 CubicWebTC.setUp(self) |
16 self.create_user('iaminusersgrouponly') |
16 self.create_user('iaminusersgrouponly') |
17 self.readoriggroups = self.schema['Personne'].get_groups('read') |
17 self.readoriggroups = self.schema['Personne'].get_groups('read') |
18 self.addoriggroups = self.schema['Personne'].get_groups('add') |
18 self.addoriggroups = self.schema['Personne'].get_groups('add') |
19 |
19 |
20 def tearDown(self): |
20 def tearDown(self): |
21 RepositoryBasedTC.tearDown(self) |
21 CubicWebTC.tearDown(self) |
22 self.schema['Personne'].set_groups('read', self.readoriggroups) |
22 self.schema['Personne'].set_groups('read', self.readoriggroups) |
23 self.schema['Personne'].set_groups('add', self.addoriggroups) |
23 self.schema['Personne'].set_groups('add', self.addoriggroups) |
24 |
24 |
25 |
25 |
26 class LowLevelSecurityFunctionTC(BaseSecurityTC): |
26 class LowLevelSecurityFunctionTC(BaseSecurityTC): |
35 check_read_access(self.schema, self.session.user, rqlst, solution) |
35 check_read_access(self.schema, self.session.user, rqlst, solution) |
36 cnx = self.login('anon') |
36 cnx = self.login('anon') |
37 cu = cnx.cursor() |
37 cu = cnx.cursor() |
38 self.assertRaises(Unauthorized, |
38 self.assertRaises(Unauthorized, |
39 check_read_access, |
39 check_read_access, |
40 self.schema, cnx.user(self.current_session()), rqlst, solution) |
40 self.schema, cnx.user(self.session), rqlst, solution) |
41 self.assertRaises(Unauthorized, cu.execute, rql) |
41 self.assertRaises(Unauthorized, cu.execute, rql) |
42 |
42 |
43 def test_upassword_not_selectable(self): |
43 def test_upassword_not_selectable(self): |
44 self.assertRaises(Unauthorized, |
44 self.assertRaises(Unauthorized, |
45 self.execute, 'Any X,P WHERE X is CWUser, X upassword P') |
45 self.execute, 'Any X,P WHERE X is CWUser, X upassword P') |
163 cnx.commit() |
163 cnx.commit() |
164 |
164 |
165 |
165 |
166 def test_insert_relation_rql_permission(self): |
166 def test_insert_relation_rql_permission(self): |
167 cnx = self.login('iaminusersgrouponly') |
167 cnx = self.login('iaminusersgrouponly') |
168 session = self.current_session() |
168 session = self.session |
169 cu = cnx.cursor(session) |
169 cu = cnx.cursor(session) |
170 cu.execute("SET A concerne S WHERE A is Affaire, S is Societe") |
170 cu.execute("SET A concerne S WHERE A is Affaire, S is Societe") |
171 # should raise Unauthorized since user don't own S |
171 # should raise Unauthorized since user don't own S |
172 # though this won't actually do anything since the selection query won't return anything |
172 # though this won't actually do anything since the selection query won't return anything |
173 cnx.commit() |
173 cnx.commit() |
208 cnx.commit() |
208 cnx.commit() |
209 cu.execute("DELETE A concerne S WHERE S nom 'chouette'") |
209 cu.execute("DELETE A concerne S WHERE S nom 'chouette'") |
210 |
210 |
211 |
211 |
212 def test_user_can_change_its_upassword(self): |
212 def test_user_can_change_its_upassword(self): |
213 ueid = self.create_user('user') |
213 ueid = self.create_user('user').eid |
214 cnx = self.login('user') |
214 cnx = self.login('user') |
215 cu = cnx.cursor() |
215 cu = cnx.cursor() |
216 cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s', |
216 cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s', |
217 {'x': ueid, 'passwd': 'newpwd'}, 'x') |
217 {'x': ueid, 'passwd': 'newpwd'}, 'x') |
218 cnx.commit() |
218 cnx.commit() |
219 cnx.close() |
219 cnx.close() |
220 cnx = self.login('user', 'newpwd') |
220 cnx = self.login('user', 'newpwd') |
221 |
221 |
222 def test_user_cant_change_other_upassword(self): |
222 def test_user_cant_change_other_upassword(self): |
223 ueid = self.create_user('otheruser') |
223 ueid = self.create_user('otheruser').eid |
224 cnx = self.login('iaminusersgrouponly') |
224 cnx = self.login('iaminusersgrouponly') |
225 cu = cnx.cursor() |
225 cu = cnx.cursor() |
226 cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s', |
226 cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s', |
227 {'x': ueid, 'passwd': 'newpwd'}, 'x') |
227 {'x': ueid, 'passwd': 'newpwd'}, 'x') |
228 self.assertRaises(Unauthorized, cnx.commit) |
228 self.assertRaises(Unauthorized, cnx.commit) |
414 cnx.commit() |
414 cnx.commit() |
415 self.failIf(cu.execute('Affaire X')) |
415 self.failIf(cu.execute('Affaire X')) |
416 |
416 |
417 def test_users_and_groups_non_readable_by_guests(self): |
417 def test_users_and_groups_non_readable_by_guests(self): |
418 cnx = self.login('anon') |
418 cnx = self.login('anon') |
419 anon = cnx.user(self.current_session()) |
419 anon = cnx.user(self.session) |
420 cu = cnx.cursor() |
420 cu = cnx.cursor() |
421 # anonymous user can only read itself |
421 # anonymous user can only read itself |
422 rset = cu.execute('Any L WHERE X owned_by U, U login L') |
422 rset = cu.execute('Any L WHERE X owned_by U, U login L') |
423 self.assertEquals(rset.rows, [['anon']]) |
423 self.assertEquals(rset.rows, [['anon']]) |
424 rset = cu.execute('CWUser X') |
424 rset = cu.execute('CWUser X') |
425 self.assertEquals(rset.rows, [[anon.eid]]) |
425 self.assertEquals(rset.rows, [[anon.eid]]) |
426 # anonymous user can read groups (necessary to check allowed transitions for instance) |
426 # anonymous user can read groups (necessary to check allowed transitions for instance) |
427 self.assert_(cu.execute('CWGroup X')) |
427 self.assert_(cu.execute('CWGroup X')) |
428 # should only be able to read the anonymous user, not another one |
428 # should only be able to read the anonymous user, not another one |
429 origuser = self.session.user |
429 origuser = self.adminsession.user |
430 self.assertRaises(Unauthorized, |
430 self.assertRaises(Unauthorized, |
431 cu.execute, 'CWUser X WHERE X eid %(x)s', {'x': origuser.eid}, 'x') |
431 cu.execute, 'CWUser X WHERE X eid %(x)s', {'x': origuser.eid}, 'x') |
432 # nothing selected, nothing updated, no exception raised |
432 # nothing selected, nothing updated, no exception raised |
433 #self.assertRaises(Unauthorized, |
433 #self.assertRaises(Unauthorized, |
434 # cu.execute, 'SET X login "toto" WHERE X eid %(x)s', |
434 # cu.execute, 'SET X login "toto" WHERE X eid %(x)s', |
460 beid1 = self.execute('INSERT Bookmark B: B path "?vid=manage", B title "manage"')[0][0] |
460 beid1 = self.execute('INSERT Bookmark B: B path "?vid=manage", B title "manage"')[0][0] |
461 beid2 = self.execute('INSERT Bookmark B: B path "?vid=index", B title "index", B bookmarked_by U WHERE U login "anon"')[0][0] |
461 beid2 = self.execute('INSERT Bookmark B: B path "?vid=index", B title "index", B bookmarked_by U WHERE U login "anon"')[0][0] |
462 self.commit() |
462 self.commit() |
463 cnx = self.login('anon') |
463 cnx = self.login('anon') |
464 cu = cnx.cursor() |
464 cu = cnx.cursor() |
465 anoneid = self.current_session().user.eid |
465 anoneid = self.session.user.eid |
466 self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,' |
466 self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,' |
467 'B bookmarked_by U, U eid %s' % anoneid).rows, |
467 'B bookmarked_by U, U eid %s' % anoneid).rows, |
468 [['index', '?vid=index']]) |
468 [['index', '?vid=index']]) |
469 self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,' |
469 self.assertEquals(cu.execute('Any T,P ORDERBY lower(T) WHERE B is Bookmark,B title T,B path P,' |
470 'B bookmarked_by U, U eid %(x)s', {'x': anoneid}).rows, |
470 'B bookmarked_by U, U eid %(x)s', {'x': anoneid}).rows, |
489 subject |
489 subject |
490 """ |
490 """ |
491 eid = self.execute('INSERT Affaire X: X ref "ARCT01"')[0][0] |
491 eid = self.execute('INSERT Affaire X: X ref "ARCT01"')[0][0] |
492 self.commit() |
492 self.commit() |
493 cnx = self.login('iaminusersgrouponly') |
493 cnx = self.login('iaminusersgrouponly') |
494 session = self.current_session() |
494 session = self.session |
495 # needed to avoid check_perm error |
495 # needed to avoid check_perm error |
496 session.set_pool() |
496 session.set_pool() |
497 # needed to remove rql expr granting update perm to the user |
497 # needed to remove rql expr granting update perm to the user |
498 self.schema['Affaire'].set_rqlexprs('update', ()) |
498 self.schema['Affaire'].set_rqlexprs('update', ()) |
499 self.assertRaises(Unauthorized, |
499 self.assertRaises(Unauthorized, |
504 # though changing a user state (even logged user) is reserved to managers |
504 # though changing a user state (even logged user) is reserved to managers |
505 rql = u"SET X in_state S WHERE X eid %(x)s, S name 'deactivated'" |
505 rql = u"SET X in_state S WHERE X eid %(x)s, S name 'deactivated'" |
506 # XXX wether it should raise Unauthorized or ValidationError is not clear |
506 # XXX wether it should raise Unauthorized or ValidationError is not clear |
507 # the best would probably ValidationError if the transition doesn't exist |
507 # the best would probably ValidationError if the transition doesn't exist |
508 # from the current state but Unauthorized if it exists but user can't pass it |
508 # from the current state but Unauthorized if it exists but user can't pass it |
509 self.assertRaises(ValidationError, cu.execute, rql, {'x': cnx.user(self.current_session()).eid}, 'x') |
509 self.assertRaises(ValidationError, cu.execute, rql, {'x': cnx.user(self.session).eid}, 'x') |
510 |
510 |
511 def test_trinfo_security(self): |
511 def test_trinfo_security(self): |
512 aff = self.execute('INSERT Affaire X: X ref "ARCT01"').get_entity(0, 0) |
512 aff = self.execute('INSERT Affaire X: X ref "ARCT01"').get_entity(0, 0) |
513 self.commit() |
513 self.commit() |
514 # can change tr info comment |
514 # can change tr info comment |