*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Commit d31411d0 authored by Moser, Maximilian's avatar Moser, Maximilian
Browse files

Update permissions

* Refactor permissions into separate module
* Add custom overrides for permission generators
* Add custom file download view, using the new embargo permission
  generator
parent 7d16c433
Branches
Tags
No related merge requests found
......@@ -9,7 +9,8 @@
try:
from flask_babelex import gettext as _
except:
except ModuleNotFoundError:
def _(x):
"""Dummy string translation."""
......@@ -33,14 +34,6 @@ FLASK_RUN_HOST = "0.0.0.0"
FLASK_RUN_PORT = "443"
# Flask-SQLAlchemy
# ================
# See https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/
SQLALCHEMY_DATABASE_URI = (
"postgresql+psycopg2://tu-data-test:tu-data-test@localhost/tu-data-test"
)
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
......@@ -199,69 +192,46 @@ USERPROFILES_EXTEND_SECURITY_FORMS = True
THEME_SITEURL = "https://researchdata.dl.hpc.tuwien.ac.at"
try:
from invenio_rdm_records.services import (
BibliographicRecordServiceConfig,
RDMRecordPermissionPolicy,
)
from invenio_records_permissions.generators import (
Admin,
AnyUser,
AnyUserIfPublic,
RecordOwners,
SuperUser,
)
# override the view for downloading files, to check for permissions
recid_files = {
"pid_type": "recid",
"record_class": "invenio_rdm_records.records:BibliographicRecord",
"route": "/records/<pid_value>/files/<path:filename>",
"view_imp": "invenio_config_tuw.views.file_download_ui",
}
# TODO remove -- they are currently in place because the original generators fail ('record' argument isn't passed)
class RecordOwners(RecordOwners):
"""Allows record owners."""
def needs(self, **kwargs):
"""Enabling Needs."""
return []
def query_filter(self, **kwargs):
"""Search filter."""
return []
class AnyUserIfPublic(AnyUserIfPublic):
"""Allows anybody if the record is public."""
def needs(self, **kwargs):
"""Enabling Needs."""
return []
def query_filter(self, **kwargs):
"""Search filter."""
return []
class TUWRecordPermissionPolicy(RDMRecordPermissionPolicy):
# fmt: off
can_create = [ Admin(), SuperUser()]
can_publish = [ RecordOwners(), Admin(), SuperUser()]
can_update = [ RecordOwners(), Admin(), SuperUser()]
can_update_draft = [ RecordOwners(), Admin(), SuperUser()]
can_update_files = [ RecordOwners(), Admin(), SuperUser()]
can_delete = [ Admin(), SuperUser()]
can_delete_draft = [ RecordOwners(), Admin(), SuperUser()]
can_read = [AnyUser(), Admin(), SuperUser()]
can_read_draft = [ RecordOwners(), Admin(), SuperUser()]
can_read_files = [AnyUserIfPublic(), RecordOwners(), Admin(), SuperUser()]
can_search = [AnyUser(), ]
# fmt: on
class TUWBibliographicRecordServiceConfig(BibliographicRecordServiceConfig):
permission_policy_cls = TUWRecordPermissionPolicy
try:
from invenio_theme_tuw.config import RECORDS_UI_ENDPOINTS
except ModuleNotFoundError:
from invenio_rdm_records.config import RECORDS_UI_ENDPOINTS
RECORDS_UI_ENDPOINTS.get("recid_files", {}).update(recid_files)
except Exception as e:
print(e)
try:
# override the permissions with our own
from .permissions import TUWBibliographicRecordServiceConfig
RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = TUWBibliographicRecordServiceConfig
except:
pass
RDM_RECORDS_BIBLIOGRAPHIC_DRAFT_FILES_SERVICE_CONFIG = (
TUWBibliographicRecordServiceConfig
)
RDM_RECORDS_BIBLIOGRAPHIC_RECORD_FILES_SERVICE_CONFIG = (
TUWBibliographicRecordServiceConfig
)
except Exception as e:
print(e)
# Invenio-PIDStore
# ================
# See https://invenio-pidstore.readthedocs.io/en/latest/configuration.html
# Note: the password has to be provided somewhere else (invenio.cfg, environment variable, ...)
# Note: the password has to be provided somewhere else
# (e.g. invenio.cfg, environment variable, ...)
PIDSTORE_DATACITE_USERNAME = "TUW.TUDATA"
PIDSTORE_DATACITE_PASSWORD = None
PIDSTORE_DATACITE_DOI_PREFIX = "10.48436"
......
import logging
import arrow
from invenio_access.permissions import any_user
from invenio_rdm_records.services import RDMRecordPermissionPolicy
from invenio_rdm_records.services.services import BibliographicRecordFilesServiceConfig
from invenio_records_permissions.generators import (
Admin,
AnyUser,
AnyUserIfPublic,
RecordOwners,
SuperUser,
)
class RecordOwners(RecordOwners):
"""Allows record owners."""
def needs(self, **kwargs):
"""Enabling Needs."""
if "record" in kwargs:
return super().needs(**kwargs)
logging.warn("no record supplied while checking for RecordOwners")
return []
def excludes(self, **kwargs):
"""Preventing Needs."""
if "record" in kwargs:
return super().excludes(**kwargs)
return []
def query_filter(self, **kwargs):
"""Search filter."""
if "record" in kwargs:
return super().query_filter(**kwargs)
return []
class AnyUserIfPublic(AnyUserIfPublic):
"""Allows anybody if the record is public."""
def is_open(self, record):
"""Check if the record is open or closed (or embargoed) access."""
if record is None:
return False
access = record.get("access", {})
embargo = access.get("embargo_date", None)
access_right = access.get("access_right", "closed")
# check if there's an embargo or the access isn't open
if embargo is None and access_right == "open":
return True
elif access_right != "open":
return False
# the access right is open, but we still have to check the embargo
if arrow.get(embargo).date() < arrow.utcnow().date():
return True
else:
return False
def needs(self, **kwargs):
"""Enabling Needs."""
if self.is_open(kwargs.get("record")):
return [any_user]
return []
def query_filter(self, **kwargs):
"""Search filter."""
return []
class TUWRecordPermissionPolicy(RDMRecordPermissionPolicy):
# fmt: off
can_create = [ Admin(), SuperUser()] # noqa
can_publish = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_update = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_update_draft = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_update_files = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_delete = [ Admin(), SuperUser()] # noqa
can_delete_draft = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_read = [AnyUser(), Admin(), SuperUser()] # noqa
can_read_draft = [ RecordOwners(), Admin(), SuperUser()] # noqa
can_read_files = [AnyUserIfPublic(), RecordOwners(), Admin(), SuperUser()] # noqa
can_search = [AnyUser(), ] # noqa
# fmt: on
class TUWBibliographicRecordServiceConfig(BibliographicRecordFilesServiceConfig):
permission_policy_cls = TUWRecordPermissionPolicy
"""Utility functions."""
from flask_principal import Identity
from invenio_access import any_user
from invenio_access.utils import get_identity
from invenio_accounts import current_accounts
def get_identity_for_user(user):
"""Get the Identity for the user specified via email or ID."""
identity = None
if user is not None:
# note: this seems like the canonical way to go
# 'as_user' can be either an integer (id) or email address
u = current_accounts.datastore.get_user(user)
if u is not None:
identity = get_identity(u)
else:
raise LookupError("user not found: %s" % user)
if identity is None:
identity = Identity(1)
identity.provides.add(any_user)
return identity
from flask import abort, request
from flask_security import current_user
from invenio_files_rest.views import ObjectResource
from invenio_rdm_records.services.services import BibliographicRecordFilesService
from invenio_rdm_records.utils import previewer_record_file_factory
from invenio_records_resources.services.errors import PermissionDeniedError
from .utils import get_identity_for_user
def file_download_ui(pid, record, _record_file_factory=None, **kwargs):
"""File download view for a given record.
If ``download`` is passed as a querystring argument, the file is sent as an
attachment.
:param pid: The persistent identifier instance.
:param record: The record metadata.
"""
_record_file_factory = _record_file_factory or previewer_record_file_factory
# Extract file from record.
fileobj = _record_file_factory(pid, record, kwargs.get("filename"))
if not fileobj:
abort(404)
obj = fileobj.obj
service = BibliographicRecordFilesService()
try:
try:
identity = get_identity_for_user(current_user.id)
except AttributeError:
identity = get_identity_for_user(None)
service.require_permission(identity, "read_files", record=record)
except PermissionDeniedError:
abort(403)
# Check permissions
# ObjectResource.check_object_permission(obj)
# Send file.
return ObjectResource.send_object(
obj.bucket,
obj,
expected_chksum=fileobj.get("checksum"),
logger_data={
"bucket_id": obj.bucket_id,
"pid_type": pid.pid_type,
"pid_value": pid.pid_value,
},
as_attachment=("download" in request.args),
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment