Skip to content

Commit 4aa2675

Browse files
committed
apply review comments
1 parent 876b6d3 commit 4aa2675

3 files changed

Lines changed: 149 additions & 91 deletions

File tree

api/tests/test_third_party_auth.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from unittest import mock
22
from unittest.mock import Mock
33

4+
from django.contrib.messages import Message, get_messages
45
from django.db.models import Max
56
from django.test import TestCase
67
from django.urls import reverse
@@ -87,7 +88,15 @@ def test_wrong_signature(self):
8788
del self.query["signature"]
8889
self.query["signature"] = hmac_hexdigest(new_key, self.query)
8990
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
90-
assert res.status_code == 403
91+
assert list(get_messages(res.wsgi_request)) == [
92+
Message(
93+
level=40,
94+
message=(
95+
"La signature est incorrecte. "
96+
"Nous ne pouvons pas garantir l'authenticité de la requête."
97+
),
98+
)
99+
]
91100

92101
def test_cgu_not_accepted(self):
93102
self.client.force_login(self.user)
@@ -102,13 +111,24 @@ def test_cgu_not_accepted(self):
102111
assert res.status_code == 200
103112

104113
def test_invalid_client(self):
114+
self.client.force_login(self.user)
105115
self.query["client_id"] = ApiClient.objects.aggregate(res=Max("id"))["res"] + 1
106116
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
107-
assert res.status_code == 403
117+
assert list(get_messages(res.wsgi_request)) == [
118+
Message(
119+
level=40,
120+
message="Les données fournies pour l'authentification sont incorrectes.",
121+
)
122+
]
108123

109124
def test_missing_parameter(self):
110-
"""Test that a 403 is raised if there is a missing parameter."""
125+
self.client.force_login(self.user)
111126
del self.query["username"]
112127
self.query["signature"] = hmac_hexdigest(self.api_client.hmac_key, self.query)
113128
res = self.client.get(reverse("api-link:third-party-auth", query=self.query))
114-
assert res.status_code == 403
129+
assert list(get_messages(res.wsgi_request)) == [
130+
Message(
131+
level=40,
132+
message="Les données fournies pour l'authentification sont incorrectes.",
133+
)
134+
]

api/views.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
import pydantic
55
import requests
6+
import sentry_sdk
67
from django.conf import settings
78
from django.contrib import messages
8-
from django.contrib.auth.mixins import LoginRequiredMixin
9-
from django.core.exceptions import PermissionDenied
9+
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
10+
from django.shortcuts import render
1011
from django.urls import reverse, reverse_lazy
1112
from django.utils.translation import gettext as _
1213
from django.views.generic import FormView, TemplateView
@@ -20,16 +21,19 @@
2021
from core.utils import hmac_hexdigest
2122

2223

23-
class ThirdPartyAuthView(LoginRequiredMixin, FormView):
24+
class ThirdPartyAuthView(AccessMixin, FormView):
2425
form_class = ThirdPartyAuthForm
2526
template_name = "api/third_party/auth.jinja"
2627
success_url = reverse_lazy("core:index")
2728

28-
def parse_params(self) -> ThirdPartyAuthParamsSchema:
29+
def parse_params(self) -> ThirdPartyAuthParamsSchema | None:
2930
"""Parse and check the authentication parameters.
3031
31-
Raises:
32-
PermissionDenied: if the verification failed.
32+
If parsing fails, messages will be created using the django message
33+
infrastructure.
34+
35+
Returns:
36+
The parses parameters, or None if the parsing failed.
3337
"""
3438
# This is here rather than in ThirdPartyAuthForm because
3539
# the given parameters and their signature are checked during both
@@ -39,20 +43,39 @@ def parse_params(self) -> ThirdPartyAuthParamsSchema:
3943
params = {key: unquote(val) for key, val in params.items()}
4044
try:
4145
params = ThirdPartyAuthParamsSchema(**params)
42-
except pydantic.ValidationError as e:
43-
raise PermissionDenied("Wrong data format") from e
46+
except pydantic.ValidationError:
47+
messages.error(
48+
self.request, _("The data provided for authentication is incorrect")
49+
)
50+
return None
4451
client: ApiClient = get_object_or_none(ApiClient, id=params.client_id)
4552
if not client:
46-
raise PermissionDenied
53+
messages.error(
54+
self.request, _("The data provided for authentication is incorrect")
55+
)
56+
return None
4757
if not hmac.compare_digest(
4858
hmac_hexdigest(client.hmac_key, params.model_dump(exclude={"signature"})),
4959
params.signature,
5060
):
51-
raise PermissionDenied("Bad signature")
61+
messages.error(
62+
self.request,
63+
_(
64+
"The signature is incorrect. "
65+
"We cannot ensure the provenance of the request."
66+
),
67+
)
68+
return None
5269
return params
5370

5471
def dispatch(self, request, *args, **kwargs):
72+
if not request.user.is_authenticated:
73+
return self.handle_no_permission()
5574
self.params = self.parse_params()
75+
if not self.params:
76+
# if parameters parsing failed, shortcut the operation and display
77+
# an empty page with just the error messages.
78+
return render(request, "core/base.jinja")
5679
return super().dispatch(request, *args, **kwargs)
5780

5881
def get(self, *args, **kwargs):
@@ -73,10 +96,14 @@ def form_valid(self, form):
7396
client = ApiClient.objects.get(id=form.cleaned_data["client_id"])
7497
user = UserProfileSchema.from_orm(self.request.user).model_dump()
7598
data = {"user": user, "signature": hmac_hexdigest(client.hmac_key, user)}
76-
response = requests.post(form.cleaned_data["callback_url"], json=data)
99+
try:
100+
ok = requests.post(form.cleaned_data["callback_url"], json=data).ok
101+
except requests.RequestException as e:
102+
sentry_sdk.capture_exception(e)
103+
ok = False
77104
self.success_url = reverse(
78105
"api-link:third-party-auth-result",
79-
kwargs={"result": "success" if response.ok else "failure"},
106+
kwargs={"result": "success" if ok else "failure"},
80107
)
81108
return super().form_valid(form)
82109

locale/fr/LC_MESSAGES/django.po

Lines changed: 86 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,24 @@ msgid ""
148148
"href=\"%(sith_cgu_link)s\">the Students' Association</a> applies as soon as "
149149
"the form is submitted."
150150
msgstr ""
151-
"Les politiques de confidentialité de <a href=\"%(privacy_link)s\">%(app)s</a> et de <a "
152-
"href=\"%(sith_cgu_link)s\">l'Association des Etudiants</a> s'appliquent dès la soumission "
153-
"du formulaire."
151+
"Les politiques de confidentialité de <a href=\"%(privacy_link)s\">%(app)s</"
152+
"a> et de <a href=\"%(sith_cgu_link)s\">l'Association des Etudiants</a> "
153+
"s'appliquent dès la soumission du formulaire."
154154

155155
#: api/templates/api/third_party/auth.jinja
156156
msgid "Confirmation of identity"
157157
msgstr "Confirmation d'identité"
158158

159+
#: api/views.py
160+
msgid "The data provided for authentication is incorrect"
161+
msgstr "Les données fournies pour l'authentification sont incorrectes."
162+
163+
#: api/views.py
164+
msgid ""
165+
"The signature is incorrect. We cannot ensure the provenance of the request."
166+
msgstr ""
167+
"La signature est incorrecte. Nous ne pouvons pas garantir l'authenticité de la requête."
168+
159169
#: api/views.py
160170
#, python-format
161171
msgid ""
@@ -167,17 +177,19 @@ msgstr ""
167177

168178
#: api/views.py
169179
msgid "You have been successfully authenticated. You can now close this page."
170-
msgstr "Vous avez été authentifié avec succès. Vous pouvez maintenant fermer cette page."
180+
msgstr ""
181+
"Vous avez été authentifié avec succès. Vous pouvez maintenant fermer cette "
182+
"page."
171183

172184
#: api/views.py
173185
msgid ""
174186
"Your authentication on the AE website was successful, but an error happened "
175187
"during the interaction with the third-party application. Please contact the "
176188
"managers of the latter."
177189
msgstr ""
178-
"Votre authentification sur le site AE a fonctionné, mais une erreur est arrivée "
179-
"durant l'interaction avec l'application tierce. Veuillez contacter les responsables "
180-
"de cette dernière."
190+
"Votre authentification sur le site AE a fonctionné, mais une erreur est "
191+
"arrivée durant l'interaction avec l'application tierce. Veuillez contacter "
192+
"les responsables de cette dernière."
181193

182194
#: club/forms.py
183195
msgid "Users to add"
@@ -263,6 +275,24 @@ msgstr "Vous devez être cotisant pour faire partie d'un club"
263275
msgid "You are already a member of this club"
264276
msgstr "Vous êtes déjà membre de ce club."
265277

278+
#: club/forms.py
279+
#, fuzzy
280+
#| msgid "Club state"
281+
msgid "Club status"
282+
msgstr "Etat du club"
283+
284+
#: club/forms.py
285+
msgid "Active"
286+
msgstr "Actif"
287+
288+
#: club/forms.py
289+
msgid "Inactive"
290+
msgstr "Inactif"
291+
292+
#: club/forms.py
293+
msgid "All clubs"
294+
msgstr "Tous les clubs"
295+
266296
#: club/models.py
267297
msgid "slug name"
268298
msgstr "nom slug"
@@ -383,37 +413,22 @@ msgstr "Cet email est déjà abonné à cette mailing"
383413
msgid "Unregistered user"
384414
msgstr "Utilisateur non enregistré"
385415

386-
#: club/templates/club/club_list.jinja
387-
msgid "Club list"
388-
msgstr "Liste des clubs"
389-
390416
#: club/templates/club/club_list.jinja
391417
msgid "The list of all clubs existing at UTBM."
392418
msgstr "La liste de tous les clubs existants à l'UTBM"
393419

394420
#: club/templates/club/club_list.jinja
395-
msgid "Filters"
396-
msgstr "Filtres"
397-
398-
#: club/templates/club/club_list.jinja
399-
msgid "Name"
400-
msgstr "Nom"
401-
402-
#: club/templates/club/club_list.jinja
403-
msgid "Club state"
404-
msgstr "Etat du club"
405-
406-
#: club/templates/club/club_list.jinja
407-
msgid "Active"
408-
msgstr "Actif"
421+
msgid "Club list"
422+
msgstr "Liste des clubs"
409423

410424
#: club/templates/club/club_list.jinja
411-
msgid "Inactive"
412-
msgstr "Inactif"
425+
msgid "Filters"
426+
msgstr "Filtres"
413427

414-
#: club/templates/club/club_list.jinja
415-
msgid "All clubs"
416-
msgstr "Tous les clubs"
428+
#: club/templates/club/club_list.jinja core/templates/core/base/header.jinja
429+
#: forum/templates/forum/macros.jinja matmat/templates/matmat/search_form.jinja
430+
msgid "Search"
431+
msgstr "Recherche"
417432

418433
#: club/templates/club/club_list.jinja core/templates/core/user_tools.jinja
419434
msgid "New club"
@@ -1945,11 +1960,6 @@ msgstr "Connexion"
19451960
msgid "Register"
19461961
msgstr "Inscription"
19471962

1948-
#: core/templates/core/base/header.jinja forum/templates/forum/macros.jinja
1949-
#: matmat/templates/matmat/search_form.jinja
1950-
msgid "Search"
1951-
msgstr "Recherche"
1952-
19531963
#: core/templates/core/base/header.jinja
19541964
msgid "Logout"
19551965
msgstr "Déconnexion"
@@ -4294,6 +4304,47 @@ msgstr ""
42944304
msgid "this page"
42954305
msgstr "cette page"
42964306

4307+
#: eboutic/templates/eboutic/eboutic_main.jinja
4308+
msgid "Eurockéennes 2025 partnership"
4309+
msgstr "Partenariat Eurockéennes 2025"
4310+
4311+
#: eboutic/templates/eboutic/eboutic_main.jinja
4312+
msgid ""
4313+
"Our partner uses Weezevent to sell tickets. Weezevent may collect user info "
4314+
"according to its own privacy policy. By clicking the accept button you "
4315+
"consent to their terms of services."
4316+
msgstr ""
4317+
"Notre partenaire utilises Wezevent pour vendre ses billets. Weezevent peut "
4318+
"collecter des informations utilisateur conformément à sa propre politique de "
4319+
"confidentialité. En cliquant sur le bouton d'acceptation vous consentez à "
4320+
"leurs termes de service."
4321+
4322+
#: eboutic/templates/eboutic/eboutic_main.jinja
4323+
msgid "Privacy policy"
4324+
msgstr "Politique de confidentialité"
4325+
4326+
#: eboutic/templates/eboutic/eboutic_main.jinja
4327+
#: trombi/templates/trombi/comment_moderation.jinja
4328+
msgid "Accept"
4329+
msgstr "Accepter"
4330+
4331+
#: eboutic/templates/eboutic/eboutic_main.jinja
4332+
msgid ""
4333+
"You must be subscribed to benefit from the partnership with the Eurockéennes."
4334+
msgstr ""
4335+
"Vous devez être cotisant pour bénéficier du partenariat avec les "
4336+
"Eurockéennes."
4337+
4338+
#: eboutic/templates/eboutic/eboutic_main.jinja
4339+
#, python-format
4340+
msgid ""
4341+
"This partnership offers a discount of up to 33%% on tickets for Friday, "
4342+
"Saturday and Sunday, as well as the 3-day package from Friday to Sunday."
4343+
msgstr ""
4344+
"Ce partenariat permet de profiter d'une réduction jusqu'à 33%% sur les "
4345+
"billets du vendredi, du samedi et du dimanche, ainsi qu'au forfait 3 jours, "
4346+
"du vendredi au dimanche."
4347+
42974348
#: eboutic/templates/eboutic/eboutic_main.jinja
42984349
msgid "There are no items available for sale"
42994350
msgstr "Aucun article n'est disponible à la vente"
@@ -5720,10 +5771,6 @@ msgstr "fin"
57205771
msgid "Moderate Trombi comments"
57215772
msgstr "Modérer les commentaires du Trombi"
57225773

5723-
#: trombi/templates/trombi/comment_moderation.jinja
5724-
msgid "Accept"
5725-
msgstr "Accepter"
5726-
57275774
#: trombi/templates/trombi/comment_moderation.jinja
57285775
msgid "Reject"
57295776
msgstr "Refuser"
@@ -5965,39 +6012,3 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée."
59656012
#, python-format
59666013
msgid "Maximum characters: %(max_length)s"
59676014
msgstr "Nombre de caractères max: %(max_length)s"
5968-
5969-
#: eboutic/templates/eboutic/eboutic_main.jinja
5970-
msgid "Eurockéennes 2025 partnership"
5971-
msgstr "Partenariat Eurockéennes 2025"
5972-
5973-
#: eboutic/templates/eboutic/eboutic_main.jinja
5974-
msgid ""
5975-
"Our partner uses Weezevent to sell tickets. Weezevent may collect user info "
5976-
"according to its own privacy policy. By clicking the accept button you "
5977-
"consent to their terms of services."
5978-
msgstr ""
5979-
"Notre partenaire utilises Wezevent pour vendre ses billets. Weezevent peut "
5980-
"collecter des informations utilisateur conformément à sa propre politique de "
5981-
"confidentialité. En cliquant sur le bouton d'acceptation vous consentez à "
5982-
"leurs termes de service."
5983-
5984-
#: eboutic/templates/eboutic/eboutic_main.jinja
5985-
msgid "Privacy policy"
5986-
msgstr "Politique de confidentialité"
5987-
5988-
#: eboutic/templates/eboutic/eboutic_main.jinja
5989-
msgid ""
5990-
"You must be subscribed to benefit from the partnership with the Eurockéennes."
5991-
msgstr ""
5992-
"Vous devez être cotisant pour bénéficier du partenariat avec les "
5993-
"Eurockéennes."
5994-
5995-
#: eboutic/templates/eboutic/eboutic_main.jinja
5996-
#, python-format
5997-
msgid ""
5998-
"This partnership offers a discount of up to 33%% on tickets for Friday, "
5999-
"Saturday and Sunday, as well as the 3-day package from Friday to Sunday."
6000-
msgstr ""
6001-
"Ce partenariat permet de profiter d'une réduction jusqu'à 33%% sur les "
6002-
"billets du vendredi, du samedi et du dimanche, ainsi qu'au forfait 3 jours, "
6003-
"du vendredi au dimanche."

0 commit comments

Comments
 (0)