Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fixes #12713] Permissions Registry and permissions handler #12714

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions geonode/resource/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@
from geonode.thumbs.utils import ThumbnailAlgorithms
from geonode.documents.tasks import create_document_thumbnail
from geonode.security.permissions import PermSpecCompact, DATA_STYLABLE_RESOURCES_SUBTYPES
from geonode.security.utils import perms_as_set, get_user_groups, skip_registered_members_common_group
from geonode.security.utils import (
perms_as_set,
get_user_groups,
skip_registered_members_common_group,
)
from geonode.security.registry import permissions_registry

from . import settings as rm_settings
from .utils import update_resource, resourcebase_post_save
Expand Down Expand Up @@ -574,11 +579,12 @@ def set_permissions(
else:
_permissions = None

# Fixup Advanced Workflow permissions
_perm_spec = AdvancedSecurityWorkflowManager.get_permissions(
_resource.uuid,
instance=_resource,
permissions=_permissions,
"""
Align _perm_spec based on the permissions handlers
"""
_perm_spec = permissions_registry.fixup_perms(
_resource,
_permissions,
created=created,
approval_status_changed=approval_status_changed,
group_status_changed=group_status_changed,
Expand Down
6 changes: 6 additions & 0 deletions geonode/security/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@
class GeoNodeSecurityAppConfig(AppConfig):
name = "geonode.security"
verbose_name = "GeoNode Security"

def ready(self):
super().ready()
from geonode.security.registry import permissions_registry

permissions_registry.init_registry()
59 changes: 59 additions & 0 deletions geonode/security/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#########################################################################
#
# Copyright (C) 2024 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from abc import ABC

from geonode.security.utils import AdvancedSecurityWorkflowManager


class BasePermissionsHandler(ABC):
"""
Abstract permissions handler.
This is the base class, all the permissions instances should
inherit from this class.
All the flows that touches the permissions will use this class
(example advanced workflow)
"""

def __str__(self):
return f"{self.__module__}.{self.__class__.__name__}"

def __repr__(self):
return self.__str__()

Check warning on line 37 in geonode/security/handlers.py

View check run for this annotation

Codecov / codecov/patch

geonode/security/handlers.py#L37

Added line #L37 was not covered by tests

@staticmethod
def fixup_perms(instance, perms_payload, *args, **kwargs):
return perms_payload

Check warning on line 41 in geonode/security/handlers.py

View check run for this annotation

Codecov / codecov/patch

geonode/security/handlers.py#L41

Added line #L41 was not covered by tests


class AdvancedWorkflowPermissionsHandler(BasePermissionsHandler):
"""
Handler that takes care of adjusting the permissions for the advanced workflow
"""

@staticmethod
def fixup_perms(instance, perms_payload, *args, **kwargs):
# Fixup Advanced Workflow permissions
return AdvancedSecurityWorkflowManager.get_permissions(
instance.uuid,
instance=instance,
permissions=perms_payload,
created=kwargs.get("created"),
approval_status_changed=kwargs.get("approval_status_changed"),
group_status_changed=kwargs.get("group_status_changed"),
)
65 changes: 65 additions & 0 deletions geonode/security/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#########################################################################
#
# Copyright (C) 2024 OSGeo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
from django.conf import settings
from django.utils.module_loading import import_string
from geonode.security.handlers import BasePermissionsHandler


class PermissionsHandlerRegistry:

REGISTRY = []

def init_registry(self):
self._register()
self.sanity_checks()

def add(self, module_path):
item = import_string(module_path)()
self.__check_item(item)
self.REGISTRY.append(item)

def reset(self):
self.REGISTRY = []

def _register(self):
for module_path in settings.PERMISSIONS_HANDLERS:
self.add(module_path)

def sanity_checks(self):
for item in self.REGISTRY:
self.__check_item(item)

def __check_item(self, item):
"""
Ensure that the handler is a subclass of BasePermissionsHandler
"""
if not isinstance(item, BasePermissionsHandler):
raise Exception(f"Handler {item} is not a subclass of BasePermissionsHandler")

Check warning on line 53 in geonode/security/registry.py

View check run for this annotation

Codecov / codecov/patch

geonode/security/registry.py#L53

Added line #L53 was not covered by tests

def fixup_perms(self, instance, payload, *args, **kwargs):
for handler in self.REGISTRY:
payload = handler.fixup_perms(instance, payload, *args, **kwargs)
return payload

@classmethod
def get_registry(cls):
return PermissionsHandlerRegistry.REGISTRY


permissions_registry = PermissionsHandlerRegistry()
42 changes: 42 additions & 0 deletions geonode/security/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from geonode.layers.models import Dataset
from geonode.documents.models import Document
from geonode.compat import ensure_string
from geonode.security.handlers import BasePermissionsHandler
from geonode.upload.models import ResourceHandlerInfo
from geonode.utils import check_ogc_backend
from geonode.tests.utils import check_dataset
Expand All @@ -56,6 +57,7 @@
from geonode.groups.models import Group, GroupMember, GroupProfile
from geonode.layers.populate_datasets_data import create_dataset_data
from geonode.base.auth import create_auth_token, get_or_create_token
from geonode.security.registry import permissions_registry

from geonode.base.models import Configuration, UserGeoLimit, GroupGeoLimit
from geonode.base.populate_test_data import (
Expand Down Expand Up @@ -2662,3 +2664,43 @@ def test_user_can_publish(self):
# setting back the owner to admin
self.dataset.owner = self.admin
self.dataset.save()


class DummyPermissionsHandler(BasePermissionsHandler):
@staticmethod
def fixup_perms(instance, perms_payload, *args, **kwargs):
return {"perms": ["this", "is", "fake"]}


@override_settings(PERMISSIONS_HANDLERS=["geonode.security.handlers.AdvancedWorkflowPermissionsHandler"])
class TestPermissionsRegistry(GeoNodeBaseTestSupport):
"""
Test to verify the permissions registry
"""

def tearDown(self):
permissions_registry.reset()

def test_registry_is_correctly_initiated(self):
"""
The permissions registry should initiated correctly
"""
permissions_registry.init_registry()
self.assertIsNotNone(permissions_registry.get_registry())

def test_new_handler_is_registered(self):
permissions_registry.add("geonode.security.tests.DummyPermissionsHandler")
reg = permissions_registry.get_registry()
self.assertTrue("geonode.security.tests.DummyPermissionsHandler" in (str(r) for r in reg))

def test_should_raise_exception_if_is_not_subclass(self):
with self.assertRaises(Exception):
permissions_registry.add(int)

def test_handler_should_handle_the_perms_payload(self):
# create resource
instance = create_single_dataset("fake_dataset")
# adding the dummy at the end, means will win over the other handler
permissions_registry.add("geonode.security.tests.DummyPermissionsHandler")
perms = permissions_registry.fixup_perms(instance, instance.get_all_level_info())
self.assertDictEqual({"perms": ["this", "is", "fake"]}, perms)
3 changes: 3 additions & 0 deletions geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2327,3 +2327,6 @@ def get_geonode_catalogue_service():
]
INSTALLED_APPS += ("geonode.assets",)
GEONODE_APPS += ("geonode.assets",)


PERMISSIONS_HANDLERS = ["geonode.security.handlers.AdvancedWorkflowPermissionsHandler"]
Loading