diff --git a/.gitignore b/.gitignore index 1cdd1df..2a330b9 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ venv # Project specific db.sqlite3 public/ + +# Vim recover files +*~ diff --git a/gestiojeux/settings_base.py b/gestiojeux/settings_base.py index df8e6bf..1d8a5b3 100644 --- a/gestiojeux/settings_base.py +++ b/gestiojeux/settings_base.py @@ -27,6 +27,8 @@ INSTALLED_APPS = [ "django.contrib.staticfiles", "mainsite", "inventory", + "django_cas_ng", + "gestiojeux_auth", ] MIDDLEWARE = [ diff --git a/gestiojeux/urls.py b/gestiojeux/urls.py index 39f3559..508755d 100644 --- a/gestiojeux/urls.py +++ b/gestiojeux/urls.py @@ -21,7 +21,9 @@ from django.conf.urls.static import static urlpatterns = [ path("admin/", admin.site.urls), path("inventory/", include("inventory.urls")), + path("accounts/", include("gestiojeux_auth.urls")), path("", include("mainsite.urls")), + ] if settings.DEBUG: diff --git a/gestiojeux_auth/__init__.py b/gestiojeux_auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gestiojeux_auth/admin.py b/gestiojeux_auth/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/gestiojeux_auth/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/gestiojeux_auth/apps.py b/gestiojeux_auth/apps.py new file mode 100644 index 0000000..2da02b9 --- /dev/null +++ b/gestiojeux_auth/apps.py @@ -0,0 +1,9 @@ +from django.apps import AppConfig + + +class GestiojeuxAuthConfig(AppConfig): + name = 'gestiojeux_auth' + + def ready(self): + from . import signals + diff --git a/gestiojeux_auth/cas_backend.py b/gestiojeux_auth/cas_backend.py new file mode 100644 index 0000000..eb590fc --- /dev/null +++ b/gestiojeux_auth/cas_backend.py @@ -0,0 +1,15 @@ +from django_cas_ng.backends import CASBackend +from .models import CasUser + + +class GestioJeuxCASBackend(CASBackend): + # Copied from the BOcal project + # Partly from Robin Champenois's "ExperiENS". Thanks! + def clean_username(self, username): + return username.lower().strip() + + def configure_user(self, user): + casUser = CasUser(user=user) + casUser.save() + return user + diff --git a/gestiojeux_auth/migrations/__init__.py b/gestiojeux_auth/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gestiojeux_auth/models.py b/gestiojeux_auth/models.py new file mode 100644 index 0000000..c83b39a --- /dev/null +++ b/gestiojeux_auth/models.py @@ -0,0 +1,11 @@ +from django.db import models +from django.contrib.auth.models import User + + +class CasUser(models.Model): + ''' Describes a Django user that was created through CAS ''' + + user = models.OneToOneField( + User, + on_delete=models.CASCADE, + primary_key=True) diff --git a/gestiojeux_auth/tests.py b/gestiojeux_auth/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/gestiojeux_auth/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/gestiojeux_auth/urls.py b/gestiojeux_auth/urls.py new file mode 100644 index 0000000..ab03bc9 --- /dev/null +++ b/gestiojeux_auth/urls.py @@ -0,0 +1,27 @@ +from django.urls import include, path +import django.contrib.auth.views as dj_auth_views +from .views import login, logout +import django_cas_ng.views + +app_name = "gestiojeux_auth" + +cas_patterns = [ + path("login/", django_cas_ng.views.LoginView.as_view(), name="cas_ng_login"), + path("logout/", django_cas_ng.views.LogoutView.as_view(), name="cas_ng_logout"), + path( + "callback/", + django_cas_ng.views.CallbackView.as_view(), + name="cas_ng_proxy_callback", + ), +] + +accounts_patterns = [ + path("cas/", include(cas_patterns)), + path("login/", login, name="login"), + path("logout/", logout, name="logout"), + path("password_login/", dj_auth_views.LoginView.as_view(), name="password_login"), +] + +urlpatterns = [ + path("", include(accounts_patterns)), +] diff --git a/gestiojeux_auth/views.py b/gestiojeux_auth/views.py new file mode 100644 index 0000000..331a52a --- /dev/null +++ b/gestiojeux_auth/views.py @@ -0,0 +1,43 @@ +from django.shortcuts import render, redirect +from django.urls import reverse +from django.contrib.auth import logout as auth_logout +from django.contrib.auth.decorators import login_required + +from urllib.parse import quote as urlquote + + +def login(req): + if req.user.is_authenticated: + return redirect("mainsite:home") + + if req.method == "GET": + reqDict = req.GET + elif req.method == "POST": + reqDict = req.POST + if "next" in reqDict: + nextUrl = reqDict["next"] + context = { + "pass_url": "{}?next={}".format( + reverse("gestiojeux_auth:password_login"), urlquote(nextUrl, safe="") + ), + "cas_url": "{}?next={}".format( + reverse("gestiojeux_auth:cas_ng_login"), urlquote(nextUrl, safe="") + ), + } + else: + context = { + "pass_url": reverse("gestiojeux_auth:password_login"), + "cas_url": reverse("gestiojeux_auth:cas_ng_login"), + } + + return render(req, "registration/login_switch.html", context=context) + + +@login_required +def logout(req): + CAS_BACKEND_NAME = "django_cas_ng.backends.CASBackend" + if req.session["_auth_user_backend"] != CAS_BACKEND_NAME: + auth_logout(req) + return redirect("mainsite:home") + return redirect("gestiojeux_auth:cas_ng_logout") + diff --git a/mainsite/templates/mainsite/login.html b/mainsite/templates/mainsite/login.html new file mode 100644 index 0000000..42145ad --- /dev/null +++ b/mainsite/templates/mainsite/login.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} + + + + + + +{% endblock content %} + diff --git a/mainsite/templates/partials/header.html b/mainsite/templates/partials/header.html index 8ae606f..47e6fde 100644 --- a/mainsite/templates/partials/header.html +++ b/mainsite/templates/partials/header.html @@ -10,7 +10,10 @@ Inventaire Suggestions - Connexion + {% if request.user.is_authenticated %} + Déconnexion + {% else %} Connexion + {% endif %} {# Logout #} {% endwith %} diff --git a/mainsite/templates/registration/login.html b/mainsite/templates/registration/login.html new file mode 100644 index 0000000..bb364f1 --- /dev/null +++ b/mainsite/templates/registration/login.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} + +{% block "content" %} +
+ {% if form.errors %} +

Login ou mot de passe incorrect

+ {% endif %} + + {% if next %} + {% if user.is_authenticated %} +

Accès non autorisé.

+ {% else %} +

Merci de vous connecter.

+ {% endif %} + {% endif %} + +
+ {% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
+
+ +{% endblock %} + diff --git a/mainsite/templates/registration/login_switch.html b/mainsite/templates/registration/login_switch.html new file mode 100644 index 0000000..d99c111 --- /dev/null +++ b/mainsite/templates/registration/login_switch.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% block "content" %} +
+
+
+
+ +
+ +
+
+
+ +{% endblock %} + diff --git a/requirements.txt b/requirements.txt index c27e930..fb87978 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django django-autoslug Pillow +django-cas-ng