Skip to content

Commit

Permalink
[Fixes #9106] Implement API for compact permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
afabiani committed Apr 14, 2022
1 parent 9311864 commit b850027
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 105 deletions.
31 changes: 23 additions & 8 deletions geonode/resource/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
from geonode.thumbs.thumbnails import _generate_thumbnail_name
from geonode.documents.tasks import create_document_thumbnail
from geonode.thumbs import utils as thumb_utils
from geonode.security.permissions import PermSpecCompact
from geonode.security.permissions import (
PermSpecCompact,
DATA_STYLABLE_RESOURCES_SUBTYPES)
from geonode.security.utils import (
perms_as_set,
get_user_groups,
Expand Down Expand Up @@ -614,7 +616,8 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
_resource.owner = owner
ResourceBase.objects.filter(uuid=_resource.uuid).update(owner=owner)
_owner = _resource.owner
_resource_type = _resource.resource_type or _resource.polymorphic_ctype.name
_resource_type = getattr(_resource, 'resource_type', None) or _resource.polymorphic_ctype.name
_resource_subtype = (getattr(_resource, 'subtype', None) or '').lower()

# default permissions for anonymous users
anonymous_group, _ = Group.objects.get_or_create(name='anonymous')
Expand Down Expand Up @@ -674,7 +677,10 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
if _resource_type == 'dataset' and perm in (
'change_dataset_data', 'change_dataset_style',
'add_dataset', 'change_dataset', 'delete_dataset'):
assign_perm(perm, anonymous_group, _resource.dataset)
if perm == 'change_dataset_style' and _resource_subtype not in DATA_STYLABLE_RESOURCES_SUBTYPES:
pass
else:
assign_perm(perm, anonymous_group, _resource.dataset)
elif AdvancedSecurityWorkflowManager.assignable_perm_condition(perm, _resource_type):
assign_perm(perm, anonymous_group, _resource.get_self_resource())

Expand All @@ -687,7 +693,10 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
if _resource_type == 'dataset' and perm in (
'change_dataset_data', 'change_dataset_style',
'add_dataset', 'change_dataset', 'delete_dataset'):
assign_perm(perm, _user, _resource.dataset)
if perm == 'change_dataset_style' and _resource_subtype not in DATA_STYLABLE_RESOURCES_SUBTYPES:
pass
else:
assign_perm(perm, _user, _resource.dataset)
elif AdvancedSecurityWorkflowManager.assignable_perm_condition(perm, _resource_type):
assign_perm(perm, _user, _resource.get_self_resource())

Expand All @@ -699,7 +708,10 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
if _resource_type == 'dataset' and perm in (
'change_dataset_data', 'change_dataset_style',
'add_dataset', 'change_dataset', 'delete_dataset'):
assign_perm(perm, _group, _resource.dataset)
if perm == 'change_dataset_style' and _resource_subtype not in DATA_STYLABLE_RESOURCES_SUBTYPES:
pass
else:
assign_perm(perm, _group, _resource.dataset)
elif AdvancedSecurityWorkflowManager.assignable_perm_condition(perm, _resource_type):
assign_perm(perm, _group, _resource.get_self_resource())

Expand All @@ -713,7 +725,10 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
if _resource_type == 'dataset' and perm in (
'change_dataset_data', 'change_dataset_style',
'add_dataset', 'change_dataset', 'delete_dataset'):
assign_perm(perm, _user, _resource.dataset)
if perm == 'change_dataset_style' and _resource_subtype not in DATA_STYLABLE_RESOURCES_SUBTYPES:
pass
else:
assign_perm(perm, _user, _resource.dataset)
elif AdvancedSecurityWorkflowManager.assignable_perm_condition(perm, _resource_type):
assign_perm(perm, _user, _resource.get_self_resource())
else:
Expand Down Expand Up @@ -741,7 +756,7 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se
_prev_perm = _perm_spec["groups"].get(user_group, []) if "groups" in _perm_spec else []
_perm_spec["groups"][user_group] = set.union(perms_as_set(_prev_perm), perms_as_set('download_resourcebase'))

if _resource.__class__.__name__ == 'Dataset':
if _resource_type == 'dataset':
# only for layer owner
assign_perm('change_dataset_data', _owner, _resource)
assign_perm('change_dataset_style', _owner, _resource)
Expand All @@ -752,7 +767,7 @@ def set_permissions(self, uuid: str, /, instance: ResourceBase = None, owner: se

# Fixup GIS Backend Security Rules Accordingly
if not self._concrete_resource_manager.set_permissions(
uuid, instance=_resource, owner=owner, permissions=_perm_spec, created=created):
uuid, instance=_resource, owner=owner, permissions=_resource.get_all_level_info(), created=created):
# This might not be a severe error. E.g. for datasets outside of local GeoServer
logger.error(Exception("Could not complete concrete manager operation successfully!"))
_resource.set_processing_state(enumerations.STATE_PROCESSED)
Expand Down
67 changes: 49 additions & 18 deletions geonode/security/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

import copy
import json
import pprint
import jsonschema
Expand All @@ -31,6 +33,33 @@
from geonode.utils import build_absolute_uri
from geonode.groups.conf import settings as groups_settings

"""
Permissions will be managed according to a "compact" set:
- view: view resource
- download: view and download
- edit: view download and edit (metadata, style, data)
- manage: change permissions, delete resource, etc.
The GET method will return:
users:
- username
- first name
- last name
- permissions (view | download | edit | manage)
organizations:
- title
- name
- permissions (view | download | edit | manage)
groups:
- title
- name
- permissions (view | download | edit | manage)
"""

# Permissions mapping
PERMISSIONS = {
Expand Down Expand Up @@ -67,15 +96,15 @@

EDIT_PERMISSIONS = [
'change_resourcebase',
'change_resourcebase_metadata',
]

BASIC_MANAGE_PERMISSIONS = [
'change_resourcebase_metadata',
'delete_resourcebase',
'change_resourcebase_permissions',
]

MANAGE_PERMISSIONS = BASIC_MANAGE_PERMISSIONS + [
'change_resourcebase_permissions',
'publish_resourcebase',
]

Expand Down Expand Up @@ -243,39 +272,41 @@ def _to_extended_perms(perm: str, resource_type: str = None, resource_subtype: s
- manage: change permissions, delete resource, etc.
- owner: admin permissions
"""

def safe_list(perms): return list(set(copy.deepcopy(perms))) if perms else []
if is_owner:
if resource_type and resource_type.lower() in DOWNLOADABLE_RESOURCES:
if resource_subtype and resource_subtype.lower() in DATA_EDITABLE_RESOURCES_SUBTYPES:
return DATASET_ADMIN_PERMISSIONS + OWNER_PERMISSIONS + DOWNLOAD_PERMISSIONS
if resource_subtype and resource_subtype.lower() in safe_list(DATA_EDITABLE_RESOURCES_SUBTYPES + DATA_STYLABLE_RESOURCES_SUBTYPES):
return safe_list(DATASET_ADMIN_PERMISSIONS + OWNER_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return OWNER_PERMISSIONS + DOWNLOAD_PERMISSIONS
return safe_list(OWNER_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return OWNER_PERMISSIONS
return safe_list(OWNER_PERMISSIONS)
elif perm is None or len(perm) == 0 or perm == NONE_RIGHTS:
return []
elif perm == VIEW_RIGHTS:
return VIEW_PERMISSIONS
return safe_list(VIEW_PERMISSIONS)
elif perm == DOWNLOAD_RIGHTS:
if resource_type and resource_type.lower() in DOWNLOADABLE_RESOURCES:
return VIEW_PERMISSIONS + DOWNLOAD_PERMISSIONS
return safe_list(VIEW_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return VIEW_PERMISSIONS
return safe_list(VIEW_PERMISSIONS)
elif perm == EDIT_RIGHTS:
if resource_type and resource_type.lower() in DOWNLOADABLE_RESOURCES:
if resource_subtype and resource_subtype.lower() in DATA_EDITABLE_RESOURCES_SUBTYPES:
return DATASET_ADMIN_PERMISSIONS + VIEW_PERMISSIONS + EDIT_PERMISSIONS + DOWNLOAD_PERMISSIONS
if resource_subtype and resource_subtype.lower() in safe_list(DATA_EDITABLE_RESOURCES_SUBTYPES + DATA_STYLABLE_RESOURCES_SUBTYPES):
return safe_list(DATASET_ADMIN_PERMISSIONS + VIEW_PERMISSIONS + EDIT_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return VIEW_PERMISSIONS + EDIT_PERMISSIONS + DOWNLOAD_PERMISSIONS
return safe_list(VIEW_PERMISSIONS + EDIT_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return VIEW_PERMISSIONS + EDIT_PERMISSIONS
return safe_list(VIEW_PERMISSIONS + EDIT_PERMISSIONS)
elif perm == MANAGE_RIGHTS:
if resource_type and resource_type.lower() in DOWNLOADABLE_RESOURCES:
if resource_subtype and resource_subtype.lower() in DATA_EDITABLE_RESOURCES_SUBTYPES:
return DATASET_ADMIN_PERMISSIONS + VIEW_PERMISSIONS + ADMIN_PERMISSIONS + DOWNLOAD_PERMISSIONS
if resource_subtype and resource_subtype.lower() in safe_list(DATA_EDITABLE_RESOURCES_SUBTYPES + DATA_STYLABLE_RESOURCES_SUBTYPES):
return safe_list(DATASET_ADMIN_PERMISSIONS + VIEW_PERMISSIONS + ADMIN_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return VIEW_PERMISSIONS + ADMIN_PERMISSIONS + DOWNLOAD_PERMISSIONS
return safe_list(VIEW_PERMISSIONS + ADMIN_PERMISSIONS + DOWNLOAD_PERMISSIONS)
else:
return VIEW_PERMISSIONS + ADMIN_PERMISSIONS
return safe_list(VIEW_PERMISSIONS + ADMIN_PERMISSIONS)


def _to_compact_perms(perms: list, resource_type: str = None, resource_subtype: str = None, is_owner: bool = False) -> str:
Expand Down Expand Up @@ -707,7 +738,7 @@ def _get_labeled_compact_perm(compact_perm: str):
for _p in COMPACT_RIGHT_MODES:
if (_p[1] not in [DOWNLOAD_RIGHTS] + DATASET_ADMIN_PERMISSIONS or
_p[1] in [DOWNLOAD_RIGHTS] and any(__p in DOWNLOAD_PERMISSIONS for __p in perms) or
_p[1] in DATASET_ADMIN_PERMISSIONS and any(__p in DATA_EDITABLE_RESOURCES_SUBTYPES for __p in perms)):
_p[1] in DATASET_ADMIN_PERMISSIONS and any(__p in DATA_EDITABLE_RESOURCES_SUBTYPES + DATA_STYLABLE_RESOURCES_SUBTYPES for __p in perms)):
_perms_list.append(_get_labeled_compact_perm(_p[1]))
if _p[1] == _perm:
break
Expand Down
Loading

0 comments on commit b850027

Please sign in to comment.