119 lines
3.9 KiB
Python
119 lines
3.9 KiB
Python
from urllib.parse import urlparse, urlunparse
|
|
|
|
from django.conf import settings
|
|
from django.contrib import auth
|
|
from django.contrib.auth import views as auth_views
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.shortcuts import redirect
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import TemplateView, View
|
|
|
|
from .forms import ElectionAuthForm
|
|
from .utils import get_cas_client
|
|
|
|
|
|
class NextPageMixin:
|
|
def get_next_url(self):
|
|
"""Decide where to go after a successful login.
|
|
|
|
Look for (in order):
|
|
- a `next` GET parameter;
|
|
- a `CASNEXT` session variable;
|
|
- the `LOGIN_REDIRECT_URL` django setting.
|
|
"""
|
|
request = self.request
|
|
next_url = request.GET.get("next")
|
|
if next_url is None and "CASNEXT" in request.session:
|
|
next_url = request.session["CASNEXT"]
|
|
del request.session["CASNEXT"]
|
|
if next_url is None:
|
|
next_url = settings.LOGIN_REDIRECT_URL
|
|
return next_url
|
|
|
|
|
|
class LoginSelectView(NextPageMixin, TemplateView):
|
|
"""Simple page letting the user choose between password and CAS authentication."""
|
|
|
|
template_name = "auth/login_select.html"
|
|
http_method_names = ["get"]
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if request.user.is_authenticated:
|
|
return redirect(self.get_next_url())
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context["next"] = self.get_next_url()
|
|
context["method"] = self.request.GET.get("method", "CAS")
|
|
context["election_id"] = self.request.GET.get("election_id", None)
|
|
|
|
return context
|
|
|
|
|
|
class CASLoginView(NextPageMixin, View):
|
|
"""CAS authentication view.
|
|
|
|
Implement the CAS authentication scheme:
|
|
|
|
1. We first redirect the user to the student CAS.
|
|
2. The user comes back with a ticket, we validate it to make sure the user is legit
|
|
(validation is delegated to the ENSCASBackend).
|
|
3. We redirect the user to the next page.
|
|
"""
|
|
|
|
http_method_names = ["get"]
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
ticket = request.GET.get("ticket")
|
|
|
|
if not ticket:
|
|
request.session["CASNEXT"] = self.get_next_url()
|
|
cas_client = get_cas_client(request)
|
|
return redirect(cas_client.get_login_url())
|
|
|
|
user = auth.authenticate(request, ticket=ticket)
|
|
if user is None:
|
|
raise PermissionDenied(_("Connexion échouée !"))
|
|
auth.login(request, user)
|
|
return redirect(self.get_next_url())
|
|
|
|
|
|
class PasswordLoginView(auth_views.LoginView):
|
|
template_name = "auth/pwd_login.html"
|
|
authentication_form = ElectionAuthForm
|
|
|
|
def get_initial(self):
|
|
return {"election_id": self.request.GET.get("election_id", None)}
|
|
|
|
|
|
class LogoutView(auth_views.LogoutView):
|
|
"""Logout view.
|
|
|
|
Tell Django to log the user out, then redirect to the CAS logout page if the user
|
|
logged in via CAS.
|
|
"""
|
|
|
|
def setup(self, request):
|
|
super().setup(request)
|
|
if "CASCONNECTED" in request.session:
|
|
del request.session["CASCONNECTED"]
|
|
self.cas_connected = True
|
|
else:
|
|
self.cas_connected = False
|
|
|
|
def get_next_page(self):
|
|
next_page = super().get_next_page()
|
|
if self.cas_connected:
|
|
cas_client = get_cas_client(self.request)
|
|
|
|
# If the next_url is local (no hostname), make it absolute so that the user
|
|
# is correctly redirected from CAS.
|
|
if not urlparse(next_page).netloc:
|
|
request = self.request
|
|
next_page = urlunparse(
|
|
(request.scheme, request.get_host(), next_page, "", "", "")
|
|
)
|
|
|
|
next_page = cas_client.get_logout_url(redirect_url=next_page)
|
|
return next_page
|