Skip to content

Commit 90adb9e

Browse files
committed
apply review comments
1 parent 5c10938 commit 90adb9e

3 files changed

Lines changed: 83 additions & 23 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: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,25 @@ 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 "
168+
"la requête."
169+
159170
#: api/views.py
160171
#, python-format
161172
msgid ""
@@ -167,17 +178,19 @@ msgstr ""
167178

168179
#: api/views.py
169180
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."
181+
msgstr ""
182+
"Vous avez été authentifié avec succès. Vous pouvez maintenant fermer cette "
183+
"page."
171184

172185
#: api/views.py
173186
msgid ""
174187
"Your authentication on the AE website was successful, but an error happened "
175188
"during the interaction with the third-party application. Please contact the "
176189
"managers of the latter."
177190
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."
191+
"Votre authentification sur le site AE a fonctionné, mais une erreur est "
192+
"arrivée durant l'interaction avec l'application tierce. Veuillez contacter "
193+
"les responsables de cette dernière."
181194

182195
#: club/forms.py
183196
msgid "Users to add"

0 commit comments

Comments
 (0)