mirror of
https://github.com/Kozea/Radicale.git
synced 2025-04-07 07:07:36 +03:00
Merge pull request #1585 from pbiering/add-permit_overwrite_collection
Add option permit_overwrite_collection
This commit is contained in:
commit
e59e4d3aff
8 changed files with 67 additions and 4 deletions
|
@ -5,6 +5,7 @@
|
|||
* Adjustment: option [auth] htpasswd_encryption change default from "md5" to "autodetect"
|
||||
* Add: option [auth] type=ldap with (group) rights management via LDAP/LDAPS
|
||||
* Enhancement: permit_delete_collection can be now controlled also per collection by rights 'D' or 'd'
|
||||
* Add: option [rights] permit_overwrite_collection (default=True) which can be also controlled per collection by rights 'O' or 'o'
|
||||
|
||||
## 3.2.3
|
||||
* Add: support for Python 3.13
|
||||
|
|
|
@ -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: True)
|
||||
|
||||
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
|
||||
|
@ -1300,6 +1309,8 @@ The following `permissions` are recognized:
|
|||
* **w:** write address book and calendar collections
|
||||
* **D:** permit delete of collection in case permit_delete_collection=False
|
||||
* **d:** forbid delete of collection in case permit_delete_collection=True
|
||||
* **O:** permit overwrite of collection in case permit_overwrite_collection=False
|
||||
* **o:** forbid overwrite of collection in case permit_overwrite_collection=True
|
||||
|
||||
### Storage
|
||||
|
||||
|
|
2
config
2
config
|
@ -115,6 +115,8 @@
|
|||
# Permit delete of a collection (global)
|
||||
#permit_delete_collection = True
|
||||
|
||||
# Permit overwrite of a collection (global)
|
||||
#permit_overwrite_collection = True
|
||||
|
||||
[storage]
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
|
|||
_auth_realm: str
|
||||
_extra_headers: Mapping[str, str]
|
||||
_permit_delete_collection: bool
|
||||
_permit_overwrite_collection: bool
|
||||
|
||||
def __init__(self, configuration: config.Configuration) -> None:
|
||||
"""Initialize Application.
|
||||
|
@ -91,6 +92,8 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
|
|||
self._auth_realm = configuration.get("auth", "realm")
|
||||
self._permit_delete_collection = configuration.get("rights", "permit_delete_collection")
|
||||
logger.info("permit delete of collection: %s", self._permit_delete_collection)
|
||||
self._permit_overwrite_collection = configuration.get("rights", "permit_overwrite_collection")
|
||||
logger.info("permit overwrite of collection: %s", self._permit_overwrite_collection)
|
||||
self._extra_headers = dict()
|
||||
for key in self.configuration.options("headers"):
|
||||
self._extra_headers[key] = configuration.get("headers", key)
|
||||
|
|
|
@ -40,6 +40,7 @@ class ApplicationBase:
|
|||
_web: web.BaseWeb
|
||||
_encoding: str
|
||||
_permit_delete_collection: bool
|
||||
_permit_overwrite_collection: bool
|
||||
_hook: hook.BaseHook
|
||||
|
||||
def __init__(self, configuration: config.Configuration) -> None:
|
||||
|
@ -125,7 +126,7 @@ class Access:
|
|||
|
||||
def check(self, permission: str,
|
||||
item: Optional[types.CollectionOrItem] = None) -> bool:
|
||||
if permission not in "rwdD":
|
||||
if permission not in "rwdDoO":
|
||||
raise ValueError("Invalid permission argument: %r" % permission)
|
||||
if not item:
|
||||
permissions = permission + permission.upper()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -245,6 +245,10 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
|
|||
"value": "True",
|
||||
"help": "permit delete of a collection",
|
||||
"type": bool}),
|
||||
("permit_overwrite_collection", {
|
||||
"value": "True",
|
||||
"help": "permit overwrite of a collection",
|
||||
"type": bool}),
|
||||
("file", {
|
||||
"value": "/etc/radicale/rights",
|
||||
"help": "file for rights management from_file",
|
||||
|
|
|
@ -41,7 +41,6 @@ class TestBaseRequests(BaseTest):
|
|||
def setup_method(self) -> None:
|
||||
BaseTest.setup_method(self)
|
||||
rights_file_path = os.path.join(self.colpath, "rights")
|
||||
self.configure({"rights": {"permit_delete_collection": True}})
|
||||
with open(rights_file_path, "w") as f:
|
||||
f.write("""\
|
||||
[permit delete collection]
|
||||
|
@ -54,6 +53,16 @@ user: .*
|
|||
collection: test-forbid-delete
|
||||
permissions: RrWwd
|
||||
|
||||
[permit overwrite collection]
|
||||
user: .*
|
||||
collection: test-permit-overwrite
|
||||
permissions: RrWwO
|
||||
|
||||
[forbid overwrite collection]
|
||||
user: .*
|
||||
collection: test-forbid-overwrite
|
||||
permissions: RrWwo
|
||||
|
||||
[allow all]
|
||||
user: .*
|
||||
collection: .*
|
||||
|
@ -450,8 +459,8 @@ permissions: RrWw""")
|
|||
assert responses["/calendar.ics/"] == 200
|
||||
self.get("/calendar.ics/", check=404)
|
||||
|
||||
def test_delete_collection_not_permitted(self) -> None:
|
||||
"""Delete a collection (try if not permitted)."""
|
||||
def test_delete_collection_global_forbid(self) -> None:
|
||||
"""Delete a collection (expect forbidden)."""
|
||||
self.configure({"rights": {"permit_delete_collection": False}})
|
||||
self.mkcalendar("/calendar.ics/")
|
||||
event = get_file_content("event1.ics")
|
||||
|
@ -488,6 +497,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/")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue