From e0594d5b33800e87b4a2c4b7a387081917a95665 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Mon, 30 Sep 2024 21:13:00 +0200 Subject: [PATCH] permit_overwrite_collection doc + rights + test cases --- DOCUMENTATION.md | 9 +++++++++ radicale/app/put.py | 8 ++++++++ radicale/tests/test_base.py | 24 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 46a9cd23..42f489e1 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -916,6 +916,15 @@ Global control of permission to delete complete collection (default: True) If False it can be permitted by permissions per section with: D If True it can be forbidden by permissions per section with: d +##### permit_overwrite_collection + +(New since 3.3.0) + +Global control of permission to overwrite complete collection (default: False) + +If False it can be permitted by permissions per section with: O +If True it can be forbidden by permissions per section with: o + #### storage ##### type diff --git a/radicale/app/put.py b/radicale/app/put.py index 15a7e00d..710e4435 100644 --- a/radicale/app/put.py +++ b/radicale/app/put.py @@ -177,6 +177,14 @@ class ApplicationPartPut(ApplicationBase): if write_whole_collection: if ("w" if tag else "W") not in access.permissions: return httputils.NOT_ALLOWED + if not self._permit_overwrite_collection: + if ("O") not in access.permissions: + logger.info("overwrite of collection is prevented by config/option [rights] permit_overwrite_collection and not explicit allowed by permssion 'O': %s", path) + return httputils.NOT_ALLOWED + else: + if ("o") in access.permissions: + logger.info("overwrite of collection is allowed by config/option [rights] permit_overwrite_collection but explicit forbidden by permission 'o': %s", path) + return httputils.NOT_ALLOWED elif "w" not in access.parent_permissions: return httputils.NOT_ALLOWED diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index afc15f9d..cfcd2d0c 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -488,6 +488,30 @@ permissions: RrWw""") self.get("/calendar.ics/", check=404) self.get("/event1.ics", 404) + def test_overwrite_collection_global_forbid(self) -> None: + """Overwrite a collection (expect forbid).""" + self.configure({"rights": {"permit_overwrite_collection": False}}) + event = get_file_content("event1.ics") + self.put("/calender.ics/", event, check=401) + + def test_overwrite_collection_global_forbid_explict_permit(self) -> None: + """Overwrite a collection with permitted path (expect permit).""" + self.configure({"rights": {"permit_overwrite_collection": False}}) + event = get_file_content("event1.ics") + self.put("/test-permit-overwrite/", event, check=201) + + def test_overwrite_collection_global_permit(self) -> None: + """Overwrite a collection (expect permit).""" + self.configure({"rights": {"permit_overwrite_collection": True}}) + event = get_file_content("event1.ics") + self.put("/calender.ics/", event, check=201) + + def test_overwrite_collection_global_permit_explict_forbid(self) -> None: + """Overwrite a collection with forbidden path (expect forbid).""" + self.configure({"rights": {"permit_overwrite_collection": True}}) + event = get_file_content("event1.ics") + self.put("/test-forbid-overwrite/", event, check=401) + def test_propfind(self) -> None: calendar_path = "/calendar.ics/" self.mkcalendar("/calendar.ics/")