Exemplo n.º 1
0
    def testApplyACLByGroup(self):
        """ security: applying acl by group name"""
        # This acl string...
        acl_rights = [
            "PGroup,AllGroup:read,write,admin "
            "AGroup:read "
        ]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        # Should apply these rights:
        users = (
            # user, rights
            ('Antony', ('read', 'write', 'admin', )),  # in PGroup
            ('Beatrice', ('read', 'write', 'admin', )),  # in PGroup
            ('Charles', ('read', )),  # virtually in AGroup
        )

        # Check rights
        for user, may in users:
            mayNot = [right for right in app.cfg.acl_rights_contents
                      if right not in may]
            # User should have these rights...
            for right in may:
                assert acl.may(user, right)
            # But NOT these:
            for right in mayNot:
                assert not acl.may(user, right)
Exemplo n.º 2
0
    def testApplyACLByGroup(self):
        """ security: applying acl by group name"""
        # This acl string...
        acl_rights = [
            "PGroup,AllGroup:read,write,admin "
            "AGroup:read "
        ]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        # Should apply these rights:
        users = (
            # user, rights
            ('Antony', ('read', 'write', 'admin', )),  # in PGroup
            ('Beatrice', ('read', 'write', 'admin', )),  # in PGroup
            ('Charles', ('read', )),  # virtually in AGroup
        )

        # Check rights
        for user, may in users:
            mayNot = [right for right in app.cfg.acl_rights_contents
                      if right not in may]
            # User should have these rights...
            for right in may:
                assert acl.may(user, right)
            # But NOT these:
            for right in mayNot:
                assert not acl.may(user, right)
Exemplo n.º 3
0
    def test_backend_acl_with_all(self):
        acl_rights = ["EditorGroup:read,write,admin All:read"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        for member in self.expanded_groups[u'EditorGroup']:
            for permission in ["read", "write", "admin"]:
                assert acl.may(member, permission)

        assert acl.may(u"Someone", "read")
        for permission in ["write", "admin"]:
            assert not acl.may(u"Someone", permission)
Exemplo n.º 4
0
    def testApplyACLByUser(self):
        """ security: applying acl by user name"""
        # This acl string...
        acl_rights = [
            "-MinusGuy:read "
            "+MinusGuy:read "
            "+PlusGuy:read "
            "-PlusGuy:read "
            "Admin1,Admin2:read,write,admin  "
            "Admin3:read,write,admin  "
            "JoeDoe:read,write  "
            "name with spaces,another one:read,write  "
            "CamelCase,extended name:read,write  "
            "BadGuy:  "
            "All:read  "
        ]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        # Should apply these rights:
        users = (
            # user,                 rights
            # CamelCase names
            ('Admin1', ('read', 'write', 'admin')),
            ('Admin2', ('read', 'write', 'admin')),
            ('Admin3', ('read', 'write', 'admin')),
            ('JoeDoe', ('read', 'write')),
            ('SomeGuy', ('read', )),
            # Extended names or mix of extended and CamelCase
            ('name with spaces', ('read', 'write', )),
            ('another one', ('read', 'write', )),
            ('CamelCase', ('read', 'write', )),
            ('extended name', ('read', 'write', )),
            # Blocking bad guys
            ('BadGuy', ()),
            # All other users - every one not mentioned in the acl lines
            ('All', ('read', )),
            ('Anonymous', ('read', )),
            # we check whether ACL processing stops for a user/right match
            # with ACL modifiers
            ('MinusGuy', ()),
            ('PlusGuy', ('read', )),
        )

        # Check rights
        for user, may in users:
            mayNot = [right for right in app.cfg.acl_rights_contents
                      if right not in may]
            # User should have these rights...
            for right in may:
                assert acl.may(user, right)
            # But NOT these:
            for right in mayNot:
                assert not acl.may(user, right)
Exemplo n.º 5
0
    def testApplyACLByUser(self):
        """ security: applying acl by user name"""
        # This acl string...
        acl_rights = [
            "-MinusGuy:read "
            "+MinusGuy:read "
            "+PlusGuy:read "
            "-PlusGuy:read "
            "Admin1,Admin2:read,write,admin  "
            "Admin3:read,write,admin  "
            "JoeDoe:read,write  "
            "name with spaces,another one:read,write  "
            "CamelCase,extended name:read,write  "
            "BadGuy:  "
            "All:read  "
        ]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        # Should apply these rights:
        users = (
            # user,                 rights
            # CamelCase names
            ('Admin1', ('read', 'write', 'admin')),
            ('Admin2', ('read', 'write', 'admin')),
            ('Admin3', ('read', 'write', 'admin')),
            ('JoeDoe', ('read', 'write')),
            ('SomeGuy', ('read', )),
            # Extended names or mix of extended and CamelCase
            ('name with spaces', ('read', 'write', )),
            ('another one', ('read', 'write', )),
            ('CamelCase', ('read', 'write', )),
            ('extended name', ('read', 'write', )),
            # Blocking bad guys
            ('BadGuy', ()),
            # All other users - every one not mentioned in the acl lines
            ('All', ('read', )),
            ('Anonymous', ('read', )),
            # we check whether ACL processing stops for a user/right match
            # with ACL modifiers
            ('MinusGuy', ()),
            ('PlusGuy', ('read', )),
        )

        # Check rights
        for user, may in users:
            mayNot = [right for right in app.cfg.acl_rights_contents
                      if right not in may]
            # User should have these rights...
            for right in may:
                assert acl.may(user, right)
            # But NOT these:
            for right in mayNot:
                assert not acl.may(user, right)
Exemplo n.º 6
0
    def test_backend_acl_deny(self):
        """
        Test if the wiki group backend works with acl code.
        Check user which does not have rights.
        """
        acl_rights = ["AdminGroup:read,write"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        assert u"SomeUser" not in flaskg.groups['AdminGroup']
        for permission in ["read", "write"]:
            assert not acl.may(u"SomeUser", permission), 'SomeUser must not have {0} permission because he is not listed in the AdminGroup'.format(permission)

        assert u'Admin1' in flaskg.groups['AdminGroup']
        assert not acl.may(u"Admin1", "admin")
Exemplo n.º 7
0
    def test_backend_acl_not_existing_group(self):
        assert u'NotExistingGroup' not in flaskg.groups

        acl_rights = ["NotExistingGroup:read,write,admin All:read"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        assert not acl.may(u"Someone", "write")
Exemplo n.º 8
0
    def test_backend_acl_allow(self):
        """
        Test if the wiki group backend works with acl code.
        Check user which has rights.
        """
        acl_rights = ["AdminGroup:admin,read,write"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        for user in self.expanded_groups['AdminGroup']:
            for permission in ["read", "write", "admin"]:
                assert acl.may(u"Admin1", permission), '{0} must have {1} permission because he is member of the AdminGroup'.format(user, permission)
Exemplo n.º 9
0
    def test_wiki_backend_item_acl_usergroupmember_item(self):
        """
        Test if the wiki group backend works with acl code.
        First check acl rights of a user that is not a member of group
        then add user member to an item group and check acl rights
        """
        become_trusted()
        update_item(u'NewGroup', {USERGROUP: ["ExampleUser"]}, DATA)

        acl_rights = ["NewGroup:read,write"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        has_rights_before = acl.may(u"AnotherUser", "read")

        # update item - add AnotherUser to a item group NewGroup
        update_item(u'NewGroup', {USERGROUP: ["AnotherUser"]}, '')

        has_rights_after = acl.may(u"AnotherUser", "read")

        assert not has_rights_before, 'AnotherUser has no read rights because in the beginning he is not a member of a group item NewGroup'
        assert has_rights_after, 'AnotherUser must have read rights because after appenditem he is member of NewGroup'
Exemplo n.º 10
0
    def test_wiki_backend_item_acl_usergroupmember_item(self):
        """
        Test if the wiki group backend works with acl code.
        First check acl rights of a user that is not a member of group
        then add user member to an item group and check acl rights
        """
        become_trusted()
        update_item(u'NewGroup', {USERGROUP: ["ExampleUser"]}, DATA)

        acl_rights = ["NewGroup:read,write"]
        acl = AccessControlList(acl_rights, valid=app.cfg.acl_rights_contents)

        has_rights_before = acl.may(u"AnotherUser", "read")

        # update item - add AnotherUser to a item group NewGroup
        update_item(u'NewGroup', {USERGROUP: ["AnotherUser"]}, '')

        has_rights_after = acl.may(u"AnotherUser", "read")

        assert not has_rights_before, 'AnotherUser has no read rights because in the beginning he is not a member of a group item NewGroup'
        assert has_rights_after, 'AnotherUser must have read rights because after appenditem he is member of NewGroup'
Exemplo n.º 11
0
class AclWrapperBackend(object):
    """
    The AMW is bound to a specific request. The actual backend is retrieved
    from the config upon request initialization. Any method that is in some
    way relevant to security needs to be wrapped in order to ensure the user
    has the permissions necessary to perform the desired action.
    Note: This may *not* inherit from MoinMoin.storage.Backend because that would
    break our __getattr__ attribute 'redirects' (which are necessary because a backend
    implementor may decide to use his own helper functions which the items and revisions
    will still try to call).
    """
    def __init__(self,
                 cfg,
                 backend,
                 hierarchic=False,
                 before=u"",
                 default=u"",
                 after=u"",
                 valid=None):
        """
        @type backend: Some object that implements the storage API.
        @param backend: The unprotected backend that we want to protect.
        @type hierarchic: bool
        @param hierarchic: Indicate whether we want to process ACLs in hierarchic mode.
        @type before: unicode
        @param before: ACL to be applied before all the other ACLs.
        @type default: unicode
        @param default: If no ACL information is given on the item in question, use this default.
        @type after: unicode
        @param after: ACL to be applied after all the other ACLs.
        @type valid: list of strings or None
        @param valid: If a list is given, only strings in the list are treated as valid acl privilege descriptors.
                      If None is give, the global wiki default is used.
        """
        self.cfg = cfg
        self.backend = backend
        self.hierarchic = hierarchic
        self.valid = valid
        self.before = AccessControlList(cfg, [before],
                                        default=default,
                                        valid=valid)
        self.default = AccessControlList(cfg, [default],
                                         default=default,
                                         valid=valid)
        self.after = AccessControlList(cfg, [after],
                                       default=default,
                                       valid=valid)

    def __getattr__(self, attr):
        # Attributes that this backend does not define itself are just looked
        # up on the real backend.
        return getattr(self.backend, attr)

    def search_items(self, searchterm):
        """
        @see: Backend.search_items.__doc__
        """
        for item in self.backend.search_items(searchterm):
            if self._may(item.name, READ):
                # The item returned needs to be wrapped because otherwise the
                # item's methods (like create_revision) wouldn't be wrapped.
                wrapped_item = AclWrapperItem(item, self)
                yield wrapped_item

    def get_item(self, itemname):
        """
        @see: Backend.get_item.__doc__
        """
        if not self._may(itemname, READ):
            raise AccessDeniedError(flaskg.user.name, READ, itemname)
        real_item = self.backend.get_item(itemname)
        # Wrap the item here as well.
        wrapped_item = AclWrapperItem(real_item, self)
        return wrapped_item

    def has_item(self, itemname):
        """
        @see: Backend.has_item.__doc__
        """
        # We do not hide the sheer existance of items. When trying
        # to create an item with the same name, the user would notice anyway.
        return self.backend.has_item(itemname)

    def create_item(self, itemname):
        """
        @see: Backend.create_item.__doc__
        """
        if not self._may(itemname, CREATE):
            raise AccessDeniedError(flaskg.user.name, CREATE, itemname)
        real_item = self.backend.create_item(itemname)
        # Wrap item.
        wrapped_item = AclWrapperItem(real_item, self)
        return wrapped_item

    def iteritems(self):
        """
        @see: Backend.iteritems.__doc__
        """
        for item in self.backend.iteritems():
            if self._may(item.name, READ):
                yield AclWrapperItem(item, self)

    def history(self, reverse=True):
        """
        @see: Backend.history.__doc__
        """
        for revision in self.backend.history(reverse):
            if self._may(revision.item.name, READ):
                # The revisions returned here should only be StoredRevisions.
                # We wrap them nevertheless to be sure. Esp. revision.item
                # would otherwise give access to an unwrapped item.
                item = revision.item
                item = AclWrapperItem(item, self)
                revision = AclWrapperRevision(revision, item)
                yield revision

    def _get_acl(self, itemname):
        """
        Get ACL strings from the last revision's metadata and return ACL object.
        """
        try:
            item = self.backend.get_item(itemname)
            # we always use the ACLs set on the latest revision:
            current_rev = item.get_revision(-1)
            acls = current_rev[ACL]
        except (NoSuchItemError, NoSuchRevisionError, KeyError):
            # do not use default acl here
            acls = []
        if not isinstance(acls, (tuple, list)):
            acls = (acls, )
        default = self.default.default
        return AccessControlList(self.cfg,
                                 acls,
                                 default=default,
                                 valid=self.valid)

    def _may(self, itemname, right):
        """ Check if self.username may have <right> access on item <itemname>.

        For hierarchic=False we just check the item in question.

        For hierarchic=True, we check each item in the hierarchy. We
        start with the deepest item and recurse to the top of the tree.
        If one of those permits, True is returned.
        This is done *only* if there is *no ACL at all* (not even an empty one)
        on the items we 'recurse over'.

        For both configurations, we check `before` before the item/default
        acl and `after` after the item/default acl, of course.

        `default` is only used if there is no ACL on the item (and none on
        any of the item's parents when using hierarchic.)

        @param itemname: item to get permissions from
        @param right: the right to check

        @rtype: bool
        @return: True if you have permission or False
        """
        username = flaskg.user.name

        allowed = self.before.may(username, right)
        if allowed is not None:
            return allowed

        if self.hierarchic:
            items = itemname.split('/')  # create item hierarchy list
            some_acl = False
            for i in range(len(items), 0, -1):
                # Create the next pagename in the hierarchy
                # starting at the leaf, going to the root
                name = '/'.join(items[:i])
                acl = self._get_acl(name)
                if acl.has_acl():
                    some_acl = True
                    allowed = acl.may(username, right)
                    if allowed is not None:
                        return allowed
                    # If the item has an acl (even one that doesn't match) we *do not*
                    # check the parents. We only check the parents if there's no acl on
                    # the item at all.
                    break
            if not some_acl:
                allowed = self.default.may(username, right)
                if allowed is not None:
                    return allowed
        else:
            acl = self._get_acl(itemname)
            if acl.has_acl():
                allowed = acl.may(username, right)
                if allowed is not None:
                    return allowed
            else:
                allowed = self.default.may(username, right)
                if allowed is not None:
                    return allowed

        allowed = self.after.may(username, right)
        if allowed is not None:
            return allowed

        return False