Edgewall Software

Ticket #9542: 9542-source-perms-r9987.patch

File 9542-source-perms-r9987.patch, 7.4 KB (added by rblank, 22 months ago)

Updated source permission policy.

  • trac/versioncontrol/svn_authz.py

    diff --git a/trac/versioncontrol/svn_authz.py b/trac/versioncontrol/svn_authz.py
    a b  
    3030 
    3131 
    3232def parent_iter(path): 
    33     path = path.strip('/') 
    34     if path: 
    35         path = '/' + path + '/' 
    36     else: 
    37         path = '/' 
    38  
    3933    while 1: 
    4034        yield path 
    4135        if path == '/': 
     
    141135    # IPermissionPolicy methods 
    142136 
    143137    def check_permission(self, action, username, resource, perm): 
     138        if username == 'anonymous': 
     139            usernames = ('$anonymous', '*') 
     140        else: 
     141            usernames = (username, '$authenticated', '*') 
    144142        if action == 'FILE_VIEW' or action == 'BROWSER_VIEW': 
    145143            authz, users = self._get_authz_info() 
    146144            if authz is None: 
    147145                return False 
    148146            if resource is None: 
    149                 return users is True or username in users 
     147                return bool(users & set(usernames)) 
    150148            if resource.realm == 'source': 
    151149                modules = [resource.parent.id or self.authz_module_name] 
    152150                if modules[0]: 
    153151                    modules.append('') 
    154                 for p in parent_iter(resource.id): 
     152                path = '/' + resource.id.strip('/') 
     153                if path != '/': 
     154                    path += '/' 
     155                 
     156                # Walk from resource up parent directories 
     157                for spath in parent_iter(path): 
    155158                    for module in modules: 
    156                         section = authz.get(module, {}).get(p, {}) 
    157                         result = section.get(username) 
    158                         if result is not None: 
    159                             return result 
    160                         result = section.get('*') 
    161                         if result is not None: 
    162                             return result 
    163                 return False 
     159                        section = authz.get(module, {}).get(spath) 
     160                        if section: 
     161                            for user in usernames: 
     162                                result = section.get(user) 
     163                                if result is not None: 
     164                                    return result 
     165                 
     166                # Allow access to parent directories of allowed resources 
     167                if any(section.get(user) is True 
     168                       for module in modules 
     169                       for spath, section in authz.get(module, {}).iteritems() 
     170                       if spath.startswith(path) 
     171                       for user in usernames): 
     172                    return True 
     173 
    164174        elif action == 'CHANGESET_VIEW': 
    165175            authz, users = self._get_authz_info() 
    166176            if authz is None: 
    167177                return False 
    168178            if resource is None: 
    169                 return users is True or username in users 
     179                return bool(users & set(usernames)) 
    170180            if resource.realm == 'changeset': 
    171181                rm = RepositoryManager(self.env) 
    172182                repos = rm.get_repository(resource.parent.id) 
     
    193203            self.log.info('Parsing authz file: %s' % self.authz_file) 
    194204            try: 
    195205                self._authz = parse(read_file(self.authz_file)) 
    196                 users = set(user for module in self._authz.itervalues() 
    197                             for path in module.itervalues() 
    198                             for user, result in path.iteritems() if result) 
    199                 self._users = '*' in users or users 
     206                self._users = set(user for module in self._authz.itervalues() 
     207                                  for path in module.itervalues() 
     208                                  for user, result in path.iteritems() 
     209                                  if result) 
    200210            except Exception, e: 
    201211                self._authz = None 
    202212                self._users = set() 
  • trac/versioncontrol/tests/svn_authz.py

    diff --git a/trac/versioncontrol/tests/svn_authz.py b/trac/versioncontrol/tests/svn_authz.py
    a b  
    148148[/wildcard] 
    149149* = r 
    150150 
     151# Special tokens 
     152[/special/anonymous] 
     153$anonymous = r 
     154[/special/authenticated] 
     155$authenticated = r 
     156 
    151157# Groups 
    152158[/groups_a] 
    153159@group1 = r 
     
    198204        self.assertEqual(result, check) 
    199205         
    200206    def test_default_permission(self): 
    201         # By default, no permission is granted 
    202         self.assertPermission(False, 'joe', '', '/not_defined') 
    203         self.assertPermission(False, 'jane', 'repo', '/not/defined/either') 
     207        # By default, permissions are undecided 
     208        self.assertPermission(None, 'joe', '', '/not_defined') 
     209        self.assertPermission(None, 'jane', 'repo', '/not/defined/either') 
    204210 
    205211    def test_read_write(self): 
    206212        # Allow 'r' and 'rw' entries, deny 'w' and empty entries 
     
    225231    def test_module_usage(self): 
    226232        # If a module name is specified, the rules are specific to the module 
    227233        self.assertPermission(True, 'user', 'module', '/module_a') 
    228         self.assertPermission(False, 'user', 'module', '/module_b') 
     234        self.assertPermission(None, 'user', 'module', '/module_b') 
    229235        # If a module is specified, but the configuration contains a non-module 
    230236        # path, the non-module path can still apply 
    231237        self.assertPermission(True, 'user', 'module', '/module_c') 
     
    233239        self.assertPermission(False, 'user', 'module', '/module_d') 
    234240 
    235241    def test_wildcard(self): 
    236         # The * wildcard matches all users 
     242        # The * wildcard matches all users, including anonymous 
     243        self.assertPermission(True, 'anonymous', '', '/wildcard') 
    237244        self.assertPermission(True, 'joe', '', '/wildcard') 
    238245        self.assertPermission(True, 'jane', '', '/wildcard') 
    239246 
     247    def test_special_tokens(self): 
     248        # The $anonymous token matches only anonymous users 
     249        self.assertPermission(True, 'anonymous', '', '/special/anonymous') 
     250        self.assertPermission(None, 'user', '', '/special/anonymous') 
     251        # The $authenticated token matches all authenticated users 
     252        self.assertPermission(None, 'anonymous', '', '/special/authenticated') 
     253        self.assertPermission(True, 'joe', '', '/special/authenticated') 
     254        self.assertPermission(True, 'jane', '', '/special/authenticated') 
     255 
    240256    def test_groups(self): 
    241257        # Groups are specified in a separate section and used with an @ prefix 
    242258        self.assertPermission(True, 'user', '', '/groups_a') 
  • trac/versioncontrol/web_ui/browser.py

    diff --git a/trac/versioncontrol/web_ui/browser.py b/trac/versioncontrol/web_ui/browser.py
    a b  
    2626from trac.mimeview.api import Mimeview, is_binary, \ 
    2727                              IHTMLPreviewAnnotator, Context 
    2828from trac.perm import IPermissionRequestor 
    29 from trac.resource import ResourceNotFound 
     29from trac.resource import Resource, ResourceNotFound 
    3030from trac.util import embedded_numbers 
    3131from trac.util.compat import any 
    3232from trac.util.datefmt import http_date, utc 
     
    505505            except TracError, err: 
    506506                entry = (reponame, repoinfo, None, None, 
    507507                         exception_to_unicode(err)) 
     508            if entry[-1] is not None:   # Check permission in case of error 
     509                root = Resource('repository', reponame).child('source', '/') 
     510                if 'BROWSER_VIEW' not in context.perm(root): 
     511                    continue 
    508512            repositories.append(entry) 
    509513 
    510514        # Ordering of repositories