from django.contrib.auth import REDIRECT_FIELD_NAME, logout from django.contrib.auth.views import SuccessURLAllowedHostsMixin from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages from django.conf import settings from django.utils import timezone from django.utils.http import url_has_allowed_host_and_scheme from django.http import HttpResponseRedirect from django.shortcuts import resolve_url from ..models.session import AuthSession class AuthSessionRequiredMixin(SuccessURLAllowedHostsMixin): redirect_field_name = REDIRECT_FIELD_NAME redirect_authenticated_user = True def dispatch(self, request, *args, **kwargs): if not request.session["AuthSession"]: if request.user.is_authenticated and self.redirect_authenticated_user: redirect_to = self.request.POST.get( self.redirect_field_name, self.request.GET.get(self.redirect_field_name, '') ) url_is_safe = url_has_allowed_host_and_scheme( url=redirect_to, allowed_hosts=self.get_success_url_allowed_hosts(), require_https=self.request.is_secure(), ) url = redirect_to if url_is_safe else resolve_url( settings.LOGIN_REDIRECT_URL) if url == self.request.path: raise ValueError( "Redirection loop for authenticated user detected. Check that " "your LOGIN_REDIRECT_URL doesn't point to a login page." ) return HttpResponseRedirect(url) if not request.user.is_authenticated: messages.error( request, "Could not identify your login session, please try again.") url = resolve_url(settings.LOGIN_URL) if params := request.GET.urlencode(): url += f"?{params}" return HttpResponseRedirect(url) if request.user.is_authenticated: logout(request) messages.error( request, "This shouldn't happen. Looks like you are logged in *and* logging in. Logged you out, just to be sure. Please try logging in again. Sorry!") request.session["AuthSession"] = None url = resolve_url(settings.LOGIN_URL) if params := request.GET.urlencode(): url += f"?{params}" return HttpResponseRedirect(url) try: session = AuthSession.objects.get( id=request.session["AuthSession"]) if session.expiry < timezone.now(): request.session["AuthSession"] = None messages.error( request, "Your session has expired. Please try logging in again.") url = resolve_url(settings.LOGIN_URL) if params := request.GET.urlencode(): url += f"?{params}" return HttpResponseRedirect(url) except AuthSession.DoesNotExist: request.session["AuthSession"] = None messages.error( request, "You are trying to access a session that doesn't exist...? Please try logging in again.") url = resolve_url(settings.LOGIN_URL) if params := request.GET.urlencode(): url += f"?{params}" return HttpResponseRedirect(url) return super().dispatch(request, *args, **kwargs) class OnlyLoggedOutMixin: redirect_field_name = REDIRECT_FIELD_NAME def dispatch(self, request, *args, **kwargs): if request.user.is_authenticated: redirect_to = self.request.POST.get( self.redirect_field_name, self.request.GET.get(self.redirect_field_name, '') ) url_is_safe = url_has_allowed_host_and_scheme( url=redirect_to, allowed_hosts=self.get_success_url_allowed_hosts(), require_https=self.request.is_secure(), ) url = redirect_to if url_is_safe else resolve_url( settings.LOGIN_REDIRECT_URL) if url == self.request.path: raise ValueError( "Redirection loop for authenticated user detected. Check that " "your LOGIN_REDIRECT_URL doesn't point to a login page." ) return HttpResponseRedirect(url) return super().dispatch(request, *args, **kwargs)