From 0ead6604ffa847cba82b299948137102a4c97f45 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Tue, 12 Mar 2019 03:29:01 +0100 Subject: [PATCH 1/9] bugfix: auto_author gives permission to everybody(#99) bugfix: auto_author gives permission to everybody(#99) --- djangoldp/serializers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 7107a004..ad46029c 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -206,9 +206,11 @@ class LDPSerializer(HyperlinkedModelSerializer): if self.context['request'].user.is_anonymous: data['permissions'] += permissions.AnonymousReadOnly.anonymous_perms - elif self.context['request'].user.is_authenticated: + elif self.context['request'].user.is_authenticated and hasattr(obj._meta, 'auto_author'): if hasattr(obj._meta, 'auto_author'): - data['permissions'] += permissions.AnonymousReadOnly.author_perms + author = getattr(obj, obj._meta.auto_author) + if author == self.context['request'].user: + data['permissions'] += permissions.AnonymousReadOnly.author_perms else: data['permissions'] += permissions.AnonymousReadOnly.authenticated_perms -- GitLab From f385488bc9f106f70d0631a6c06fc70d97534db0 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Tue, 12 Mar 2019 13:24:52 +0100 Subject: [PATCH 2/9] syntax: auto_author gives permission to everybody(#99) syntax: auto_author gives permission to everybody(#99) --- djangoldp/serializers.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index ad46029c..3a4438d4 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -206,13 +206,12 @@ class LDPSerializer(HyperlinkedModelSerializer): if self.context['request'].user.is_anonymous: data['permissions'] += permissions.AnonymousReadOnly.anonymous_perms - elif self.context['request'].user.is_authenticated and hasattr(obj._meta, 'auto_author'): - if hasattr(obj._meta, 'auto_author'): - author = getattr(obj, obj._meta.auto_author) - if author == self.context['request'].user: - data['permissions'] += permissions.AnonymousReadOnly.author_perms - else: - data['permissions'] += permissions.AnonymousReadOnly.authenticated_perms + if hasattr(obj._meta, 'auto_author'): + author = getattr(obj, obj._meta.auto_author) + if author == self.context['request'].user: + data['permissions'] += permissions.AnonymousReadOnly.author_perms + else: + data['permissions'] += permissions.AnonymousReadOnly.authenticated_perms if hasattr(obj._meta, 'rdf_context'): data['@context'] = obj._meta.rdf_context -- GitLab From 997dc7711c17f357bed29054e819b5bef17c9d64 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 15 Mar 2019 17:26:16 +0100 Subject: [PATCH 3/9] bugfix: user_permissions is now a method of the permission class bugfix: user_permissions is now a method of the permission class --- djangoldp/permissions.py | 24 +++++++++++++++++++++++- djangoldp/serializers.py | 14 +++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 00f75d11..47ec7ab7 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -33,6 +33,10 @@ class WACPermissions(permissions.DjangoObjectPermissions): else: return super().has_permission(request, view) + # This method should be overriden by other permission classes + def user_permissions(self, request, view, obj): + return [] + class ObjectFilter(filters.BaseFilterBackend): def filter_queryset(self, request, queryset, view): @@ -97,4 +101,22 @@ class AnonymousReadOnly(WACPermissions): if author == request.user: return True else: - return super().has_object_permission(request, view, obj) \ No newline at end of file + return super().has_object_permission(request, view, obj) + + def user_permissions(self, request, view, obj): + if request.user.is_anonymous: + return self.anonymous_perms + else: + if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: + return self.author_perms + else: + return self.authenticated_perms + + def filter_user_perms(self, request, obj, permissions): + if request.user.is_anonymous: + return [perm for perm in permissions if perm in self.anonymous_perms] + else: + if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: + return [perm for perm in permissions if perm in self.author_perms] + else: + return [perm for perm in permissions if perm in self.authenticated_perms] \ No newline at end of file diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 3a4438d4..9768a803 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -19,7 +19,6 @@ from rest_framework.utils.serializer_helpers import ReturnDict from djangoldp.fields import LDPUrlField, IdURLField from djangoldp.models import Model -from djangoldp import permissions class LDListMixin: @@ -198,20 +197,17 @@ class LDPSerializer(HyperlinkedModelSerializer): def to_representation(self, obj): data = super().to_representation(obj) + permissions = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}, {'mode': {'@type': 'change'}}, {'mode': {'@type': ''}}] if hasattr(obj._meta, 'rdf_type'): data['@type'] = obj._meta.rdf_type + data['permissions'] = [{'mode': {'@type': name.split('_')[0]}} for name in get_perms(self.context['request'].user, obj)] - if self.context['request'].user.is_anonymous: - data['permissions'] += permissions.AnonymousReadOnly.anonymous_perms - if hasattr(obj._meta, 'auto_author'): - author = getattr(obj, obj._meta.auto_author) - if author == self.context['request'].user: - data['permissions'] += permissions.AnonymousReadOnly.author_perms - else: - data['permissions'] += permissions.AnonymousReadOnly.authenticated_perms + for permission_class in obj._meta.permission_classes: + perms = permission_class().filter_user_perms(self.context['request'], obj, permissions) + data['permissions'] += perms if hasattr(obj._meta, 'rdf_context'): data['@context'] = obj._meta.rdf_context -- GitLab From 4eba0e2e067e3f1450e01d6c8d5f4333729a7661 Mon Sep 17 00:00:00 2001 From: Sylvain Le Bon <sylvain@happy-dev.fr> Date: Fri, 15 Mar 2019 16:52:11 +0000 Subject: [PATCH 4/9] bugfix: added missing permissions --- djangoldp/permissions.py | 20 +++++++------------- djangoldp/serializers.py | 24 ++++++++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 47ec7ab7..f070a7b3 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -37,6 +37,9 @@ class WACPermissions(permissions.DjangoObjectPermissions): def user_permissions(self, request, view, obj): return [] + def filter_user_perms(self, request, obj, permissions): + return [perm for perm in permissions if perm in self.user_permissions(request, obj)] + class ObjectFilter(filters.BaseFilterBackend): def filter_queryset(self, request, queryset, view): @@ -78,9 +81,9 @@ class AnonymousReadOnly(WACPermissions): Author: can read all posts + create new posts + update their own """ - anonymous_perms = [{'mode': {'@type': 'view'}}] - authenticated_perms = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}] - author_perms = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}, {'mode': {'@type': 'change'}}] + anonymous_perms = ['view'] + authenticated_perms = ['view','add'] + author_perms = ['view', 'add', 'change'] def has_permission(self, request, view): if view.action in ['list', 'retrieve']: @@ -110,13 +113,4 @@ class AnonymousReadOnly(WACPermissions): if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: return self.author_perms else: - return self.authenticated_perms - - def filter_user_perms(self, request, obj, permissions): - if request.user.is_anonymous: - return [perm for perm in permissions if perm in self.anonymous_perms] - else: - if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: - return [perm for perm in permissions if perm in self.author_perms] - else: - return [perm for perm in permissions if perm in self.authenticated_perms] \ No newline at end of file + return self.authenticated_perms \ No newline at end of file diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 9768a803..19b4fc3f 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -195,23 +195,27 @@ class LDPSerializer(HyperlinkedModelSerializer): pass return fields + list(getattr(self.Meta, 'extra_fields', [])) + def get_permissions(self, obj): + permissions = [] + + for permission_class in obj._meta.permission_classes: + perms = permission_class().filter_user_perms(self.context['request'], obj, permissions) + + permissions = get_perms(self.context['request'].user, obj) + + return [{'mode': {'@type': name.split('_')[0]}} for name in permissions] + def to_representation(self, obj): data = super().to_representation(obj) - permissions = [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'add'}}, {'mode': {'@type': 'change'}}, {'mode': {'@type': ''}}] + permissions = ['view', 'add', 'change', 'control', 'delete'] if hasattr(obj._meta, 'rdf_type'): data['@type'] = obj._meta.rdf_type - - data['permissions'] = [{'mode': {'@type': name.split('_')[0]}} for name in - get_perms(self.context['request'].user, obj)] - - for permission_class in obj._meta.permission_classes: - perms = permission_class().filter_user_perms(self.context['request'], obj, permissions) - data['permissions'] += perms - if hasattr(obj._meta, 'rdf_context'): data['@context'] = obj._meta.rdf_context - + + data['permissions'] self.get_permissions(obj) + return data def build_standard_field(self, field_name, model_field): -- GitLab From 7d91374b11bed8a329866236504a55f805808b35 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 15 Mar 2019 18:29:57 +0100 Subject: [PATCH 5/9] update: user_permissions method update: user_permissions method --- djangoldp/permissions.py | 38 ++++++++++++++++++++++++-------------- djangoldp/serializers.py | 12 +++++------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index f070a7b3..7a9b4b20 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -34,7 +34,7 @@ class WACPermissions(permissions.DjangoObjectPermissions): return super().has_permission(request, view) # This method should be overriden by other permission classes - def user_permissions(self, request, view, obj): + def user_permissions(self, request, obj): return [] def filter_user_perms(self, request, obj, permissions): @@ -53,26 +53,36 @@ class ObjectFilter(filters.BaseFilterBackend): class ObjectPermission(WACPermissions): filter_class = ObjectFilter + class InboxPermissions(WACPermissions): """ - Anonymous users: can create notifications but can't read - Logged in users: can create notifications but can't read - Inbox owners: can read + update all notifications + Everybody can create + Author can edit """ - filter_class = ObjectFilter + anonymous_perms = ['view', 'create'] + authenticated_perms = ['view','create'] + author_perms = ['view'] + def has_permission(self, request, view): - if view.action in ['create', 'retrieve', 'update', 'partial_update', 'destroy']: + if view.action in ['create', 'list', 'retrieve']: return True else: return super().has_permission(request, view) def has_object_permission(self, request, view, obj): - if view.action == "create": - return True - if hasattr(obj._meta, 'auto_author'): - if request.user == getattr(obj, obj._meta.auto_author): - return True - return super().has_object_permission(request, view) + if view.action == ['update', 'partial_update', 'destroy']: + return False + else: + return super().has_object_permission(request, view) + + def user_permissions(self, request, obj): + if request.user.is_anonymous: + return self.anonymous_perms + else: + if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: + return self.author_perms + else: + return self.authenticated_perms class AnonymousReadOnly(WACPermissions): """ @@ -83,7 +93,7 @@ class AnonymousReadOnly(WACPermissions): anonymous_perms = ['view'] authenticated_perms = ['view','add'] - author_perms = ['view', 'add', 'change'] + author_perms = ['view', 'add', 'change', 'control', 'delete'] def has_permission(self, request, view): if view.action in ['list', 'retrieve']: @@ -106,7 +116,7 @@ class AnonymousReadOnly(WACPermissions): else: return super().has_object_permission(request, view, obj) - def user_permissions(self, request, view, obj): + def user_permissions(self, request, obj): if request.user.is_anonymous: return self.anonymous_perms else: diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 19b4fc3f..a7fea8d2 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -196,25 +196,23 @@ class LDPSerializer(HyperlinkedModelSerializer): return fields + list(getattr(self.Meta, 'extra_fields', [])) def get_permissions(self, obj): - permissions = [] + permissions = ['view', 'add', 'change', 'control', 'delete'] for permission_class in obj._meta.permission_classes: - perms = permission_class().filter_user_perms(self.context['request'], obj, permissions) - - permissions = get_perms(self.context['request'].user, obj) - + permissions = permission_class().filter_user_perms(self.context['request'], obj, permissions) + + permissions += get_perms(self.context['request'].user, obj) return [{'mode': {'@type': name.split('_')[0]}} for name in permissions] def to_representation(self, obj): data = super().to_representation(obj) - permissions = ['view', 'add', 'change', 'control', 'delete'] if hasattr(obj._meta, 'rdf_type'): data['@type'] = obj._meta.rdf_type if hasattr(obj._meta, 'rdf_context'): data['@context'] = obj._meta.rdf_context - data['permissions'] self.get_permissions(obj) + data['permissions'] = self.get_permissions(obj) return data -- GitLab From 5ea8203aa524e14bf227f1c2f24899a07a724986 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 15 Mar 2019 18:50:55 +0100 Subject: [PATCH 6/9] syntax: modification in permissions.py syntax: modification in permissions.py --- djangoldp/permissions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 7a9b4b20..56c3fa3f 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -70,7 +70,7 @@ class InboxPermissions(WACPermissions): return super().has_permission(request, view) def has_object_permission(self, request, view, obj): - if view.action == ['update', 'partial_update', 'destroy']: + if view.action in ['update', 'partial_update', 'destroy']: return False else: return super().has_object_permission(request, view) @@ -106,7 +106,7 @@ class AnonymousReadOnly(WACPermissions): def has_object_permission(self, request, view, obj): if view.action == "create" and request.user.is_authenticated(): return True - elif view.action == ["list", "retrieve"]: + elif view.action in ["list", "retrieve"]: return True elif view.action in ['update', 'partial_update', 'destroy']: if hasattr(obj._meta, 'auto_author'): -- GitLab From f4a9a65e190baa6920b8d49fa141bfb93ecaf850 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 15 Mar 2019 19:11:55 +0100 Subject: [PATCH 7/9] bugfix: object has no attribute permission_classes bugfix: object has no attribute permission_classes --- djangoldp/serializers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index 8c780454..eef36c04 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -207,8 +207,9 @@ class LDPSerializer(HyperlinkedModelSerializer): def get_permissions(self, obj): permissions = ['view', 'add', 'change', 'control', 'delete'] - for permission_class in obj._meta.permission_classes: - permissions = permission_class().filter_user_perms(self.context['request'], obj, permissions) + if obj._meta.permission_classes: + for permission_class in obj._meta.permission_classes: + permissions = permission_class().filter_user_perms(self.context['request'], obj, permissions) permissions += get_perms(self.context['request'].user, obj) return [{'mode': {'@type': name.split('_')[0]}} for name in permissions] -- GitLab From 21fa979369e1148ef300694f0d3703f2d13767d7 Mon Sep 17 00:00:00 2001 From: Thibaud Duquennoy <thibaud@duquennoy.fr> Date: Fri, 15 Mar 2019 19:23:52 +0100 Subject: [PATCH 8/9] bugfix: object has no attribute permission_classes bugfix: object has no attribute permission_classes --- djangoldp/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djangoldp/serializers.py b/djangoldp/serializers.py index eef36c04..b2cc8fc4 100644 --- a/djangoldp/serializers.py +++ b/djangoldp/serializers.py @@ -207,7 +207,7 @@ class LDPSerializer(HyperlinkedModelSerializer): def get_permissions(self, obj): permissions = ['view', 'add', 'change', 'control', 'delete'] - if obj._meta.permission_classes: + if hasattr(obj._meta, 'permission_classes'): for permission_class in obj._meta.permission_classes: permissions = permission_class().filter_user_perms(self.context['request'], obj, permissions) -- GitLab From 6805cae194bed42c9175ff73b3cef9e68d528f70 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste <bleme@pm.me> Date: Mon, 18 Mar 2019 16:13:21 +0100 Subject: [PATCH 9/9] syntax: code format --- djangoldp/permissions.py | 13 ++++++++----- djangoldp/tests/tests_user_permissions.py | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/djangoldp/permissions.py b/djangoldp/permissions.py index 56c3fa3f..7b5c1345 100644 --- a/djangoldp/permissions.py +++ b/djangoldp/permissions.py @@ -1,6 +1,6 @@ -from rest_framework import permissions -from rest_framework import filters from guardian.shortcuts import get_objects_for_user +from rest_framework import filters +from rest_framework import permissions """ Liste des actions passées dans views selon le protocole REST : @@ -16,6 +16,7 @@ Pour chacune de ces actions, on va définir si on accepte la requête (True) ou checks have already passed """ + class WACPermissions(permissions.DjangoObjectPermissions): perms_map = { 'GET': ['%(app_label)s.view_%(model_name)s'], @@ -50,6 +51,7 @@ class ObjectFilter(filters.BaseFilterBackend): objects = get_objects_for_user(request.user, perm, klass=queryset) return objects + class ObjectPermission(WACPermissions): filter_class = ObjectFilter @@ -60,7 +62,7 @@ class InboxPermissions(WACPermissions): Author can edit """ anonymous_perms = ['view', 'create'] - authenticated_perms = ['view','create'] + authenticated_perms = ['view', 'create'] author_perms = ['view'] def has_permission(self, request, view): @@ -84,6 +86,7 @@ class InboxPermissions(WACPermissions): else: return self.authenticated_perms + class AnonymousReadOnly(WACPermissions): """ Anonymous users: can read all posts @@ -92,7 +95,7 @@ class AnonymousReadOnly(WACPermissions): """ anonymous_perms = ['view'] - authenticated_perms = ['view','add'] + authenticated_perms = ['view', 'add'] author_perms = ['view', 'add', 'change', 'control', 'delete'] def has_permission(self, request, view): @@ -123,4 +126,4 @@ class AnonymousReadOnly(WACPermissions): if hasattr(obj._meta, 'auto_author') and getattr(obj, obj._meta.auto_author) == request.user: return self.author_perms else: - return self.authenticated_perms \ No newline at end of file + return self.authenticated_perms diff --git a/djangoldp/tests/tests_user_permissions.py b/djangoldp/tests/tests_user_permissions.py index 9f510926..5bda0e58 100644 --- a/djangoldp/tests/tests_user_permissions.py +++ b/djangoldp/tests/tests_user_permissions.py @@ -7,6 +7,7 @@ from djangoldp.views import LDPViewSet import json + class TestUserPermissions(APITestCase): def setUp(self): -- GitLab