Back to index

moin  1.9.0~rc2
test_security.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - MoinMoin.security Tests
00004 
00005     TODO: when refactoring this, do not use "iter" (is a builtin)
00006 
00007     @copyright: 2003-2004 by Juergen Hermann <jh@web.de>,
00008                 2007 by MoinMoin:ReimarBauer,
00009                 2007 by MoinMoin:ThomasWaldmann
00010     @license: GNU GPL, see COPYING for details.
00011 """
00012 
00013 import py
00014 
00015 from MoinMoin import security
00016 acliter = security.ACLStringIterator
00017 AccessControlList = security.AccessControlList
00018 
00019 from MoinMoin.PageEditor import PageEditor
00020 from MoinMoin.user import User
00021 
00022 from MoinMoin._tests import become_trusted, create_page, nuke_page
00023 
00024 class TestACLStringIterator(object):
00025 
00026     def testEmpty(self):
00027         """ security: empty acl string raise StopIteration """
00028         iter = acliter(self.request.cfg.acl_rights_valid, '')
00029         py.test.raises(StopIteration, iter.next)
00030 
00031     def testWhiteSpace(self):
00032         """ security: white space acl string raise StopIteration """
00033         iter = acliter(self.request.cfg.acl_rights_valid, '       ')
00034         py.test.raises(StopIteration, iter.next)
00035 
00036     def testDefault(self):
00037         """ security: default meta acl """
00038         iter = acliter(self.request.cfg.acl_rights_valid, 'Default Default')
00039         for mod, entries, rights in iter:
00040             assert entries == ['Default']
00041             assert rights == []
00042 
00043     def testEmptyRights(self):
00044         """ security: empty rights """
00045         iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:')
00046         mod, entries, rights = iter.next()
00047         assert entries == ['WikiName']
00048         assert rights == []
00049 
00050     def testSingleWikiNameSingleWrite(self):
00051         """ security: single wiki name, single right """
00052         iter = acliter(self.request.cfg.acl_rights_valid, 'WikiName:read')
00053         mod, entries, rights = iter.next()
00054         assert entries == ['WikiName']
00055         assert rights == ['read']
00056 
00057     def testMultipleWikiNameAndRights(self):
00058         """ security: multiple wiki names and rights """
00059         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,UserTwo:read,write')
00060         mod, entries, rights = iter.next()
00061         assert entries == ['UserOne', 'UserTwo']
00062         assert rights == ['read', 'write']
00063 
00064     def testMultipleWikiNameAndRightsSpaces(self):
00065         """ security: multiple names with spaces """
00066         iter = acliter(self.request.cfg.acl_rights_valid, 'user one,user two:read')
00067         mod, entries, rights = iter.next()
00068         assert entries == ['user one', 'user two']
00069         assert rights == ['read']
00070 
00071     def testMultipleEntries(self):
00072         """ security: multiple entries """
00073         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write UserTwo:read All:')
00074         mod, entries, rights = iter.next()
00075         assert entries == ['UserOne']
00076         assert rights == ['read', 'write']
00077         mod, entries, rights = iter.next()
00078         assert entries == ['UserTwo']
00079         assert rights == ['read']
00080         mod, entries, rights = iter.next()
00081         assert entries == ['All']
00082         assert rights == []
00083 
00084     def testNameWithSpaces(self):
00085         """ security: single name with spaces """
00086         iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read')
00087         mod, entries, rights = iter.next()
00088         assert entries == ['user one']
00089         assert rights == ['read']
00090 
00091     def testMultipleEntriesWithSpaces(self):
00092         """ security: multiple entries with spaces """
00093         iter = acliter(self.request.cfg.acl_rights_valid, 'user one:read,write user two:read')
00094         mod, entries, rights = iter.next()
00095         assert entries == ['user one']
00096         assert rights == ['read', 'write']
00097         mod, entries, rights = iter.next()
00098         assert entries == ['user two']
00099         assert rights == ['read']
00100 
00101     def testMixedNames(self):
00102         """ security: mixed wiki names and names with spaces """
00103         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write user three,UserFour:read')
00104         mod, entries, rights = iter.next()
00105         assert entries == ['UserOne', 'user two']
00106         assert rights == ['read', 'write']
00107         mod, entries, rights = iter.next()
00108         assert entries == ['user three', 'UserFour']
00109         assert rights == ['read']
00110 
00111     def testModifier(self):
00112         """ security: acl modifiers """
00113         iter = acliter(self.request.cfg.acl_rights_valid, '+UserOne:read -UserTwo:')
00114         mod, entries, rights = iter.next()
00115         assert mod == '+'
00116         assert entries == ['UserOne']
00117         assert rights == ['read']
00118         mod, entries, rights = iter.next()
00119         assert mod == '-'
00120         assert entries == ['UserTwo']
00121         assert rights == []
00122 
00123     def testIgnoreInvalidACL(self):
00124         """ security: ignore invalid acl
00125 
00126         The last part of this acl can not be parsed. If it ends with :
00127         then it will be parsed as one name with spaces.
00128         """
00129         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read user two is ignored')
00130         mod, entries, rights = iter.next()
00131         assert entries == ['UserOne']
00132         assert rights == ['read']
00133         py.test.raises(StopIteration, iter.next)
00134 
00135     def testEmptyNamesWithRight(self):
00136         """ security: empty names with rights
00137 
00138         The documents does not talk about this case, may() should ignore
00139         the rights because there is no entry.
00140         """
00141         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read :read All:')
00142         mod, entries, rights = iter.next()
00143         assert entries == ['UserOne']
00144         assert rights == ['read']
00145         mod, entries, rights = iter.next()
00146         assert entries == []
00147         assert rights == ['read']
00148         mod, entries, rights = iter.next()
00149         assert entries == ['All']
00150         assert rights == []
00151 
00152     def testIgnodeInvalidRights(self):
00153         """ security: ignore rights not in acl_rights_valid """
00154         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,sing,write,drink,sleep')
00155         mod, entries, rights = iter.next()
00156         assert rights == ['read', 'write']
00157 
00158     def testBadGuy(self):
00159         """ security: bad guy may not allowed anything
00160 
00161         This test was failing on the apply acl rights test.
00162         """
00163         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne:read,write BadGuy: All:read')
00164         mod, entries, rights = iter.next()
00165         mod, entries, rights = iter.next()
00166         assert entries == ['BadGuy']
00167         assert rights == []
00168 
00169     def testAllowExtraWhitespace(self):
00170         """ security: allow extra white space between entries """
00171         iter = acliter(self.request.cfg.acl_rights_valid, 'UserOne,user two:read,write   user three,UserFour:read  All:')
00172         mod, entries, rights = iter.next()
00173         assert  entries == ['UserOne', 'user two']
00174         assert rights == ['read', 'write']
00175         mod, entries, rights = iter.next()
00176         assert entries == ['user three', 'UserFour']
00177         assert rights == ['read']
00178         mod, entries, rights = iter.next()
00179         assert entries == ['All']
00180         assert rights == []
00181 
00182 
00183 class TestAcl(object):
00184     """ security: testing access control list
00185 
00186     TO DO: test unknown user?
00187     """
00188     def setup_method(self, method):
00189         # Backup user
00190         self.savedUser = self.request.user.name
00191 
00192     def teardown_method(self, method):
00193         # Restore user
00194         self.request.user.name = self.savedUser
00195 
00196     def testApplyACLByUser(self):
00197         """ security: applying acl by user name"""
00198         # This acl string...
00199         acl_rights = [
00200             "-MinusGuy:read "
00201             "+MinusGuy:read "
00202             "+PlusGuy:read "
00203             "-PlusGuy:read "
00204             "Admin1,Admin2:read,write,delete,revert,admin  "
00205             "Admin3:read,write,admin  "
00206             "JoeDoe:read,write  "
00207             "name with spaces,another one:read,write  "
00208             "CamelCase,extended name:read,write  "
00209             "BadGuy:  "
00210             "All:read  "
00211             ]
00212         acl = security.AccessControlList(self.request.cfg, acl_rights)
00213 
00214         # Should apply these rights:
00215         users = (
00216             # user,                 rights
00217             # CamelCase names
00218             ('Admin1', ('read', 'write', 'admin', 'revert', 'delete')),
00219             ('Admin2', ('read', 'write', 'admin', 'revert', 'delete')),
00220             ('Admin3', ('read', 'write', 'admin')),
00221             ('JoeDoe', ('read', 'write')),
00222             ('SomeGuy', ('read', )),
00223             # Extended names or mix of extended and CamelCase
00224             ('name with spaces', ('read', 'write', )),
00225             ('another one', ('read', 'write', )),
00226             ('CamelCase', ('read', 'write', )),
00227             ('extended name', ('read', 'write', )),
00228             # Blocking bad guys
00229             ('BadGuy', ()),
00230             # All other users - every one not mentioned in the acl lines
00231             ('All', ('read', )),
00232             ('Anonymous', ('read', )),
00233             # we check whether ACL processing stops for a user/right match
00234             # with ACL modifiers
00235             ('MinusGuy', ()),
00236             ('PlusGuy', ('read', )),
00237             )
00238 
00239         # Check rights
00240         for user, may in users:
00241             mayNot = [right for right in self.request.cfg.acl_rights_valid
00242                       if right not in may]
00243             # User should have these rights...
00244             for right in may:
00245                 assert acl.may(self.request, user, right)
00246             # But NOT these:
00247             for right in mayNot:
00248                 assert not acl.may(self.request, user, right)
00249 
00250 
00251 class TestPageAcls(object):
00252     """ security: real-life access control list on pages testing
00253     """
00254     mainpage_name = u'AclTestMainPage'
00255     subpage_name = u'AclTestMainPage/SubPage'
00256     item_rwforall = u'EveryoneMayReadWriteMe'
00257     subitem_4boss = u'EveryoneMayReadWriteMe/OnlyTheBossMayWMe'
00258     pages = [
00259         # pagename, content
00260         (mainpage_name, u"#acl JoeDoe:\n#acl JaneDoe:read,write\nFoo!"),
00261         (subpage_name, u"FooFoo!"),
00262         (item_rwforall, u"#acl All:read,write\nMay be read from and written to by anyone"),
00263         (subitem_4boss, u"#acl JoeDoe:read,write\nOnly JoeDoe (the boss) may write"),
00264     ]
00265 
00266     from MoinMoin._tests import wikiconfig
00267     class Config(wikiconfig.Config):
00268         acl_rights_before = u"WikiAdmin:admin,read,write,delete,revert"
00269         acl_rights_default = u"All:read,write"
00270         acl_rights_after = u"All:read"
00271         acl_hierarchic = False
00272 
00273     def setup_class(self):
00274         # Backup user
00275         self.savedUser = self.request.user.name
00276         self.request.user = User(self.request, auth_username=u'WikiAdmin')
00277         self.request.user.valid = True
00278 
00279         for page_name, page_content in self.pages:
00280             create_page(self.request, page_name, page_content)
00281 
00282     def teardown_class(self):
00283         # Restore user
00284         self.request.user.name = self.savedUser
00285 
00286         for page_name, dummy in self.pages:
00287             nuke_page(self.request, page_name)
00288 
00289     def testPageACLs(self):
00290         """ security: test page acls """
00291         tests = [
00292             # hierarchic, pagename, username, expected_rights
00293             (False, self.mainpage_name, u'WikiAdmin', ['read', 'write', 'admin', 'revert', 'delete']),
00294             (True,  self.mainpage_name, u'WikiAdmin', ['read', 'write', 'admin', 'revert', 'delete']),
00295             (False, self.mainpage_name, u'AnyUser', ['read']), # by after acl
00296             (True,  self.mainpage_name, u'AnyUser', ['read']), # by after acl
00297             (False, self.mainpage_name, u'JaneDoe', ['read', 'write']), # by page acl
00298             (True,  self.mainpage_name, u'JaneDoe', ['read', 'write']), # by page acl
00299             (False, self.mainpage_name, u'JoeDoe', []), # by page acl
00300             (True,  self.mainpage_name, u'JoeDoe', []), # by page acl
00301             (False, self.subpage_name, u'WikiAdmin', ['read', 'write', 'admin', 'revert', 'delete']),
00302             (True,  self.subpage_name, u'WikiAdmin', ['read', 'write', 'admin', 'revert', 'delete']),
00303             (False, self.subpage_name, u'AnyUser', ['read', 'write']), # by default acl
00304             (True,  self.subpage_name, u'AnyUser', ['read']), # by after acl
00305             (False, self.subpage_name, u'JoeDoe', ['read', 'write']), # by default acl
00306             (True,  self.subpage_name, u'JoeDoe', []), # by inherited acl from main page
00307             (False, self.subpage_name, u'JaneDoe', ['read', 'write']), # by default acl
00308             (True,  self.subpage_name, u'JaneDoe', ['read', 'write']), # by inherited acl from main page
00309             (True,  self.subitem_4boss, u'AnyUser', ['read']), # by after acl
00310             (True,  self.subitem_4boss, u'JoeDoe', ['read', 'write']), # by item acl
00311         ]
00312 
00313         for hierarchic, pagename, username, may in tests:
00314             u = User(self.request, auth_username=username)
00315             u.valid = True
00316 
00317             def _have_right(u, right, pagename, hierarchic):
00318                 self.request.cfg.acl_hierarchic = hierarchic
00319                 can_access = u.may.__getattr__(right)(pagename)
00320                 if can_access:
00321                     print "page %s: %s test if %s may %s (success)" % (
00322                         pagename, ['normal', 'hierarchic'][hierarchic], username, right)
00323                 else:
00324                     print "page %s: %s test if %s may %s (failure)" % (
00325                         pagename, ['normal', 'hierarchic'][hierarchic], username, right)
00326                 assert can_access
00327 
00328             # User should have these rights...
00329             for right in may:
00330                 yield _have_right, u, right, pagename, hierarchic
00331 
00332             def _not_have_right(u, right, pagename, hierarchic):
00333                 self.request.cfg.acl_hierarchic = hierarchic
00334                 can_access = u.may.__getattr__(right)(pagename)
00335                 if can_access:
00336                     print "page %s: %s test if %s may not %s (failure)" % (
00337                         pagename, ['normal', 'hierarchic'][hierarchic], username, right)
00338                 else:
00339                     print "page %s: %s test if %s may not %s (success)" % (
00340                         pagename, ['normal', 'hierarchic'][hierarchic], username, right)
00341                 assert not can_access
00342 
00343             # User should NOT have these rights:
00344             mayNot = [right for right in self.request.cfg.acl_rights_valid
00345                       if right not in may]
00346             for right in mayNot:
00347                 yield _not_have_right, u, right, pagename, hierarchic
00348 
00349 coverage_modules = ['MoinMoin.security']