sharing: add global and conditional permissions support
This commit is contained in:
@@ -2102,6 +2102,40 @@ Share collection by map
|
||||
|
||||
Default: `false`
|
||||
|
||||
##### permit_create_token
|
||||
|
||||
_(>= 3.7.0)_
|
||||
|
||||
Permit create of token-based sharing
|
||||
|
||||
Default: `false`
|
||||
|
||||
* If `False` it can be explicitly granted by `permissions: t`
|
||||
* If `True` it can be explicitly forbidden by `permissions: T`
|
||||
|
||||
##### permit_create_map
|
||||
|
||||
_(>= 3.7.0)_
|
||||
|
||||
Permit create of map-based sharing
|
||||
|
||||
Default: `false`
|
||||
|
||||
* If `False` it can be explicitly granted by `permissions: m`
|
||||
* If `True` it can be explicitly forbidden by `permissions: M`
|
||||
|
||||
##### default_permissions_create_token
|
||||
|
||||
Default permissions for create token-based sharing
|
||||
|
||||
Default: `r`
|
||||
|
||||
##### default_permissions_create_map
|
||||
|
||||
Default permissions for map-based sharing
|
||||
|
||||
Default: `r`
|
||||
|
||||
## Supported Clients
|
||||
|
||||
Radicale has been tested with:
|
||||
@@ -2326,6 +2360,10 @@ The following `permissions` are recognized:
|
||||
* **d:** deny deleting a collection in case `permit_delete_collection=True` _(>= 3.3.0)_
|
||||
* **O:** allow overwriting a collection in case `permit_overwrite_collection=False` _(>= 3.3.0)_
|
||||
* **o:** deny overwriting a collection in case `permit_overwrite_collection=True` _(>= 3.3.0)_
|
||||
* **T:** permit create of token-based sharing of collection in case `permit_create_token=False` _(>= 3.7.0)_
|
||||
* **t:** deny create of token-based sharing of collection in case `permit_create_token=True` _(>= 3.7.0)_
|
||||
* **M:** permit create of map-based sharing of collection in case `permit_create_map= False` _(>= 3.7.0)_
|
||||
* **m:** deny create of map-based sharing of collection in case `permit_create_map=True` _(>= 3.7.0)_
|
||||
|
||||
### Storage
|
||||
|
||||
|
||||
16
config
16
config
@@ -317,6 +317,22 @@
|
||||
# Share collection by map
|
||||
#collection_by_map = false
|
||||
|
||||
# Permit create of token-based sharing
|
||||
# If False it can be explicitly granted by permissions: t
|
||||
# If True it can be explicitly forbidden by permissions: T
|
||||
#permit_create_token = false
|
||||
|
||||
# Permit create of map-based sharing
|
||||
# If False it can be explicitly granted by permissions: m
|
||||
# If True it can be explicitly forbidden by permissions: M
|
||||
#permit_create_map = false
|
||||
|
||||
# Default permissions for token-based sharing
|
||||
#default_permissions_create_token = r
|
||||
|
||||
# Default permissions for map-based sharing
|
||||
#default_permissions_create_map = r
|
||||
|
||||
|
||||
[web]
|
||||
|
||||
|
||||
@@ -482,7 +482,23 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
|
||||
("collection_by_map", {
|
||||
"value": "false",
|
||||
"help": "enable sharing of collection by map",
|
||||
"type": bool})])),
|
||||
"type": bool}),
|
||||
("permit_create_token", {
|
||||
"value": "false",
|
||||
"help": "permit create of token-based sharing",
|
||||
"type": bool}),
|
||||
("permit_create_map", {
|
||||
"value": "false",
|
||||
"help": "permit create of map-based sharing",
|
||||
"type": bool}),
|
||||
("default_permissions_create_token", {
|
||||
"value": "r",
|
||||
"help": "default permissions for token-based sharing",
|
||||
"type": rights_permission}),
|
||||
("default_permissions_create_map", {
|
||||
"value": "r",
|
||||
"help": "default permissions for map-based sharing",
|
||||
"type": rights_permission})])),
|
||||
("hook", OrderedDict([
|
||||
("type", {
|
||||
"value": "none",
|
||||
|
||||
@@ -31,6 +31,10 @@ Permissions:
|
||||
- d: deny deleting a collection in case permit_delete_collection=True (>= 3.3.0)
|
||||
- O: allow overwriting a collection in case permit_overwrite_collection=False (>= 3.3.0)
|
||||
- o: deny overwriting a collection in case permit_overwrite_collection=True (>= 3.3.0)
|
||||
- T: permit create of token-based sharing of collection in case permit_create_token=False (>= 3.7.0)
|
||||
- t: deny create of token-based sharing of collection in case permit_create_token=True (>= 3.7.0)
|
||||
- M: permit create of map-based sharing of collection in case permit_create_map= False (>= 3.7.0)
|
||||
- m: deny create of map-based sharing of collection in case permit_create_map=True (>= 3.7.0)
|
||||
|
||||
Take a look at the class ``BaseRights`` if you want to implement your own.
|
||||
|
||||
|
||||
@@ -102,8 +102,16 @@ class BaseSharing:
|
||||
# Sharing
|
||||
self.sharing_collection_by_map = configuration.get("sharing", "collection_by_map")
|
||||
self.sharing_collection_by_token = configuration.get("sharing", "collection_by_token")
|
||||
self.permit_create_token = configuration.get("sharing", "permit_create_token")
|
||||
self.permit_create_map = configuration.get("sharing", "permit_create_map")
|
||||
self.default_permissions_create_token = configuration.get("sharing", "default_permissions_create_token")
|
||||
self.default_permissions_create_map = configuration.get("sharing", "default_permissions_create_map")
|
||||
logger.info("sharing.collection_by_map : %s", self.sharing_collection_by_map)
|
||||
logger.info("sharing.collection_by_token: %s", self.sharing_collection_by_token)
|
||||
logger.info("sharing.permit_create_token: %s", self.permit_create_token)
|
||||
logger.info("sharing.permit_create_map : %s", self.permit_create_map)
|
||||
logger.info("sharing.default_permissions_create_token: %r", self.default_permissions_create_token)
|
||||
logger.info("sharing.default_permissions_create_map : %r", self.default_permissions_create_map)
|
||||
|
||||
if ((self.sharing_collection_by_map is False) and (self.sharing_collection_by_token is False)):
|
||||
logger.info("sharing disabled as no feature is enabled")
|
||||
@@ -634,7 +642,13 @@ class BaseSharing:
|
||||
if logger.isEnabledFor(logging.DEBUG):
|
||||
logger.debug("TRACE/" + api_info + ": start")
|
||||
if 'Permissions' not in request_data:
|
||||
Permissions = "r"
|
||||
if ShareType == "token":
|
||||
Permissions = self.default_permissions_create_token
|
||||
elif ShareType == "map":
|
||||
Permissions = self.default_permissions_create_map
|
||||
else:
|
||||
# default
|
||||
Permissions = "r"
|
||||
|
||||
if 'Enabled' in request_data:
|
||||
EnabledByOwner = config._convert_to_bool(request_data['Enabled'])
|
||||
@@ -652,10 +666,19 @@ class BaseSharing:
|
||||
if ShareType == "token":
|
||||
# check access Permissions
|
||||
access = Access(self._rights, user, str(PathMapped)) # PathMapped is mandatory
|
||||
if not access.check("r") and "i" not in access.permissions:
|
||||
if not access.check("r"):
|
||||
logger.info("Add sharing-by-token: access to %r not allowed for user %r", PathMapped, user)
|
||||
return httputils.NOT_ALLOWED
|
||||
|
||||
if self.permit_create_token is False:
|
||||
if "t" not in access.permissions:
|
||||
logger.info("Add sharing-by-token: access to %r not allowed for user %r (permit=False but explict grant misses 't')", PathMapped, user)
|
||||
return httputils.NOT_ALLOWED
|
||||
else:
|
||||
if "T" in access.permissions:
|
||||
logger.info("Add sharing-by-token: access to %r not allowed for user %r (permit=True but denied by 'T')", PathMapped, user)
|
||||
return httputils.NOT_ALLOWED
|
||||
|
||||
# v1: create uuid token with 2x 32 bytes = 256 bit
|
||||
token = "v1/" + str(base64.urlsafe_b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes), 'utf-8')
|
||||
|
||||
@@ -690,9 +713,18 @@ class BaseSharing:
|
||||
logger.info("Add sharing-by-map: access to path(mapped) %r not allowed for owner %r", PathMapped, Owner)
|
||||
return httputils.NOT_ALLOWED
|
||||
|
||||
if self.permit_create_map is False:
|
||||
if "m" not in access.permissions:
|
||||
logger.info("Add sharing-by-map: access to %r not allowed for user %r (permit=False but explicit grant misses 'm')", PathMapped, user)
|
||||
return httputils.NOT_ALLOWED
|
||||
else:
|
||||
if "M" in access.permissions:
|
||||
logger.info("Add sharing-by-map: access to %r not allowed for user %r (permit=True but denied by 'M')", PathMapped, user)
|
||||
return httputils.NOT_ALLOWED
|
||||
|
||||
access = Access(self._rights, str(User), PathOrToken)
|
||||
if not access.check("r") and "i" not in access.permissions:
|
||||
logger.info("Add sharing-by-map: access to path %r not allowed for user %r", PathOrToken, user)
|
||||
if not access.check("r"):
|
||||
logger.info("Add sharing-by-map: access to path %r not allowed for user %r", PathOrToken, User)
|
||||
return httputils.NOT_ALLOWED
|
||||
|
||||
# check whether share is already existing as real collection
|
||||
|
||||
Reference in New Issue
Block a user