mirror of
https://github.com/ae-utbm/sith.git
synced 2026-04-27 09:06:02 +00:00
apply review comments
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from unittest import mock
|
||||
from unittest.mock import Mock
|
||||
|
||||
from django.contrib.messages import Message, get_messages
|
||||
from django.db.models import Max
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
@@ -87,7 +88,15 @@ class TestThirdPartyAuth(TestCase):
|
||||
del self.query["signature"]
|
||||
self.query["signature"] = hmac_hexdigest(new_key, self.query)
|
||||
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
|
||||
assert res.status_code == 403
|
||||
assert list(get_messages(res.wsgi_request)) == [
|
||||
Message(
|
||||
level=40,
|
||||
message=(
|
||||
"La signature est incorrecte. "
|
||||
"Nous ne pouvons pas garantir l'authenticité de la requête."
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
def test_cgu_not_accepted(self):
|
||||
self.client.force_login(self.user)
|
||||
@@ -102,13 +111,24 @@ class TestThirdPartyAuth(TestCase):
|
||||
assert res.status_code == 200
|
||||
|
||||
def test_invalid_client(self):
|
||||
self.client.force_login(self.user)
|
||||
self.query["client_id"] = ApiClient.objects.aggregate(res=Max("id"))["res"] + 1
|
||||
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
|
||||
assert res.status_code == 403
|
||||
assert list(get_messages(res.wsgi_request)) == [
|
||||
Message(
|
||||
level=40,
|
||||
message="Les données fournies pour l'authentification sont incorrectes.",
|
||||
)
|
||||
]
|
||||
|
||||
def test_missing_parameter(self):
|
||||
"""Test that a 403 is raised if there is a missing parameter."""
|
||||
self.client.force_login(self.user)
|
||||
del self.query["username"]
|
||||
self.query["signature"] = hmac_hexdigest(self.api_client.hmac_key, self.query)
|
||||
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
|
||||
assert res.status_code == 403
|
||||
assert list(get_messages(res.wsgi_request)) == [
|
||||
Message(
|
||||
level=40,
|
||||
message="Les données fournies pour l'authentification sont incorrectes.",
|
||||
)
|
||||
]
|
||||
|
||||
+39
-12
@@ -3,10 +3,11 @@ from urllib.parse import unquote
|
||||
|
||||
import pydantic
|
||||
import requests
|
||||
import sentry_sdk
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import FormView, TemplateView
|
||||
@@ -20,16 +21,19 @@ from core.schemas import UserProfileSchema
|
||||
from core.utils import hmac_hexdigest
|
||||
|
||||
|
||||
class ThirdPartyAuthView(LoginRequiredMixin, FormView):
|
||||
class ThirdPartyAuthView(AccessMixin, FormView):
|
||||
form_class = ThirdPartyAuthForm
|
||||
template_name = "api/third_party/auth.jinja"
|
||||
success_url = reverse_lazy("core:index")
|
||||
|
||||
def parse_params(self) -> ThirdPartyAuthParamsSchema:
|
||||
def parse_params(self) -> ThirdPartyAuthParamsSchema | None:
|
||||
"""Parse and check the authentication parameters.
|
||||
|
||||
Raises:
|
||||
PermissionDenied: if the verification failed.
|
||||
If parsing fails, messages will be created using the django message
|
||||
infrastructure.
|
||||
|
||||
Returns:
|
||||
The parses parameters, or None if the parsing failed.
|
||||
"""
|
||||
# This is here rather than in ThirdPartyAuthForm because
|
||||
# the given parameters and their signature are checked during both
|
||||
@@ -39,20 +43,39 @@ class ThirdPartyAuthView(LoginRequiredMixin, FormView):
|
||||
params = {key: unquote(val) for key, val in params.items()}
|
||||
try:
|
||||
params = ThirdPartyAuthParamsSchema(**params)
|
||||
except pydantic.ValidationError as e:
|
||||
raise PermissionDenied("Wrong data format") from e
|
||||
except pydantic.ValidationError:
|
||||
messages.error(
|
||||
self.request, _("The data provided for authentication is incorrect")
|
||||
)
|
||||
return None
|
||||
client: ApiClient = get_object_or_none(ApiClient, id=params.client_id)
|
||||
if not client:
|
||||
raise PermissionDenied
|
||||
messages.error(
|
||||
self.request, _("The data provided for authentication is incorrect")
|
||||
)
|
||||
return None
|
||||
if not hmac.compare_digest(
|
||||
hmac_hexdigest(client.hmac_key, params.model_dump(exclude={"signature"})),
|
||||
params.signature,
|
||||
):
|
||||
raise PermissionDenied("Bad signature")
|
||||
messages.error(
|
||||
self.request,
|
||||
_(
|
||||
"The signature is incorrect. "
|
||||
"We cannot ensure the provenance of the request."
|
||||
),
|
||||
)
|
||||
return None
|
||||
return params
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_authenticated:
|
||||
return self.handle_no_permission()
|
||||
self.params = self.parse_params()
|
||||
if not self.params:
|
||||
# if parameters parsing failed, shortcut the operation and display
|
||||
# an empty page with just the error messages.
|
||||
return render(request, "core/base.jinja")
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
@@ -73,10 +96,14 @@ class ThirdPartyAuthView(LoginRequiredMixin, FormView):
|
||||
client = ApiClient.objects.get(id=form.cleaned_data["client_id"])
|
||||
user = UserProfileSchema.from_orm(self.request.user).model_dump()
|
||||
data = {"user": user, "signature": hmac_hexdigest(client.hmac_key, user)}
|
||||
response = requests.post(form.cleaned_data["callback_url"], json=data)
|
||||
try:
|
||||
ok = requests.post(form.cleaned_data["callback_url"], json=data).ok
|
||||
except requests.RequestException as e:
|
||||
sentry_sdk.capture_exception(e)
|
||||
ok = False
|
||||
self.success_url = reverse(
|
||||
"api-link:third-party-auth-result",
|
||||
kwargs={"result": "success" if response.ok else "failure"},
|
||||
kwargs={"result": "success" if ok else "failure"},
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
@@ -148,14 +148,24 @@ msgid ""
|
||||
"href=\"%(sith_cgu_link)s\">the Students' Association</a> applies as soon as "
|
||||
"the form is submitted."
|
||||
msgstr ""
|
||||
"Les politiques de confidentialité de <a href=\"%(privacy_link)s\">%(app)s</a> et de <a "
|
||||
"href=\"%(sith_cgu_link)s\">l'Association des Etudiants</a> s'appliquent dès la soumission "
|
||||
"du formulaire."
|
||||
"Les politiques de confidentialité de <a href=\"%(privacy_link)s\">%(app)s</"
|
||||
"a> et de <a href=\"%(sith_cgu_link)s\">l'Association des Etudiants</a> "
|
||||
"s'appliquent dès la soumission du formulaire."
|
||||
|
||||
#: api/templates/api/third_party/auth.jinja
|
||||
msgid "Confirmation of identity"
|
||||
msgstr "Confirmation d'identité"
|
||||
|
||||
#: api/views.py
|
||||
msgid "The data provided for authentication is incorrect"
|
||||
msgstr "Les données fournies pour l'authentification sont incorrectes."
|
||||
|
||||
#: api/views.py
|
||||
msgid ""
|
||||
"The signature is incorrect. We cannot ensure the provenance of the request."
|
||||
msgstr ""
|
||||
"La signature est incorrecte. Nous ne pouvons pas garantir l'authenticité de la requête."
|
||||
|
||||
#: api/views.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
@@ -167,7 +177,9 @@ msgstr ""
|
||||
|
||||
#: api/views.py
|
||||
msgid "You have been successfully authenticated. You can now close this page."
|
||||
msgstr "Vous avez été authentifié avec succès. Vous pouvez maintenant fermer cette page."
|
||||
msgstr ""
|
||||
"Vous avez été authentifié avec succès. Vous pouvez maintenant fermer cette "
|
||||
"page."
|
||||
|
||||
#: api/views.py
|
||||
msgid ""
|
||||
@@ -175,9 +187,9 @@ msgid ""
|
||||
"during the interaction with the third-party application. Please contact the "
|
||||
"managers of the latter."
|
||||
msgstr ""
|
||||
"Votre authentification sur le site AE a fonctionné, mais une erreur est arrivée "
|
||||
"durant l'interaction avec l'application tierce. Veuillez contacter les responsables "
|
||||
"de cette dernière."
|
||||
"Votre authentification sur le site AE a fonctionné, mais une erreur est "
|
||||
"arrivée durant l'interaction avec l'application tierce. Veuillez contacter "
|
||||
"les responsables de cette dernière."
|
||||
|
||||
#: club/forms.py
|
||||
msgid "Users to add"
|
||||
@@ -263,6 +275,24 @@ msgstr "Vous devez être cotisant pour faire partie d'un club"
|
||||
msgid "You are already a member of this club"
|
||||
msgstr "Vous êtes déjà membre de ce club."
|
||||
|
||||
#: club/forms.py
|
||||
#, fuzzy
|
||||
#| msgid "Club state"
|
||||
msgid "Club status"
|
||||
msgstr "Etat du club"
|
||||
|
||||
#: club/forms.py
|
||||
msgid "Active"
|
||||
msgstr "Actif"
|
||||
|
||||
#: club/forms.py
|
||||
msgid "Inactive"
|
||||
msgstr "Inactif"
|
||||
|
||||
#: club/forms.py
|
||||
msgid "All clubs"
|
||||
msgstr "Tous les clubs"
|
||||
|
||||
#: club/models.py
|
||||
msgid "slug name"
|
||||
msgstr "nom slug"
|
||||
@@ -383,37 +413,22 @@ msgstr "Cet email est déjà abonné à cette mailing"
|
||||
msgid "Unregistered user"
|
||||
msgstr "Utilisateur non enregistré"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Club list"
|
||||
msgstr "Liste des clubs"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "The list of all clubs existing at UTBM."
|
||||
msgstr "La liste de tous les clubs existants à l'UTBM"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Club list"
|
||||
msgstr "Liste des clubs"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Filters"
|
||||
msgstr "Filtres"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Club state"
|
||||
msgstr "Etat du club"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Active"
|
||||
msgstr "Actif"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "Inactive"
|
||||
msgstr "Inactif"
|
||||
|
||||
#: club/templates/club/club_list.jinja
|
||||
msgid "All clubs"
|
||||
msgstr "Tous les clubs"
|
||||
#: club/templates/club/club_list.jinja core/templates/core/base/header.jinja
|
||||
#: forum/templates/forum/macros.jinja matmat/templates/matmat/search_form.jinja
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: club/templates/club/club_list.jinja core/templates/core/user_tools.jinja
|
||||
msgid "New club"
|
||||
@@ -1945,11 +1960,6 @@ msgstr "Connexion"
|
||||
msgid "Register"
|
||||
msgstr "Inscription"
|
||||
|
||||
#: core/templates/core/base/header.jinja forum/templates/forum/macros.jinja
|
||||
#: matmat/templates/matmat/search_form.jinja
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: core/templates/core/base/header.jinja
|
||||
msgid "Logout"
|
||||
msgstr "Déconnexion"
|
||||
@@ -4294,6 +4304,47 @@ msgstr ""
|
||||
msgid "this page"
|
||||
msgstr "cette page"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid "Eurockéennes 2025 partnership"
|
||||
msgstr "Partenariat Eurockéennes 2025"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid ""
|
||||
"Our partner uses Weezevent to sell tickets. Weezevent may collect user info "
|
||||
"according to its own privacy policy. By clicking the accept button you "
|
||||
"consent to their terms of services."
|
||||
msgstr ""
|
||||
"Notre partenaire utilises Wezevent pour vendre ses billets. Weezevent peut "
|
||||
"collecter des informations utilisateur conformément à sa propre politique de "
|
||||
"confidentialité. En cliquant sur le bouton d'acceptation vous consentez à "
|
||||
"leurs termes de service."
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid "Privacy policy"
|
||||
msgstr "Politique de confidentialité"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
#: trombi/templates/trombi/comment_moderation.jinja
|
||||
msgid "Accept"
|
||||
msgstr "Accepter"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid ""
|
||||
"You must be subscribed to benefit from the partnership with the Eurockéennes."
|
||||
msgstr ""
|
||||
"Vous devez être cotisant pour bénéficier du partenariat avec les "
|
||||
"Eurockéennes."
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This partnership offers a discount of up to 33%% on tickets for Friday, "
|
||||
"Saturday and Sunday, as well as the 3-day package from Friday to Sunday."
|
||||
msgstr ""
|
||||
"Ce partenariat permet de profiter d'une réduction jusqu'à 33%% sur les "
|
||||
"billets du vendredi, du samedi et du dimanche, ainsi qu'au forfait 3 jours, "
|
||||
"du vendredi au dimanche."
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid "There are no items available for sale"
|
||||
msgstr "Aucun article n'est disponible à la vente"
|
||||
@@ -5720,10 +5771,6 @@ msgstr "fin"
|
||||
msgid "Moderate Trombi comments"
|
||||
msgstr "Modérer les commentaires du Trombi"
|
||||
|
||||
#: trombi/templates/trombi/comment_moderation.jinja
|
||||
msgid "Accept"
|
||||
msgstr "Accepter"
|
||||
|
||||
#: trombi/templates/trombi/comment_moderation.jinja
|
||||
msgid "Reject"
|
||||
msgstr "Refuser"
|
||||
@@ -5965,39 +6012,3 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée."
|
||||
#, python-format
|
||||
msgid "Maximum characters: %(max_length)s"
|
||||
msgstr "Nombre de caractères max: %(max_length)s"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid "Eurockéennes 2025 partnership"
|
||||
msgstr "Partenariat Eurockéennes 2025"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid ""
|
||||
"Our partner uses Weezevent to sell tickets. Weezevent may collect user info "
|
||||
"according to its own privacy policy. By clicking the accept button you "
|
||||
"consent to their terms of services."
|
||||
msgstr ""
|
||||
"Notre partenaire utilises Wezevent pour vendre ses billets. Weezevent peut "
|
||||
"collecter des informations utilisateur conformément à sa propre politique de "
|
||||
"confidentialité. En cliquant sur le bouton d'acceptation vous consentez à "
|
||||
"leurs termes de service."
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid "Privacy policy"
|
||||
msgstr "Politique de confidentialité"
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
msgid ""
|
||||
"You must be subscribed to benefit from the partnership with the Eurockéennes."
|
||||
msgstr ""
|
||||
"Vous devez être cotisant pour bénéficier du partenariat avec les "
|
||||
"Eurockéennes."
|
||||
|
||||
#: eboutic/templates/eboutic/eboutic_main.jinja
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This partnership offers a discount of up to 33%% on tickets for Friday, "
|
||||
"Saturday and Sunday, as well as the 3-day package from Friday to Sunday."
|
||||
msgstr ""
|
||||
"Ce partenariat permet de profiter d'une réduction jusqu'à 33%% sur les "
|
||||
"billets du vendredi, du samedi et du dimanche, ainsi qu'au forfait 3 jours, "
|
||||
"du vendredi au dimanche."
|
||||
|
||||
Reference in New Issue
Block a user