Portail de connexion pour une élection
This commit is contained in:
parent
a4db79353b
commit
92fe03d81c
8 changed files with 45 additions and 211 deletions
|
@ -38,7 +38,7 @@
|
|||
<hr>
|
||||
|
||||
{# Indications de connexion #}
|
||||
{% if election.start_date < current_time and election.end_date > current_time %}
|
||||
{% if election.start_date < current_time and election.end_date > current_time and not can_vote %}
|
||||
<div class="message is-warning">
|
||||
<div class="message-body">
|
||||
{% if election.restricted %}
|
||||
|
@ -48,6 +48,34 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<div class="tile is-ancestor">
|
||||
<div class="tile is-parent">
|
||||
{% if election.restricted %}
|
||||
<a class="tile is-child notification is-primary" href="{% url 'auth.election' election.pk %}?next={% url 'election.view' election.pk %}">
|
||||
<div class="subtitle has-text-centered mb-2">
|
||||
<span class="icon has-text-white">
|
||||
<i class="fas fa-unlock"></i>
|
||||
</span>
|
||||
<span class="ml-3">{% trans "Connexion par identifiants" %}</span>
|
||||
</div>
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="tile is-child notification is-primary" href="{% url 'authens:login.cas' %}">
|
||||
<div class="subtitle has-text-centered mb-2">
|
||||
<span class="icon has-text-white">
|
||||
<i class="fas fa-school"></i>
|
||||
</span>
|
||||
<span class="ml-3">{% trans "Connexion via CAS" %}</span>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Description de l'élection #}
|
||||
|
|
|
@ -3,8 +3,9 @@ from django.urls import path
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("login/select", views.LoginSelectView.as_view(), name="auth.select"),
|
||||
path("login/cas", views.CASLoginView.as_view(), name="auth.cas"),
|
||||
path("login/pwd", views.PasswordLoginView.as_view(), name="auth.pwd"),
|
||||
path("logout", views.LogoutView.as_view(), name="auth.logout"),
|
||||
path(
|
||||
"election/<int:election_id>/login",
|
||||
views.ElectionLoginView.as_view(),
|
||||
name="auth.election",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
from urllib.parse import urlunparse
|
||||
|
||||
from cas import CASClient
|
||||
|
||||
|
||||
def get_cas_client(request):
|
||||
"""Return a CAS client configured for SPI's CAS."""
|
||||
return CASClient(
|
||||
version=3,
|
||||
service_url=urlunparse(
|
||||
(request.scheme, request.get_host(), request.path, "", "", "")
|
||||
),
|
||||
server_url="https://cas.eleves.ens.fr/",
|
||||
)
|
|
@ -1,121 +1,19 @@
|
|||
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
|
||||
|
||||
# #############################################################################
|
||||
# Election Specific Login
|
||||
# #############################################################################
|
||||
|
||||
|
||||
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"
|
||||
class ElectionLoginView(auth_views.LoginView):
|
||||
template_name = "auth/election_login.html"
|
||||
authentication_form = ElectionAuthForm
|
||||
|
||||
def get_initial(self):
|
||||
return {"election_id": self.request.GET.get("election_id", None)}
|
||||
return {"election_id": self.kwargs.get("election_id")}
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
template_name = "auth/logout.html"
|
||||
|
||||
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
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.update({"election_id": self.kwargs.get("election_id")})
|
||||
return super().get_context_data(**kwargs)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-primary" href="{% url 'auth.select' %}?next={{ next }}&election_id={{ election_id }}&method={{ method }}">
|
||||
<a class="button is-primary" href="{% url 'election.view' election_id %}">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-undo-alt"></i>
|
||||
</span>
|
|
@ -1,51 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block auth %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1 class="title">{% trans "Choisissez la méthode de connexion" %}</h1>
|
||||
<hr>
|
||||
|
||||
{# Indications de connexion #}
|
||||
{% if method %}
|
||||
<div class="message is-warning">
|
||||
<div class="message-body">
|
||||
{% if method == "PWD" %}
|
||||
{% trans "Pour voter lors de cette élection, vous devez vous connecter à l'aide des identifiants reçus par mail. Choisissez la connexion par mot de passe." %}
|
||||
{% elif method == "CAS" %}
|
||||
{% trans "Pour voter lors de cette élection, vous devez vous connecter à l'aide du CAS élève." %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="tile is-ancestor">
|
||||
<div class="tile is-parent">
|
||||
<a class="tile is-child notification is-primary" href="{% url "auth.cas" %}?next={{ next }}">
|
||||
<div class="subtitle has-text-centered mb-2">
|
||||
<span class="icon has-text-white">
|
||||
<i class="fas fa-school"></i>
|
||||
</span>
|
||||
<span class="ml-3">{% trans "Connexion via CAS" %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="tile is-parent">
|
||||
<a class="tile is-child notification" href="{% url "auth.pwd" %}?next={{ next }}&election_id={{ election_id }}&method={{ method }}">
|
||||
<div class="subtitle has-text-centered mb-2">
|
||||
<span class="icon">
|
||||
<i class="fas fa-key"></i>
|
||||
</span>
|
||||
<span class="ml-3">{% trans "Connexion par mot de passe" %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
|
@ -1,12 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block auth %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1 class="title">{% trans "Vous avez bien été déconnecté." %}</h1>
|
||||
<hr>
|
||||
|
||||
{% endblock %}
|
|
@ -9,22 +9,6 @@
|
|||
<h1 class="title">{% trans "Choisissez la méthode de connexion" %}</h1>
|
||||
<hr>
|
||||
|
||||
{# Indications de connexion #}
|
||||
{% comment %}
|
||||
{% if method %}
|
||||
<div class="message is-warning">
|
||||
<div class="message-body">
|
||||
{% if method == "PWD" %}
|
||||
{% trans "Pour voter lors de cette élection, vous devez vous connecter à l'aide des identifiants reçus par mail. Choisissez la connexion par mot de passe." %}
|
||||
{% elif method == "CAS" %}
|
||||
{% trans "Pour voter lors de cette élection, vous devez vous connecter à l'aide du CAS élève." %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endcomment %}
|
||||
|
||||
|
||||
<div class="tile is-ancestor">
|
||||
<div class="tile is-parent">
|
||||
<a class="tile is-child notification is-primary" href="{% url "authens:login.cas" %}?next={{ next }}">
|
||||
|
|
Loading…
Reference in a new issue