Source code for invenio_records_permissions.policies.base
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019-2020 CERN.
# Copyright (C) 2019-2020 Northwestern University.
#
# Invenio-Records-Permissions is free software; you can redistribute it
# and/or modify it under the terms of the MIT License; see LICENSE file for
# more details.
"""Base access controls."""
from itertools import chain
from invenio_access import Permission
from invenio_access.permissions import superuser_access
from invenio_search.engine import dsl
from ..generators import Disable
# Where can a property be used?
#
# | Action | need | excludes | query_filters |
# |-------------|------|----------|---------------|
# | create | x | x | |
# |-------------|------|----------|---------------|
# | list | x | x | |
# |-------------|------|----------|---------------|
# | read | x | x | x |
# |-------------|------|----------|---------------|
# | read files | x | x | TODO: revisit |
# |-------------|------|----------|---------------|
# | update | x | x | |
# |-------------|------|----------|---------------|
# | delete | x | x | |
# |-------------|------|----------|---------------|
#
[docs]class BasePermissionPolicy(Permission):
"""
BasePermissionPolicy to inherit from.
The class defines the overall policy and the instance encapsulates the
permissions for an *action* *over* a set of objects.
If `can_<self.action>`
is not defined, no one is allowed (Disable()).
is an empty list, only Super Users are allowed (via NOTE above).
"""
can_search = []
can_create = []
can_read = []
can_update = []
can_delete = []
def __init__(self, action, **over):
"""Constructor."""
super().__init__()
self.action = action
self.over = over
@property
def generators(self):
"""List of Needs generators for self.action.
Defaults to Disable() if no can_<self.action> defined.
"""
return getattr(self.__class__, "can_" + self.action, [Disable()])
@property
def needs(self):
"""Set of Needs granting permission.
If ANY of the Needs are matched, permission is granted.
.. note::
``_load_permissions()`` method from `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ adds by default the
``superuser_access`` Need (if tied to a User or Role) for us.
It also expands ActionNeeds into the Users/Roles that
provide them.
"""
needs = [generator.needs(**self.over) for generator in self.generators]
self.explicit_needs |= set(chain.from_iterable(needs))
self._load_permissions() # self.explicit_needs is used here
return self._permissions.needs
@property
def excludes(self):
"""Set of Needs denying permission.
If ANY of the Needs are matched, permission is revoked.
.. note::
``_load_permissions()`` method from `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ adds by default the
``superuser_access`` Need (if tied to a User or Role) for us.
It also expands ActionNeeds into the Users/Roles that
provide them.
If the same Need is returned by `needs` and `excludes`, then that
Need provider is disallowed.
"""
excludes = [generator.excludes(**self.over) for generator in self.generators]
self.explicit_excludes |= set(chain.from_iterable(excludes))
self._load_permissions() # self.explicit_excludes is used here
return self._permissions.excludes
def _query_filters_superuser(self, filters):
"""Allow superuser identity to retrieve all results."""
identity = self.over.get("identity")
identity_provides = identity.provides if identity else set()
# expand action to resolve needs
expanded = self._expand_action(superuser_access)
superuser_needs = expanded.needs if expanded else set()
is_superuser = superuser_needs & identity_provides
if is_superuser:
filters.append(dsl.Q("match_all"))
return filters
@property
def query_filters(self):
"""List of search engine query filters.
These filters consist of additive queries mapping to what the current
user should be able to retrieve via search.
"""
filters = [generator.query_filter(**self.over) for generator in self.generators]
filters = self._query_filters_superuser(filters)
return [f for f in filters if f]