Skip to content

Commit

Permalink
CH-167 Async support on Django user attach middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
filippomc committed Dec 17, 2024
1 parent 4dd9656 commit 8ab3502
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import jwt

from django.contrib.auth.models import User
from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware

from keycloak.exceptions import KeycloakGetError

Expand Down Expand Up @@ -36,20 +38,56 @@ def _get_user():
return None


class BearerTokenMiddleware:
def __init__(self, get_response=None):
# One-time configuration and initialization.
self.get_response = get_response
async def _aget_user():
bearer = get_authentication_token()
if bearer:
# found bearer token get the Django user
try:
token = bearer.split(" ")[-1]
payload = jwt.decode(token, algorithms=["RS256"], options={"verify_signature": False}, audience="web-client")
kc_id = payload["sub"]
try:
user = await User.objects.aget(member__kc_id=kc_id)
except User.DoesNotExist:
user = await get_user_service().async_kc_user(get_auth_service().get_auth_client().get_current_user())
return user
except KeycloakGetError:
# KC user not found
return None
except InvalidToken:
return None
except Exception as e:
log.exception("User mapping error, %s", payload["email"])
return None

return None


@sync_and_async_middleware
def BearerTokenMiddleware(get_response=None):
# One-time configuration and initialization.
if iscoroutinefunction(get_response):
async def middleware(request):
if (not request.path.startswith("/static")) and getattr(getattr(request, "user", {}), "is_anonymous", True):
user = await _aget_user()
if user:
# auto login, set the user
request.user = user
request._cached_user = user

def __call__(self, request):
if getattr(getattr(request, "user", {}), "is_anonymous", True):
user = _get_user()
if user:
# auto login, set the user
request.user = user
request._cached_user = user
response = await get_response(request)
return response
else:
def middleware(request):
if (not request.path.startswith("/static")) and getattr(getattr(request, "user", {}), "is_anonymous", True):
user = _get_user()
if user:
# auto login, set the user
request.user = user
request._cached_user = user

return self.get_response(request)
return get_response(request)
return middleware


class BearerTokenAuthentication:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ def sync_kc_user(self, kc_user, is_superuser=False, delete=False):
user.save()
return user

async def async_kc_user(self, kc_user, is_superuser=False, delete=False):
# sync the kc user with the django user

user, created = await User.objects.aget_or_create(username=kc_user["username"])

await Member.objects.aget_or_create(user=user, kc_id=kc_user["id"])
user = self._map_kc_user(user, kc_user, is_superuser, delete)
user.save()
return user

def sync_kc_user_groups(self, kc_user):
# Sync the user usergroups and memberships
user = User.objects.get(username=kc_user["email"])
Expand Down

0 comments on commit 8ab3502

Please sign in to comment.