Files
labhelper/labhelper/auth_backend.py
Adrian A. Baumann 4ad03403aa
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 17s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 3s
Keycloak shenanigans
2026-02-25 22:24:44 +01:00

55 lines
2.1 KiB
Python

from mozilla_django_oidc.auth import OIDCAuthenticationBackend
from django.contrib.auth.models import Group
# Keycloak group name → Django group name mapping.
# Keycloak may send group paths with a leading slash (e.g. "/LabHelper Administrators");
# these are stripped before comparison.
KEYCLOAK_GROUP_MAP = {
'LabHelper Administrators': 'LabHelper Administrators',
'LabHelper Staff': 'LabHelper Staff',
'LabHelper Viewers': 'LabHelper Viewers',
}
# Members of these groups receive is_staff=True (Django admin access)
STAFF_GROUPS = {'LabHelper Administrators'}
class KeycloakOIDCBackend(OIDCAuthenticationBackend):
"""OIDC backend that maps Keycloak groups to Django groups on every login."""
def get_username(self, claims):
return claims.get('preferred_username') or super().get_username(claims)
def create_user(self, claims):
user = super().create_user(claims)
self._sync_from_claims(user, claims)
return user
def update_user(self, user, claims):
user = super().update_user(user, claims)
self._sync_from_claims(user, claims)
return user
def _sync_from_claims(self, user, claims):
"""Sync user attributes and group memberships from Keycloak token claims."""
user.first_name = claims.get('given_name', user.first_name)
user.last_name = claims.get('family_name', user.last_name)
# Keycloak sends group paths like "/LabHelper Administrators"; normalise them.
raw_groups = claims.get('groups', [])
keycloak_groups = {g.lstrip('/') for g in raw_groups}
user.is_staff = bool(keycloak_groups & STAFF_GROUPS)
user.save()
# Add/remove the user from each managed Django group to match Keycloak.
for kc_group, django_group_name in KEYCLOAK_GROUP_MAP.items():
try:
group = Group.objects.get(name=django_group_name)
except Group.DoesNotExist:
continue
if kc_group in keycloak_groups:
user.groups.add(group)
else:
user.groups.remove(group)