示例#1
0
    def can_access(self, user, allow_admin=True):
        """Checks if the user can access the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param allow_admin: If admin users should always have access
        """

        override = self._check_can_access_override(user, allow_admin=allow_admin)
        if override is not None:
            return override

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            rv = True
        # If there's a valid access key we can skip all other ACL checks
        elif self.allow_access_key and self.check_access_key():
            rv = True
        elif self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            rv = True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            if any(user in entry.principal for entry in iter_acl(self.acl_entries)):
                rv = True
            elif isinstance(self, ProtectionManagersMixin):
                rv = self.can_manage(user, allow_admin=allow_admin)
            else:
                rv = False
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection
            # unless `inheriting_have_acl` is set, in which case we
            # might not need to check the parents at all
            if self.inheriting_have_acl and any(user in entry.principal for entry in iter_acl(self.acl_entries)):
                rv = True
            else:
                # the parent can be either an object inheriting from this
                # mixin or a legacy object with an AccessController
                parent = self.protection_parent
                if parent is None:
                    # This should be the case for the top-level object,
                    # i.e. the root category, which shouldn't allow
                    # ProtectionMode.inheriting as it makes no sense.
                    raise TypeError('protection_parent of {} is None'.format(self))
                elif hasattr(parent, 'can_access'):
                    rv = parent.can_access(user, allow_admin=allow_admin)
                else:
                    raise TypeError('protection_parent of {} is of invalid type {} ({})'.format(self, type(parent),
                                                                                                parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError('Invalid protection mode: {}'.format(self.protection_mode))

        override = self._check_can_access_override(user, allow_admin=allow_admin, authorized=rv)
        return override if override is not None else rv
示例#2
0
    def can_access(self, user, allow_admin=True):
        """Checks if the user can access the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param allow_admin: If admin users should always have access
        """

        # Trigger signals for protection overrides
        rv = values_from_signal(
            signals.acl.can_access.send(type(self), obj=self, user=user, allow_admin=allow_admin), single_value=True
        )
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            return True

        if self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            return True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            return user is not None and any(user in entry.principal for entry in iter_acl(self.acl_entries))
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection
            # unless `inheriting_have_acl` is set, in which case we
            # might not need to check the parents at all
            if (
                self.inheriting_have_acl
                and user is not None
                and any(user in entry.principal for entry in iter_acl(self.acl_entries))
            ):
                return True
            # the parent can be either an object inheriting from this
            # mixin or a legacy object with an AccessController
            parent = self.protection_parent
            if parent is None:
                # This should be the case for the top-level object,
                # i.e. the root category, which shouldn't allow
                # ProtectionMode.inheriting as it makes no sense.
                raise TypeError("protection_parent of {} is None".format(self))
            elif hasattr(parent, "can_access"):
                return parent.can_access(user, allow_admin=allow_admin)
            elif hasattr(parent, "canAccess"):
                return parent.canAccess(AccessWrapper(user.as_avatar if user else None))
            else:
                raise TypeError("protection_parent of {} is of invalid type {} ({})".format(self, type(parent), parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError("Invalid protection mode: {}".format(self.protection_mode))
示例#3
0
def get_contributions_with_user_as_submitter(event, user):
    """Get a list of contributions in which the `user` has submission rights"""
    contribs = (Contribution.query.with_parent(event)
                .options(joinedload('acl_entries'))
                .filter(Contribution.acl_entries.any(ContributionPrincipal.has_management_role('submit')))
                .all())
    return {c for c in contribs if any(user in entry.principal for entry in iter_acl(c.acl_entries))}
示例#4
0
def get_sessions_for_user(event, user):
    sessions = (Session.query.with_parent(event)
                .options(joinedload('acl_entries'))
                .filter(Session.acl_entries.any(SessionPrincipal.has_management_role('coordinate')),
                        ~Session.is_deleted)
                .all())
    return {sess for sess in sessions if any(user in entry.principal for entry in iter_acl(sess.acl_entries))}
示例#5
0
    def can_access(self, user, acl_attr='acl', legacy_method='canAccess', allow_admin=True):
        """Checks if the user can access the object.

        When using a custom `acl_attr` on an object that supports
        inherited proection, ALL possible `protection_parent` objects
        need to have an ACL with the same name too!

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param acl_attr: The name of the property that contains the
                         set of authorized principals.
        :param legacy_method: The method name to use when inheriting
                              the protection from a legacy object.
        :param allow_admin: If admin users should always have access
        """

        # Trigger signals for protection overrides
        rv = values_from_signal(signals.acl.can_access.send(type(self), obj=self, user=user, acl_attr=acl_attr,
                                                            legacy_method=legacy_method, allow_admin=allow_admin),
                                single_value=True)
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            return True

        if self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            return True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            return any(user in principal for principal in iter_acl(getattr(self, acl_attr)))
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection.
            # the parent can be either an object inheriting from this
            # mixin or a legacy object with an AccessController
            parent = self.protection_parent
            if parent is None:
                # This should be the case for the top-level object,
                # i.e. the root category, which shouldn't allow
                # ProtectionMode.inheriting as it makes no sense.
                raise TypeError('protection_parent of {} is None'.format(self))
            elif hasattr(parent, 'can_access'):
                return parent.can_access(user, acl_attr=acl_attr)
            elif legacy_method is not None and hasattr(parent, legacy_method):
                return getattr(parent, legacy_method)(AccessWrapper(user.as_avatar if user else None))
            else:
                raise TypeError('protection_parent of {} is of invalid type {} ({})'.format(self, type(parent), parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError('Invalid protection mode: {}'.format(self.protection_mode))
示例#6
0
def test_iter_acl():
    user = MagicMock(is_group=False, spec=['is_group'])
    user_p = MagicMock(principal=user, spec=['principal'])
    local_group = MagicMock(is_group=True, is_local=True, spec=['is_local'])
    local_group_p = MagicMock(principal=local_group, spec=['principal'])
    remote_group = MagicMock(is_group=True, is_local=False, spec=['is_local'])
    remote_group_p = MagicMock(principal=remote_group, spec=['principal'])
    acl = [user_p, remote_group, local_group_p, user, local_group, remote_group_p]
    assert list(iter_acl(iter(acl))) == [user_p, user, local_group_p, local_group, remote_group, remote_group_p]
示例#7
0
    def contains_user(self, name, user):
        """Checks if a user is in an ACL.

        To pass this check, the user can either be in the ACL itself
        or in a group in the ACL.

        :param name: Setting name
        :param user: A :class:`.User`
        """
        return any(user in principal for principal in iter_acl(self.get(name)))
示例#8
0
def test_iter_acl():
    user = User()
    user_p = MagicMock(principal=user, spec=['principal'])
    ipn = IPNetworkGroup()
    ipn_p = MagicMock(principal=ipn, spec=['principal'])
    local_group = GroupProxy(123, _group=MagicMock())
    local_group_p = MagicMock(principal=local_group, spec=['principal'])
    remote_group = GroupProxy('foo', 'bar')
    remote_group_p = MagicMock(principal=remote_group, spec=['principal'])
    acl = [ipn, user_p, remote_group, local_group_p, user, local_group, remote_group_p, ipn_p]
    assert list(iter_acl(iter(acl))) == [user_p, user,
                                         ipn, ipn_p,
                                         local_group_p, local_group,
                                         remote_group, remote_group_p]
示例#9
0
    def can_be_overridden(self, user, room=None, explicit_only=False):
        """Determines if a user can override the blocking

        The following persons are authorized to override a blocking:
        - owner (the one who created the blocking)
        - any users on the blocking's ACL
        - unless explicitOnly is set: admins and room owners (if a room is given)
        """
        if not user:
            return False
        if self.created_by_user == user:
            return True
        if not explicit_only:
            if rb_is_admin(user):
                return True
            elif room and room.is_owned_by(user):
                return True
        return any(user in principal for principal in iter_acl(self.allowed))
示例#10
0
    def can_override(self, user, room=None, explicit_only=False, allow_admin=True):
        """Check if a user can override the blocking

        The following persons are authorized to override a blocking:
        - the creator of the blocking
        - anyone on the blocking's ACL
        - unless explicit_only is set: rb admins and room managers (if a room is given)
        """
        if not user:
            return False
        if self.created_by_user == user:
            return True
        if not explicit_only:
            if allow_admin and rb_is_admin(user):
                return True
            if room and room.can_manage(user):
                return True
        return any(user in principal for principal in iter_acl(self.allowed))
示例#11
0
def test_iter_acl():
    user = MagicMock(is_group=False, spec=['is_group'])
    local_group = MagicMock(is_group=True, is_local=True)
    remote_group = MagicMock(is_group=True, is_local=False)
    acl = [remote_group, user, local_group]
    assert list(iter_acl(iter(acl))) == [user, local_group, remote_group]
示例#12
0
    def can_manage(self, user, role=None, allow_admin=True, check_parent=True, explicit_role=False):
        """Checks if the user can manage the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param: role: The management role that is needed for the
                      check to succeed.  If not specified, full
                      management privs are required.  May be set to
                      the string ``'ANY'`` to check if the user has
                      any management privileges.  If the user has
                      `full_access` privileges, he's assumed to have
                      all possible roles.
        :param allow_admin: If admin users should always have access
        :param check_parent: If the parent object should be checked.
                             In this case the role is ignored; only
                             full management access is inherited to
                             children.
        :param explicit_role: If the specified role should be checked
                              explicitly instead of short-circuiting
                              the check for Indico admins or managers.
                              When this option is set to ``True``, the
                              values of `allow_admin` and `check_parent`
                              are ignored.  This also applies if `role`
                              is None in which case this argument being
                              set to ``True`` is equivalent to
                              `allow_admin` and `check_parent` being set
                              to ``False``.
        """
        if role is not None and role != 'ANY' and role not in get_available_roles(type(self)):
            raise ValueError("role '{}' is not valid for '{}' objects".format(role, type(self).__name__))

        if user is None:
            # An unauthorized user is never allowed to perform management operations.
            # Not even signals may override this since management code generally
            # expects session.user to be not None.
            # XXX: Legacy modification keys are checked outside
            return False

        # Trigger signals for protection overrides
        rv = values_from_signal(signals.acl.can_manage.send(type(self), obj=self, user=user, role=role,
                                                            allow_admin=allow_admin, check_parent=check_parent,
                                                            explicit_role=explicit_role),
                                single_value=True)
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if not explicit_role and allow_admin and user.is_admin:
            return True

        if any(user in entry.principal
               for entry in iter_acl(self.acl_entries)
               if entry.has_management_role(role, explicit=(explicit_role and role is not None))):
            return True

        if not check_parent or explicit_role:
            return False

        # the parent can be either an object inheriting from this
        # mixin or a legacy object with an AccessController
        parent = self.protection_parent
        if parent is None:
            # This should be the case for the top-level object,
            # i.e. the root category
            return False
        elif hasattr(parent, 'can_manage'):
            return parent.can_manage(user, allow_admin=allow_admin)
        elif hasattr(parent, 'canUserModify'):
            return parent.canUserModify(user.as_avatar)
        else:
            raise TypeError('protection_parent of {} is of invalid type {} ({})'.format(self, type(parent), parent))
示例#13
0
    def can_manage(self,
                   user,
                   permission=None,
                   allow_admin=True,
                   check_parent=True,
                   explicit_permission=False):
        """Checks if the user can manage the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param: permission: The management permission that is needed for
                            the check to succeed.  If not specified, full
                            management privs are required.  May be set to
                            the string ``'ANY'`` to check if the user has
                            any management privileges.  If the user has
                            `full_access` privileges, he's assumed to have
                            all possible permissions.
        :param allow_admin: If admin users should always have access
        :param check_parent: If the parent object should be checked.
                             In this case the permission is ignored; only
                             full management access is inherited to
                             children.
        :param explicit_permission: If the specified permission should be checked
                                    explicitly instead of short-circuiting
                                    the check for Indico admins or managers.
                                    When this option is set to ``True``, the
                                    values of `allow_admin` and `check_parent`
                                    are ignored.  This also applies if `permission`
                                    is None in which case this argument being
                                    set to ``True`` is equivalent to
                                    `allow_admin` and `check_parent` being set
                                    to ``False``.
        """
        if permission is not None and permission != 'ANY' and permission not in get_available_permissions(
                type(self)):
            raise ValueError(
                "permission '{}' is not valid for '{}' objects".format(
                    permission,
                    type(self).__name__))

        if user is None:
            # An unauthorized user is never allowed to perform management operations.
            # Not even signals may override this since management code generally
            # expects session.user to be not None.
            return False

        # Trigger signals for protection overrides
        rv = values_from_signal(signals.acl.can_manage.send(
            type(self),
            obj=self,
            user=user,
            permission=permission,
            allow_admin=allow_admin,
            check_parent=check_parent,
            explicit_permission=explicit_permission),
                                single_value=True)
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if not explicit_permission and allow_admin and user.is_admin:
            return True

        if any(user in entry.principal for entry in iter_acl(self.acl_entries)
               if entry.has_management_permission(
                   permission,
                   explicit=(explicit_permission and permission is not None))):
            return True

        if not check_parent or explicit_permission:
            return False

        # the parent can be either an object inheriting from this
        # mixin or a legacy object with an AccessController
        parent = self.protection_parent
        if parent is None:
            # This should be the case for the top-level object,
            # i.e. the root category
            return False
        elif hasattr(parent, 'can_manage'):
            return parent.can_manage(user, allow_admin=allow_admin)
        else:
            raise TypeError(
                'protection_parent of {} is of invalid type {} ({})'.format(
                    self, type(parent), parent))
示例#14
0
    def can_access(self, user, allow_admin=True):
        """Checks if the user can access the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param allow_admin: If admin users should always have access
        """

        override = self._check_can_access_override(user,
                                                   allow_admin=allow_admin)
        if override is not None:
            return override

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            rv = True
        # If there's a valid access key we can skip all other ACL checks
        elif self.allow_access_key and self.check_access_key():
            rv = True
        elif self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            rv = True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            if any(user in entry.principal
                   for entry in iter_acl(self.acl_entries)):
                rv = True
            elif isinstance(self, ProtectionManagersMixin):
                rv = self.can_manage(user, allow_admin=allow_admin)
            else:
                rv = False
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection
            # unless `inheriting_have_acl` is set, in which case we
            # might not need to check the parents at all
            if self.inheriting_have_acl and any(
                    user in entry.principal
                    for entry in iter_acl(self.acl_entries)):
                rv = True
            else:
                # the parent can be either an object inheriting from this
                # mixin or a legacy object with an AccessController
                parent = self.protection_parent
                if parent is None:
                    # This should be the case for the top-level object,
                    # i.e. the root category, which shouldn't allow
                    # ProtectionMode.inheriting as it makes no sense.
                    raise TypeError(
                        'protection_parent of {} is None'.format(self))
                elif hasattr(parent, 'can_access'):
                    rv = parent.can_access(user, allow_admin=allow_admin)
                else:
                    raise TypeError(
                        'protection_parent of {} is of invalid type {} ({})'.
                        format(self, type(parent), parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError('Invalid protection mode: {}'.format(
                self.protection_mode))

        override = self._check_can_access_override(user,
                                                   allow_admin=allow_admin,
                                                   authorized=rv)
        return override if override is not None else rv
示例#15
0
    def can_access(self, user, allow_admin=True):
        """Checks if the user can access the object.

        :param user: The :class:`.User` to check. May be None if the
                     user is not logged in.
        :param allow_admin: If admin users should always have access
        """

        # Trigger signals for protection overrides
        rv = values_from_signal(signals.acl.can_access.send(
            type(self), obj=self, user=user, allow_admin=allow_admin),
                                single_value=True)
        if rv:
            # in case of contradictory results (shouldn't happen at all)
            # we stay on the safe side and deny access
            return all(rv)

        # Usually admins can access everything, so no need for checks
        if allow_admin and user and user.is_admin:
            return True

        if self.protection_mode == ProtectionMode.public:
            # if it's public we completely ignore the parent protection
            # this is quite ugly which is why it should only be allowed
            # in rare cases (e.g. events which might be in a protected
            # category but should be public nonetheless)
            return True
        elif self.protection_mode == ProtectionMode.protected:
            # if it's protected, we also ignore the parent protection
            # and only check our own ACL
            if user is None:
                return False
            elif any(user in entry.principal
                     for entry in iter_acl(self.acl_entries)):
                return True
            elif isinstance(self, ProtectionManagersMixin):
                return self.can_manage(user, allow_admin=allow_admin)
            else:
                return False
        elif self.protection_mode == ProtectionMode.inheriting:
            # if it's inheriting, we only check the parent protection
            # unless `inheriting_have_acl` is set, in which case we
            # might not need to check the parents at all
            if (self.inheriting_have_acl and user is not None
                    and any(user in entry.principal
                            for entry in iter_acl(self.acl_entries))):
                return True
            # the parent can be either an object inheriting from this
            # mixin or a legacy object with an AccessController
            parent = self.protection_parent
            if parent is None:
                # This should be the case for the top-level object,
                # i.e. the root category, which shouldn't allow
                # ProtectionMode.inheriting as it makes no sense.
                raise TypeError('protection_parent of {} is None'.format(self))
            elif hasattr(parent, 'can_access'):
                return parent.can_access(user, allow_admin=allow_admin)
            elif hasattr(parent, 'canAccess'):
                return parent.canAccess(
                    AccessWrapper(user.as_avatar if user else None))
            else:
                raise TypeError(
                    'protection_parent of {} is of invalid type {} ({})'.
                    format(self, type(parent), parent))
        else:
            # should never happen, but since this is a sensitive area
            # we better fail loudly if we have garbage
            raise ValueError('Invalid protection mode: {}'.format(
                self.protection_mode))