diff --git a/CHANGES/7706.feature b/CHANGES/7706.feature new file mode 100644 index 000000000..a2d8266cf --- /dev/null +++ b/CHANGES/7706.feature @@ -0,0 +1 @@ +Added access policy and permission management to container repositories. diff --git a/pulp_container/app/migrations/0011_add_container_repository_permissions.py b/pulp_container/app/migrations/0011_add_container_repository_permissions.py new file mode 100644 index 000000000..fae4041c0 --- /dev/null +++ b/pulp_container/app/migrations/0011_add_container_repository_permissions.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.17 on 2020-12-14 12:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('container', '0010_remove_uploadchunk'), + ] + + operations = [ + migrations.AlterModelOptions( + name='containerrepository', + options={'default_related_name': '%(app_label)s_%(model_name)s', 'permissions': [('sync_containerrepository', 'Can start a sync task'), ('modify_content_containerrepository', 'Can modify content in a repository'), ('build_image_containerrepository', 'Can use the image builder in a repository')]}, + ), + ] diff --git a/pulp_container/app/models.py b/pulp_container/app/models.py index 6476b324f..2aaa7e738 100644 --- a/pulp_container/app/models.py +++ b/pulp_container/app/models.py @@ -197,7 +197,11 @@ class Meta: unique_together = (("name",),) -class ContainerRepository(Repository): +class ContainerRepository( + Repository, + AutoAddObjPermsMixin, + AutoDeleteObjPermsMixin, +): """ Repository for "container" content. @@ -208,9 +212,15 @@ class ContainerRepository(Repository): TYPE = "container" CONTENT_TYPES = [Blob, Manifest, Tag] PUSH_ENABLED = False + ACCESS_POLICY_VIEWSET_NAME = "repositories/container/container" class Meta: default_related_name = "%(app_label)s_%(model_name)s" + permissions = [ + ("sync_containerrepository", "Can start a sync task"), + ("modify_content_containerrepository", "Can modify content in a repository"), + ("build_image_containerrepository", "Can use the image builder in a repository"), + ] def finalize_new_version(self, new_version): """ diff --git a/pulp_container/app/viewsets.py b/pulp_container/app/viewsets.py index 732002349..588f281f8 100644 --- a/pulp_container/app/viewsets.py +++ b/pulp_container/app/viewsets.py @@ -10,6 +10,7 @@ from django_filters import CharFilter, MultipleChoiceFilter from drf_spectacular.utils import extend_schema from rest_framework import mixins +from rest_framework.decorators import action from pulpcore.plugin.access_policy import AccessPolicyFromDB from pulpcore.plugin.serializers import ( @@ -32,7 +33,6 @@ RepositoryVersionViewSet, OperationPostponedResponse, ) -from rest_framework.decorators import action from pulp_container.app import models, serializers, tasks @@ -201,6 +201,80 @@ class ContainerRepositoryViewSet(RepositoryViewSet): endpoint_name = "container" queryset = models.ContainerRepository.objects.all() serializer_class = serializers.ContainerRepositorySerializer + permission_classes = (AccessPolicyFromDB,) + queryset_filtering_required_permission = "container.view_containerrepository" + DEFAULT_ACCESS_POLICY = { + "statements": [ + { + "action": ["list"], + "principal": "authenticated", + "effect": "allow", + }, + { + "action": ["create"], + "principal": "authenticated", + "effect": "allow", + "condition": "has_model_perms:container.add_containerrepository", + }, + { + "action": ["retrieve"], + "principal": "authenticated", + "effect": "allow", + "condition": "has_model_or_obj_perms:container.view_containerrepository", + }, + { + "action": ["destroy"], + "principal": "authenticated", + "effect": "allow", + "condition": "has_model_or_obj_perms:container.delete_containerrepository", + }, + { + "action": ["update", "partial_update"], + "principal": "authenticated", + "effect": "allow", + "condition": "has_model_or_obj_perms:container.change_containerrepository", + }, + { + "action": ["sync"], + "principal": "authenticated", + "effect": "allow", + "condition": [ + "has_model_or_obj_perms:container.sync_containerrepository", + "has_remote_param_model_or_obj_perms:container.view_containerremote", + ], + }, + { + "action": ["add", "remove", "tag", "untag", "copy_tags", "copy_manifests"], + "principal": "authenticated", + "effect": "allow", + "condition": [ + "has_model_or_obj_perms:container.modify_content_containerrepository", + ], + }, + { + "action": ["build_image"], + "principal": "authenticated", + "effect": "allow", + "condition": [ + "has_model_or_obj_perms:container.build_image_containerrepository", + ], + }, + ], + "permissions_assignment": [ + { + "function": "add_for_object_creator", + "parameters": None, + "permissions": [ + "container.view_containerrepository", + "container.change_containerrepository", + "container.delete_containerrepository", + "container.sync_containerrepository", + "container.modify_content_containerrepository", + "container.build_image_containerrepository", + ], + }, + ], + } # This decorator is necessary since a sync operation is asyncrounous and returns # the id and href of the sync task.