Skip to content

Commit

Permalink
Merge pull request #961 from ae-utbm/auth-backend
Browse files Browse the repository at this point in the history
Custom auth backend
  • Loading branch information
imperosol authored Dec 22, 2024
2 parents 9ca9577 + ab81f11 commit eaac0c7
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 42 deletions.
37 changes: 37 additions & 0 deletions core/auth_backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission

from core.models import Group

if TYPE_CHECKING:
from core.models import User


class SithModelBackend(ModelBackend):
"""Custom auth backend for the Sith.
In fact, it's the exact same backend as `django.contrib.auth.backend.ModelBackend`,
with the exception that group permissions are fetched slightly differently.
Indeed, django tries by default to fetch the permissions associated
with all the `django.contrib.auth.models.Group` of a user ;
however, our User model overrides that, so the actual linked group model
is [core.models.Group][].
Instead of having the relation `auth_perm --> auth_group <-- core_user`,
we have `auth_perm --> auth_group <-- core_group <-- core_user`.
Thus, this backend make the small tweaks necessary to make
our custom models interact with the django auth.
"""

def _get_group_permissions(self, user_obj: User):
groups = user_obj.groups.all()
if user_obj.is_subscribed:
groups = groups.union(
Group.objects.get(pk=settings.SITH_GROUP_SUBSCRIBERS_ID)
)
return Permission.objects.filter(group__group__in=groups)
170 changes: 128 additions & 42 deletions core/management/commands/populate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@
from datetime import date, timedelta
from io import StringIO
from pathlib import Path
from typing import ClassVar
from typing import ClassVar, NamedTuple

from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.db import connection
from django.db.models import Q
from django.utils import timezone
from django.utils.timezone import localdate
from PIL import Image
Expand All @@ -56,6 +57,18 @@
from subscription.models import Subscription


class PopulatedGroups(NamedTuple):
root: Group
public: Group
subscribers: Group
old_subscribers: Group
sas_admin: Group
com_admin: Group
counter_admin: Group
accounting_admin: Group
pedagogy_admin: Group


class Command(BaseCommand):
ROOT_PATH: ClassVar[Path] = Path(__file__).parent.parent.parent.parent
SAS_FIXTURE_PATH: ClassVar[Path] = (
Expand All @@ -79,25 +92,7 @@ def handle(self, *args, **options):

Sith.objects.create(weekmail_destinations="[email protected] [email protected]")
Site.objects.create(domain=settings.SITH_URL, name=settings.SITH_NAME)

root_group = Group.objects.create(name="Root")
public_group = Group.objects.create(name="Public")
subscribers = Group.objects.create(name="Subscribers")
old_subscribers = Group.objects.create(name="Old subscribers")
Group.objects.create(name="Accounting admin")
Group.objects.create(name="Communication admin")
Group.objects.create(name="Counter admin")
Group.objects.create(name="Banned from buying alcohol")
Group.objects.create(name="Banned from counters")
Group.objects.create(name="Banned to subscribe")
Group.objects.create(name="SAS admin")
Group.objects.create(name="Forum admin")
Group.objects.create(name="Pedagogy admin")
self.reset_index("core", "auth")

change_billing = Permission.objects.get(codename="change_billinginfo")
add_billing = Permission.objects.get(codename="add_billinginfo")
root_group.permissions.add(change_billing, add_billing)
groups = self._create_groups()

root = User.objects.create_superuser(
id=0,
Expand Down Expand Up @@ -155,7 +150,7 @@ def handle(self, *args, **options):
Counter.edit_groups.through.objects.bulk_create(bar_groups)
self.reset_index("counter")

subscribers.viewable_files.add(home_root, club_root)
groups.subscribers.viewable_files.add(home_root, club_root)

Weekmail().save()

Expand Down Expand Up @@ -260,21 +255,11 @@ def handle(self, *args, **options):
)
User.groups.through.objects.bulk_create(
[
User.groups.through(
group_id=settings.SITH_GROUP_COUNTER_ADMIN_ID, user=counter
),
User.groups.through(
group_id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID, user=comptable
),
User.groups.through(
group_id=settings.SITH_GROUP_COM_ADMIN_ID, user=comunity
),
User.groups.through(
group_id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID, user=tutu
),
User.groups.through(
group_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
),
User.groups.through(group=groups.counter_admin, user=counter),
User.groups.through(group=groups.accounting_admin, user=comptable),
User.groups.through(group=groups.com_admin, user=comunity),
User.groups.through(group=groups.pedagogy_admin, user=tutu),
User.groups.through(group=groups.sas_admin, user=skia),
]
)
for user in richard, sli, krophil, skia:
Expand Down Expand Up @@ -335,7 +320,7 @@ def handle(self, *args, **options):
content="Fonctionnement de la laverie",
)

public_group.viewable_page.set(
groups.public.viewable_page.set(
[syntax_page, services_page, index_page, laundry_page]
)

Expand Down Expand Up @@ -512,8 +497,10 @@ def handle(self, *args, **options):
club=main_club,
limit_age=18,
)
subscribers.products.add(cotis, cotis2, refill, barb, cble, cors, carolus)
old_subscribers.products.add(cotis, cotis2)
groups.subscribers.products.add(
cotis, cotis2, refill, barb, cble, cors, carolus
)
groups.old_subscribers.products.add(cotis, cotis2)

mde = Counter.objects.get(name="MDE")
mde.products.add(barb, cble, cons, dcons)
Expand Down Expand Up @@ -616,10 +603,10 @@ def handle(self, *args, **options):
start_date="1942-06-12 10:28:45+01",
end_date="7942-06-12 10:28:45+01",
)
el.view_groups.add(public_group)
el.view_groups.add(groups.public)
el.edit_groups.add(ae_board_group)
el.candidature_groups.add(subscribers)
el.vote_groups.add(subscribers)
el.candidature_groups.add(groups.subscribers)
el.vote_groups.add(groups.subscribers)
liste = ElectionList.objects.create(title="Candidature Libre", election=el)
listeT = ElectionList.objects.create(title="Troll", election=el)
pres = Role.objects.create(
Expand Down Expand Up @@ -898,3 +885,102 @@ def _create_subscription(
start=s.subscription_start,
)
s.save()

def _create_groups(self) -> PopulatedGroups:
perms = Permission.objects.all()

root_group = Group.objects.create(name="Root")
root_group.permissions.add(*list(perms.values_list("pk", flat=True)))
# public has no permission.
# Its purpose is not to link users to permissions,
# but to other objects (like products)
public_group = Group.objects.create(name="Public")

subscribers = Group.objects.create(name="Subscribers")
old_subscribers = Group.objects.create(name="Old subscribers")
old_subscribers.permissions.add(
*list(
perms.filter(
codename__in=[
"view_user",
"view_picture",
"view_album",
"view_peoplepicturerelation",
"add_peoplepicturerelation",
]
)
)
)
accounting_admin = Group.objects.create(name="Accounting admin")
accounting_admin.permissions.add(
*list(
perms.filter(
Q(content_type__app_label="accounting")
| Q(
codename__in=[
"view_customer",
"view_product",
"change_product",
"add_product",
"view_producttype",
"change_producttype",
"add_producttype",
"delete_selling",
]
)
).values_list("pk", flat=True)
)
)
com_admin = Group.objects.create(name="Communication admin")
com_admin.permissions.add(
*list(
perms.filter(content_type__app_label="com").values_list("pk", flat=True)
)
)
counter_admin = Group.objects.create(name="Counter admin")
counter_admin.permissions.add(
*list(
perms.filter(
Q(content_type__app_label__in=["counter", "launderette"])
& ~Q(codename__in=["delete_product", "delete_producttype"])
)
)
)
Group.objects.create(name="Banned from buying alcohol")
Group.objects.create(name="Banned from counters")
Group.objects.create(name="Banned to subscribe")
sas_admin = Group.objects.create(name="SAS admin")
sas_admin.permissions.add(
*list(
perms.filter(content_type__app_label="sas").values_list("pk", flat=True)
)
)
forum_admin = Group.objects.create(name="Forum admin")
forum_admin.permissions.add(
*list(
perms.filter(content_type__app_label="forum").values_list(
"pk", flat=True
)
)
)
pedagogy_admin = Group.objects.create(name="Pedagogy admin")
pedagogy_admin.permissions.add(
*list(
perms.filter(content_type__app_label="pedagogy").values_list(
"pk", flat=True
)
)
)
self.reset_index("core", "auth")

return PopulatedGroups(
root=root_group,
public=public_group,
subscribers=subscribers,
old_subscribers=old_subscribers,
com_admin=com_admin,
counter_admin=counter_admin,
accounting_admin=accounting_admin,
sas_admin=sas_admin,
pedagogy_admin=pedagogy_admin,
)
1 change: 1 addition & 0 deletions sith/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@
# Auth configuration
AUTH_USER_MODEL = "core.User"
AUTH_ANONYMOUS_MODEL = "core.models.AnonymousUser"
AUTHENTICATION_BACKENDS = ["core.auth_backends.SithModelBackend"]
LOGIN_URL = "/login"
LOGOUT_URL = "/logout"
LOGIN_REDIRECT_URL = "/"
Expand Down

0 comments on commit eaac0c7

Please sign in to comment.