Skip to content

Commit

Permalink
Add ability to disable explicit permissions at object level (ref #893)
Browse files Browse the repository at this point in the history
  • Loading branch information
leplatrem committed Oct 6, 2020
1 parent 02a9545 commit 1646147
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ This document describes changes between each past release.
14.0.2 (unreleased)
-------------------

**New feature**

- Add ability to disable explicit permissions at object level (ref #893). Use ``kinto.explicit_permissions = false`` to only rely on inherited permissions (see settings docs)

**Internal Changes**

- Distinguish readonly errors in storage backend (``kinto.core.storage.exceptions.ReadonlyError``)
Expand Down
3 changes: 2 additions & 1 deletion kinto/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"eos": None,
"eos_message": None,
"eos_url": None,
"explicit_permissions": True,
"error_info_link": "https://github.com/Kinto/kinto/issues/",
"http_host": None,
"http_scheme": None,
Expand Down Expand Up @@ -155,7 +156,7 @@ def includeme(config):
config.registry.heartbeats = {}

# Public settings registry.
config.registry.public_settings = {"batch_max_requests", "readonly"}
config.registry.public_settings = {"batch_max_requests", "readonly", "explicit_permissions"}

# Directive to declare arbitrary API capabilities.
def add_api_capability(config, identifier, description="", url="", **kw):
Expand Down
2 changes: 2 additions & 0 deletions kinto/core/resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
HTTPServiceUnavailable,
)
from pyramid.security import Everyone
from pyramid.settings import asbool

from kinto.core import Service
from kinto.core.errors import ERRORS, http_error, raise_invalid, request_GET, send_alert
Expand Down Expand Up @@ -209,6 +210,7 @@ def __init__(self, request, context=None):
parent_id=parent_id,
current_principal=current_principal,
prefixed_principals=request.prefixed_principals,
explicit_perm=asbool(request.registry.settings["explicit_permissions"]),
)

# Initialize timestamp as soon as possible.
Expand Down
11 changes: 10 additions & 1 deletion kinto/core/resource/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def __init__(
parent_id="",
current_principal=None,
prefixed_principals=None,
explicit_perm=True,
):
"""
:param storage: an instance of storage
Expand All @@ -44,6 +45,12 @@ def __init__(
:param str resource_name: the resource name
:param str parent_id: the default parent id
:param bool explicit_perm:
Without explicit permissions, the ACLs on the object will
fully depend on the inherited permission tree (eg. read/write on parent).
This basically means that if user loose the permission on the
parent, they also loose the permission on children.
See https://github.com/Kinto/kinto/issues/893
"""
self.storage = storage
self.permission = permission
Expand All @@ -52,6 +59,7 @@ def __init__(
self.resource_name = resource_name
self.current_principal = current_principal
self.prefixed_principals = prefixed_principals
self.explicit_perm = explicit_perm

# Object permission id.
self.get_permission_object_id = None
Expand Down Expand Up @@ -81,7 +89,8 @@ def _annotate(self, obj, perm_object_id):

def _allow_write(self, perm_object_id):
"""Helper to give the ``write`` permission to the current user."""
self.permission.add_principal_to_ace(perm_object_id, "write", self.current_principal)
if self.explicit_perm:
self.permission.add_principal_to_ace(perm_object_id, "write", self.current_principal)

def get_objects(
self,
Expand Down
10 changes: 9 additions & 1 deletion kinto/plugins/history/listener.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime, timezone

from pyramid.settings import aslist
from pyramid.settings import asbool, aslist

from kinto.core.utils import instance_uri

Expand Down Expand Up @@ -109,6 +109,14 @@ def on_resource_changed(event):
# Note: this will be rolledback if the transaction is rolledback.
entry = storage.create(parent_id=bucket_uri, resource_name="history", obj=attrs)

# Without explicit permissions, the ACLs on the history entries will
# fully depend on the inherited permission tree (eg. bucket:read, bucket:write).
# This basically means that if user loose the permissions on the related
# object, they also loose the permission on the history entry.
# See https://github.com/Kinto/kinto/issues/893
if not asbool(settings["explicit_permissions"]):
return

# The read permission on the newly created history entry is the union
# of the object permissions with the one from bucket and collection.
entry_principals = set(read_principals)
Expand Down
2 changes: 1 addition & 1 deletion tests/core/resource/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_raise_unavailable_if_fail_to_obtain_timestamp_with_readonly(self):

excepted_exc = httpexceptions.HTTPServiceUnavailable

request.registry.settings = {"readonly": "true"}
request.registry.settings = {"readonly": "true", "explicit_permissions": "true"}
with mock.patch.object(
request.registry.storage,
"resource_timestamp",
Expand Down
2 changes: 1 addition & 1 deletion tests/core/test_views_hello.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_returns_eos_if_not_empty_in_settings(self):
def test_public_settings_are_shown_in_view(self):
response = self.app.get("/")
settings = response.json["settings"]
expected = {"batch_max_requests": 25, "readonly": False}
expected = {"batch_max_requests": 25, "readonly": False, "explicit_permissions": True}
self.assertEqual(expected, settings)

def test_public_settings_can_be_set_from_registry(self):
Expand Down

0 comments on commit 1646147

Please sign in to comment.