33
44import pydantic
55import requests
6+ import sentry_sdk
67from django .conf import settings
78from django .contrib import messages
89from django .contrib .auth .mixins import LoginRequiredMixin
9- from django .core . exceptions import PermissionDenied
10+ from django .shortcuts import render
1011from django .urls import reverse , reverse_lazy
1112from django .utils .translation import gettext as _
1213from django .views .generic import FormView , TemplateView
@@ -25,11 +26,14 @@ class ThirdPartyAuthView(LoginRequiredMixin, FormView):
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 ):
5572 self .params = self .parse_params ()
73+ if not self .params :
74+ # if parameters parsing failed, shortcut the operation and display
75+ # an empty page with just the error messages.
76+ if not request .user .is_authenticated :
77+ return self .handle_no_permission ()
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
0 commit comments