11import  json 
2+ import  warnings 
23from  urllib .parse  import  urlparse 
34
45from  django .contrib .auth  import  logout 
@@ -225,6 +226,8 @@ def validate_logout_request(request, id_token_hint, client_id, post_logout_redir
225226    will be validated against each other. 
226227    """ 
227228
229+     warnings .warn ("This method is deprecated and will be removed in version 2.5.0." , DeprecationWarning )
230+ 
228231    id_token  =  None 
229232    must_prompt_logout  =  True 
230233    token_user  =  None 
@@ -315,17 +318,16 @@ def get(self, request, *args, **kwargs):
315318        state  =  request .GET .get ("state" )
316319
317320        try :
318-             prompt , (redirect_uri , application ), token_user  =  validate_logout_request (
319-                 request = request ,
321+             application , token_user  =  self .validate_logout_request (
320322                id_token_hint = id_token_hint ,
321323                client_id = client_id ,
322324                post_logout_redirect_uri = post_logout_redirect_uri ,
323325            )
324326        except  OIDCError  as  error :
325327            return  self .error_response (error )
326328
327-         if  not  prompt :
328-             return  self .do_logout (application , redirect_uri , state , token_user )
329+         if  not  self . must_prompt ( token_user ) :
330+             return  self .do_logout (application , post_logout_redirect_uri , state , token_user )
329331
330332        self .oidc_data  =  {
331333            "id_token_hint" : id_token_hint ,
@@ -347,21 +349,100 @@ def form_valid(self, form):
347349        state  =  form .cleaned_data .get ("state" )
348350
349351        try :
350-             prompt , (redirect_uri , application ), token_user  =  validate_logout_request (
351-                 request = self .request ,
352+             application , token_user  =  self .validate_logout_request (
352353                id_token_hint = id_token_hint ,
353354                client_id = client_id ,
354355                post_logout_redirect_uri = post_logout_redirect_uri ,
355356            )
356357
357-             if  not  prompt  or  form .cleaned_data .get ("allow" ):
358-                 return  self .do_logout (application , redirect_uri , state , token_user )
358+             if  not  self . must_prompt ( token_user )  or  form .cleaned_data .get ("allow" ):
359+                 return  self .do_logout (application , post_logout_redirect_uri , state , token_user )
359360            else :
360361                raise  LogoutDenied ()
361362
362363        except  OIDCError  as  error :
363364            return  self .error_response (error )
364365
366+     def  validate_post_logout_redirect_uri (self , application , post_logout_redirect_uri ):
367+         """ 
368+         Validate the OIDC RP-Initiated Logout Request post_logout_redirect_uri parameter 
369+         """ 
370+ 
371+         if  not  post_logout_redirect_uri :
372+             return 
373+ 
374+         if  not  application :
375+             raise  InvalidOIDCClientError ()
376+         scheme  =  urlparse (post_logout_redirect_uri )[0 ]
377+         if  not  scheme :
378+             raise  InvalidOIDCRedirectURIError ("A Scheme is required for the redirect URI." )
379+         if  oauth2_settings .OIDC_RP_INITIATED_LOGOUT_STRICT_REDIRECT_URIS  and  (
380+             scheme  ==  "http"  and  application .client_type  !=  "confidential" 
381+         ):
382+             raise  InvalidOIDCRedirectURIError ("http is only allowed with confidential clients." )
383+         if  scheme  not  in application .get_allowed_schemes ():
384+             raise  InvalidOIDCRedirectURIError (f'Redirect to scheme "{ scheme }  )
385+         if  not  application .post_logout_redirect_uri_allowed (post_logout_redirect_uri ):
386+             raise  InvalidOIDCRedirectURIError ("This client does not have this redirect uri registered." )
387+ 
388+     def  validate_logout_request_user (self , id_token_hint , client_id ):
389+         """ 
390+         Validate the an OIDC RP-Initiated Logout Request user 
391+         """ 
392+ 
393+         if  not  id_token_hint :
394+             return 
395+ 
396+         # Only basic validation has been done on the IDToken at this point. 
397+         id_token , claims  =  _load_id_token (id_token_hint )
398+ 
399+         if  not  id_token  or  not  _validate_claims (self .request , claims ):
400+             raise  InvalidIDTokenError ()
401+ 
402+         # If both id_token_hint and client_id are given it must be verified that they match. 
403+         if  client_id :
404+             if  id_token .application .client_id  !=  client_id :
405+                 raise  ClientIdMissmatch ()
406+ 
407+         return  id_token 
408+ 
409+     def  get_request_application (self , id_token , client_id ):
410+         if  client_id :
411+             return  get_application_model ().objects .get (client_id = client_id )
412+         if  id_token :
413+             return  id_token .application 
414+ 
415+     def  validate_logout_request (self , id_token_hint , client_id , post_logout_redirect_uri ):
416+         """ 
417+         Validate an OIDC RP-Initiated Logout Request. 
418+         `(application, token_user)` is returned. 
419+ 
420+         If it is set, `application` is the Application that is requesting the logout. 
421+         `token_user` is the id_token user, which will used to revoke the tokens if found. 
422+ 
423+         The `id_token_hint` will be validated if given. If both `client_id` and `id_token_hint` are given they 
424+         will be validated against each other. 
425+         """ 
426+ 
427+         id_token  =  self .validate_logout_request_user (id_token_hint , client_id )
428+         application  =  self .get_request_application (id_token , client_id )
429+         self .validate_post_logout_redirect_uri (application , post_logout_redirect_uri )
430+ 
431+         return  application , id_token .user  if  id_token  else  None 
432+ 
433+     def  must_prompt (self , token_user ):
434+         """Indicate whether the logout has to be confirmed by the user. This happens if the 
435+         specifications force a confirmation, or it is enabled by `OIDC_RP_INITIATED_LOGOUT_ALWAYS_PROMPT`. 
436+ 
437+         A logout without user interaction (i.e. no prompt) is only allowed 
438+         if an ID Token is provided that matches the current user. 
439+         """ 
440+         return  (
441+             oauth2_settings .OIDC_RP_INITIATED_LOGOUT_ALWAYS_PROMPT 
442+             or  token_user  is  None 
443+             or  token_user  !=  self .request .user 
444+         )
445+ 
365446    def  do_logout (self , application = None , post_logout_redirect_uri = None , state = None , token_user = None ):
366447        user  =  token_user  or  self .request .user 
367448        # Delete Access Tokens if a user was found 
0 commit comments