mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
Check that permissions are working when accessing to API pages
Signed-off-by: Yohann D'ANELLO <yohann.danello@gmail.com>
This commit is contained in:
parent
5cb4183e9f
commit
f570ff3cd5
@ -210,9 +210,24 @@ class TestActivityAPI(TestAPI):
|
|||||||
|
|
||||||
def test_activity_api(self):
|
def test_activity_api(self):
|
||||||
"""
|
"""
|
||||||
Load API pages for the activity app and test all filters
|
Load Activity API page and test all filters and permissions
|
||||||
"""
|
"""
|
||||||
self.check_viewset(ActivityViewSet, "/api/activity/activity/")
|
self.check_viewset(ActivityViewSet, "/api/activity/activity/")
|
||||||
|
|
||||||
|
def test_activity_type_api(self):
|
||||||
|
"""
|
||||||
|
Load ActivityType API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(ActivityTypeViewSet, "/api/activity/type/")
|
self.check_viewset(ActivityTypeViewSet, "/api/activity/type/")
|
||||||
|
|
||||||
|
def test_entry_api(self):
|
||||||
|
"""
|
||||||
|
Load Entry API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(EntryViewSet, "/api/activity/entry/")
|
self.check_viewset(EntryViewSet, "/api/activity/entry/")
|
||||||
|
|
||||||
|
def test_guest_api(self):
|
||||||
|
"""
|
||||||
|
Load Guest API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(GuestViewSet, "/api/activity/guest/")
|
self.check_viewset(GuestViewSet, "/api/activity/guest/")
|
||||||
|
@ -2,14 +2,18 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db.models.fields.files import ImageFieldFile
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, OrderingFilter
|
from django_filters.rest_framework import DjangoFilterBackend, OrderingFilter
|
||||||
|
from member.models import Membership, Club
|
||||||
from note.models import NoteClub, NoteUser, Alias, Note
|
from note.models import NoteClub, NoteUser, Alias, Note
|
||||||
|
from permission.models import PermissionMask, Permission, Role
|
||||||
from phonenumbers import PhoneNumber
|
from phonenumbers import PhoneNumber
|
||||||
from rest_framework.filters import SearchFilter
|
from rest_framework.filters import SearchFilter
|
||||||
|
|
||||||
@ -103,6 +107,77 @@ class TestAPI(TestCase):
|
|||||||
f"{model._meta.verbose_name} does not work. "
|
f"{model._meta.verbose_name} does not work. "
|
||||||
f"Given parameter: {value}")
|
f"Given parameter: {value}")
|
||||||
|
|
||||||
|
self.check_permissions(url, obj)
|
||||||
|
|
||||||
|
def check_permissions(self, url, obj):
|
||||||
|
"""
|
||||||
|
Check that permissions are working
|
||||||
|
"""
|
||||||
|
# Drop rights
|
||||||
|
self.user.is_superuser = False
|
||||||
|
self.user.save()
|
||||||
|
sess = self.client.session
|
||||||
|
sess["permission_mask"] = 0
|
||||||
|
sess.save()
|
||||||
|
|
||||||
|
# Delete user permissions
|
||||||
|
for m in Membership.objects.filter(user=self.user).all():
|
||||||
|
m.roles.clear()
|
||||||
|
m.save()
|
||||||
|
|
||||||
|
# Create a new role, which will have the checking permission
|
||||||
|
role = Role.objects.get_or_create(name="β-tester")[0]
|
||||||
|
role.permissions.clear()
|
||||||
|
role.save()
|
||||||
|
membership = Membership.objects.get_or_create(user=self.user, club=Club.objects.get(name="BDE"))[0]
|
||||||
|
membership.roles.set([role])
|
||||||
|
membership.save()
|
||||||
|
|
||||||
|
# Ensure that the access to the object is forbidden without permission
|
||||||
|
resp = self.client.get(url + f"{obj.pk}/")
|
||||||
|
self.assertEqual(resp.status_code, 404, f"Mysterious access to {url}{obj.pk}/ for {obj}")
|
||||||
|
|
||||||
|
obj.refresh_from_db()
|
||||||
|
|
||||||
|
# There are problems with polymorphism
|
||||||
|
if isinstance(obj, Note) and hasattr(obj, "note_ptr"):
|
||||||
|
obj = obj.note_ptr
|
||||||
|
|
||||||
|
mask = PermissionMask.objects.get(rank=0)
|
||||||
|
|
||||||
|
for field in obj._meta.fields:
|
||||||
|
# Build permission query
|
||||||
|
value = self.get_value(obj, field.name)
|
||||||
|
if isinstance(value, date) or isinstance(value, datetime):
|
||||||
|
value = value.isoformat()
|
||||||
|
elif isinstance(value, ImageFieldFile):
|
||||||
|
value = value.name
|
||||||
|
query = json.dumps({field.name: value})
|
||||||
|
|
||||||
|
# Create sample permission
|
||||||
|
permission = Permission.objects.get_or_create(
|
||||||
|
model=ContentType.objects.get_for_model(obj._meta.model),
|
||||||
|
query=query,
|
||||||
|
mask=mask,
|
||||||
|
type="view",
|
||||||
|
permanent=False,
|
||||||
|
description=f"Can view {obj._meta.verbose_name}",
|
||||||
|
)[0]
|
||||||
|
role.permissions.set([permission])
|
||||||
|
role.save()
|
||||||
|
|
||||||
|
# Check that the access is possible
|
||||||
|
resp = self.client.get(url + f"{obj.pk}/")
|
||||||
|
self.assertEqual(resp.status_code, 200, f"Permission {permission.query} is not working "
|
||||||
|
f"for the model {obj._meta.verbose_name}")
|
||||||
|
|
||||||
|
# Restore rights
|
||||||
|
self.user.is_superuser = True
|
||||||
|
self.user.save()
|
||||||
|
sess = self.client.session
|
||||||
|
sess["permission_mask"] = 42
|
||||||
|
sess.save()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_value(obj, key: str):
|
def get_value(obj, key: str):
|
||||||
"""
|
"""
|
||||||
|
@ -432,10 +432,20 @@ class TestMemberAPI(TestAPI):
|
|||||||
self.membership.roles.add(Role.objects.get(name="Bureau de club"))
|
self.membership.roles.add(Role.objects.get(name="Bureau de club"))
|
||||||
self.membership.save()
|
self.membership.save()
|
||||||
|
|
||||||
def test_member_api(self):
|
def test_club_api(self):
|
||||||
"""
|
"""
|
||||||
Load API pages for the member app and test all filters
|
Load Club API page and test all filters and permissions
|
||||||
"""
|
"""
|
||||||
self.check_viewset(ClubViewSet, "/api/members/club/")
|
self.check_viewset(ClubViewSet, "/api/members/club/")
|
||||||
|
|
||||||
|
def test_profile_api(self):
|
||||||
|
"""
|
||||||
|
Load Profile API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(ProfileViewSet, "/api/members/profile/")
|
self.check_viewset(ProfileViewSet, "/api/members/profile/")
|
||||||
|
|
||||||
|
def test_membership_api(self):
|
||||||
|
"""
|
||||||
|
Load Membership API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(MembershipViewSet, "/api/members/membership/")
|
self.check_viewset(MembershipViewSet, "/api/members/membership/")
|
||||||
|
@ -15,7 +15,7 @@ from permission.backends import PermissionBackend
|
|||||||
|
|
||||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
|
||||||
TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
||||||
from ..models.notes import Note, Alias
|
from ..models.notes import Note, Alias, NoteUser, NoteClub, NoteSpecial
|
||||||
from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
|
from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
|
||||||
|
|
||||||
|
|
||||||
@ -40,7 +40,12 @@ class NotePolymorphicViewSet(ReadProtectedModelViewSet):
|
|||||||
Parse query and apply filters.
|
Parse query and apply filters.
|
||||||
:return: The filtered set of requested notes
|
:return: The filtered set of requested notes
|
||||||
"""
|
"""
|
||||||
queryset = super().get_queryset().distinct()
|
user = self.request.user
|
||||||
|
get_current_session().setdefault("permission_mask", 42)
|
||||||
|
queryset = self.queryset.filter(PermissionBackend.filter_queryset(user, Note, "view")
|
||||||
|
| PermissionBackend.filter_queryset(user, NoteUser, "view")
|
||||||
|
| PermissionBackend.filter_queryset(user, NoteClub, "view")
|
||||||
|
| PermissionBackend.filter_queryset(user, NoteSpecial, "view")).distinct()
|
||||||
|
|
||||||
alias = self.request.query_params.get("alias", ".*")
|
alias = self.request.query_params.get("alias", ".*")
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
|
@ -399,13 +399,38 @@ class TestNoteAPI(TestAPI):
|
|||||||
description="Test template",
|
description="Test template",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_note_api(self):
|
def test_alias_api(self):
|
||||||
"""
|
"""
|
||||||
Load API pages for the note app and test all filters
|
Load Alias API page and test all filters and permissions
|
||||||
"""
|
"""
|
||||||
self.check_viewset(AliasViewSet, "/api/note/alias/")
|
self.check_viewset(AliasViewSet, "/api/note/alias/")
|
||||||
|
|
||||||
|
def test_consumer_api(self):
|
||||||
|
"""
|
||||||
|
Load Consumer API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(ConsumerViewSet, "/api/note/consumer/")
|
self.check_viewset(ConsumerViewSet, "/api/note/consumer/")
|
||||||
|
|
||||||
|
def test_note_api(self):
|
||||||
|
"""
|
||||||
|
Load Note API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(NotePolymorphicViewSet, "/api/note/note/")
|
self.check_viewset(NotePolymorphicViewSet, "/api/note/note/")
|
||||||
|
|
||||||
|
def test_template_category_api(self):
|
||||||
|
"""
|
||||||
|
Load TemplateCategory API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(TemplateCategoryViewSet, "/api/note/transaction/category/")
|
self.check_viewset(TemplateCategoryViewSet, "/api/note/transaction/category/")
|
||||||
|
|
||||||
|
def test_transaction_template_api(self):
|
||||||
|
"""
|
||||||
|
Load TemplateTemplate API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(TransactionTemplateViewSet, "/api/note/transaction/template/")
|
self.check_viewset(TransactionTemplateViewSet, "/api/note/transaction/template/")
|
||||||
|
|
||||||
|
def test_transaction_api(self):
|
||||||
|
"""
|
||||||
|
Load Transaction API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(TransactionViewSet, "/api/note/transaction/transaction/")
|
self.check_viewset(TransactionViewSet, "/api/note/transaction/transaction/")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
import sys
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
@ -38,6 +38,10 @@ def memoize(f):
|
|||||||
|
|
||||||
nonlocal last_collect
|
nonlocal last_collect
|
||||||
|
|
||||||
|
if "test" in sys.argv:
|
||||||
|
# In a test environment, don't memoize permissions
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
if time() - last_collect > 60:
|
if time() - last_collect > 60:
|
||||||
# Clear cache
|
# Clear cache
|
||||||
collect()
|
collect()
|
||||||
|
@ -453,12 +453,32 @@ class TestTreasuryAPI(TestAPI):
|
|||||||
self.kfet_membership._soge = True
|
self.kfet_membership._soge = True
|
||||||
self.kfet_membership.save()
|
self.kfet_membership.save()
|
||||||
|
|
||||||
def test_treasury_api(self):
|
def test_invoice_api(self):
|
||||||
"""
|
"""
|
||||||
Load API pages for the treasury app and test all filters
|
Load Invoice API page and test all filters and permissions
|
||||||
"""
|
"""
|
||||||
self.check_viewset(InvoiceViewSet, "/api/treasury/invoice/")
|
self.check_viewset(InvoiceViewSet, "/api/treasury/invoice/")
|
||||||
|
|
||||||
|
def test_product_api(self):
|
||||||
|
"""
|
||||||
|
Load Product API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(ProductViewSet, "/api/treasury/product/")
|
self.check_viewset(ProductViewSet, "/api/treasury/product/")
|
||||||
|
|
||||||
|
def test_remittance_api(self):
|
||||||
|
"""
|
||||||
|
Load Remittance API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(RemittanceViewSet, "/api/treasury/remittance/")
|
self.check_viewset(RemittanceViewSet, "/api/treasury/remittance/")
|
||||||
|
|
||||||
|
def test_remittance_type_api(self):
|
||||||
|
"""
|
||||||
|
Load RemittanceType API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(RemittanceTypeViewSet, "/api/treasury/remittance_type/")
|
self.check_viewset(RemittanceTypeViewSet, "/api/treasury/remittance_type/")
|
||||||
|
|
||||||
|
def test_sogecredit_api(self):
|
||||||
|
"""
|
||||||
|
Load SogeCredit API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(SogeCreditViewSet, "/api/treasury/soge_credit/")
|
self.check_viewset(SogeCreditViewSet, "/api/treasury/soge_credit/")
|
||||||
|
@ -527,7 +527,7 @@ class TestWEIRegistration(TestCase):
|
|||||||
sess["permission_mask"] = 0
|
sess["permission_mask"] = 0
|
||||||
sess.save()
|
sess.save()
|
||||||
response = self.client.get(reverse("wei:wei_update_registration", kwargs=dict(pk=self.registration.pk)))
|
response = self.client.get(reverse("wei:wei_update_registration", kwargs=dict(pk=self.registration.pk)))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 403)
|
||||||
sess["permission_mask"] = 42
|
sess["permission_mask"] = 42
|
||||||
sess.save()
|
sess.save()
|
||||||
|
|
||||||
@ -869,13 +869,38 @@ class TestWeiAPI(TestAPI):
|
|||||||
self.membership.roles.add(WEIRole.objects.last())
|
self.membership.roles.add(WEIRole.objects.last())
|
||||||
self.membership.save()
|
self.membership.save()
|
||||||
|
|
||||||
def test_wei_api(self):
|
def test_weiclub_api(self):
|
||||||
"""
|
"""
|
||||||
Load API pages for the treasury app and test all filters
|
Load WEI API page and test all filters and permissions
|
||||||
"""
|
"""
|
||||||
self.check_viewset(WEIClubViewSet, "/api/wei/club/")
|
self.check_viewset(WEIClubViewSet, "/api/wei/club/")
|
||||||
|
|
||||||
|
def test_wei_bus_api(self):
|
||||||
|
"""
|
||||||
|
Load Bus API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(BusViewSet, "/api/wei/bus/")
|
self.check_viewset(BusViewSet, "/api/wei/bus/")
|
||||||
|
|
||||||
|
def test_wei_team_api(self):
|
||||||
|
"""
|
||||||
|
Load BusTeam API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(BusTeamViewSet, "/api/wei/team/")
|
self.check_viewset(BusTeamViewSet, "/api/wei/team/")
|
||||||
|
|
||||||
|
def test_weirole_api(self):
|
||||||
|
"""
|
||||||
|
Load WEIRole API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(WEIRoleViewSet, "/api/wei/role/")
|
self.check_viewset(WEIRoleViewSet, "/api/wei/role/")
|
||||||
|
|
||||||
|
def test_weiregistration_api(self):
|
||||||
|
"""
|
||||||
|
Load WEIRegistration API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(WEIRegistrationViewSet, "/api/wei/registration/")
|
self.check_viewset(WEIRegistrationViewSet, "/api/wei/registration/")
|
||||||
|
|
||||||
|
def test_weimembership_api(self):
|
||||||
|
"""
|
||||||
|
Load WEIMembership API page and test all filters and permissions
|
||||||
|
"""
|
||||||
self.check_viewset(WEIMembershipViewSet, "/api/wei/membership/")
|
self.check_viewset(WEIMembershipViewSet, "/api/wei/membership/")
|
||||||
|
Loading…
Reference in New Issue
Block a user