@@ -237,6 +237,30 @@ def do_provider_info(self, client=None, state='', behaviour_args=None):
237237 except KeyError :
238238 return _context .get ('issuer' )
239239
240+ def add_callbacks (self , context ):
241+ _iss = context .get ('issuer' )
242+ # Create the necessary callback URLs
243+ # as a side effect self.hash2issuer is set
244+ _extra_uris = {
245+ "request_uri" : False ,
246+ "backchannel_logout_uri" : False ,
247+ "frontchannel_logout_uri" : False
248+ }
249+ _pi = context .get ('provider_info' )
250+ _cp = context .config .get ("client_preferences" )
251+ if 'require_request_uri_registration' in _pi and "request_uri_usable" in _cp :
252+ _extra_uris ['request_uri' ] = True
253+ if 'frontchannel_logout_supported' in _pi and "frontchannel_logout_usable" in _cp :
254+ _extra_uris ["frontchannel_logout_uri" ] = True
255+ if 'backchannel_logout_supported' in _pi and "backchannel_logout_usable" in _cp :
256+ _extra_uris ["backchannel_logout_uri" ] = True
257+
258+ callbacks = self .create_callbacks (_iss , ** _extra_uris )
259+
260+ context .set ('redirect_uris' , [
261+ v for k , v in callbacks .items () if not k .startswith ('__' )])
262+ context .set ('callback' , callbacks )
263+
240264 def do_client_registration (self , client = None ,
241265 iss_id : Optional [str ] = '' ,
242266 state : Optional [str ] = '' ,
@@ -266,16 +290,7 @@ def do_client_registration(self, client=None,
266290
267291 if not _context .client_id : # means I have to do dynamic client registration
268292 if not _context .get ('redirect_uris' ):
269- # Create the necessary callback URLs
270- # as a side effect self.hash2issuer is set
271- if 'require_request_uri_registration' in _context .get ('provider_info' ):
272- callbacks = self .create_callbacks (_iss , request_uri = True )
273- else :
274- callbacks = self .create_callbacks (_iss )
275-
276- _context .set ('redirect_uris' , [
277- v for k , v in callbacks .items () if not k .startswith ('__' )])
278- _context .set ('callback' , callbacks )
293+ self .add_callbacks (_context )
279294
280295 if behaviour_args :
281296 _params = RegistrationRequest ().parameters ()
@@ -285,19 +300,6 @@ def do_client_registration(self, client=None,
285300
286301 load_registration_response (client , request_args = request_args )
287302
288- def add_callbacks (self , service_context ):
289- _iss = service_context .get ('issuer' )
290-
291- if 'require_request_uri_registration' in service_context .get ('provider_info' ):
292- _callbacks = self .create_callbacks (_iss , request_uri = True )
293- else :
294- _callbacks = self .create_callbacks (_iss )
295-
296- service_context .set ('redirect_uris' , [
297- v for k , v in _callbacks .items () if not k .startswith ('__' )])
298- service_context .set ('callback' , _callbacks )
299- return _callbacks
300-
301303 def do_webfinger (self , user ):
302304 """
303305 Does OpenID Provider Issuer discovery using webfinger.
@@ -356,12 +358,16 @@ def client_setup(self, iss_id='', user='', behaviour_args=None):
356358 self .issuer2rp [issuer ] = client
357359 return client
358360
359- def create_callbacks (self , issuer , request_uri = False ):
361+ def create_callbacks (self , issuer , request_uri = False , backchannel_logout_uri = False ,
362+ frontchannel_logout_uri = False ):
360363 """
361364 To mitigate some security issues the redirect_uris should be OP/AS
362365 specific. This method creates a set of redirect_uris unique to the
363366 OP/AS.
364367
368+ :param frontchannel_logout_uri: Whether a front-channel logout uri should be constructed
369+ :param backchannel_logout_uri: Whether a back-channel logout uri should be constructed
370+ :param request_uri: Whether a request_uri should be constructed
365371 :param issuer: Issuer ID
366372 :return: A set of redirect_uris
367373 """
@@ -379,6 +385,15 @@ def create_callbacks(self, issuer, request_uri=False):
379385 if request_uri :
380386 res ["request_uri" ] = f"{ self .base_url } /req_uri/{ _hex } "
381387
388+ if backchannel_logout_uri or frontchannel_logout_uri :
389+ res ["post_logout_redirect_uris" ] = f"{ self .base_url } /session_logout/{ _hex } "
390+
391+ if backchannel_logout_uri :
392+ res ["backchannel_logout_uri" ] = f"{ self .base_url } /bc_logout/{ _hex } "
393+ if frontchannel_logout_uri :
394+ res ["frontchannel_logout_uri" ] = f"{ self .base_url } /fc_logout/{ _hex } "
395+
396+ logger .debug (f"Created callback URIs: { res } " )
382397 return res
383398
384399 def _get_response_type (self , context , req_args : Optional [dict ] = None ):
@@ -678,7 +693,7 @@ def finalize_auth(self, client, issuer: str, response: dict,
678693
679694 def get_access_and_id_token (self , authorization_response = None ,
680695 state : Optional [str ] = '' ,
681- client : Optional [object ] = None ,
696+ client : Optional [object ] = None ,
682697 behaviour_args : Optional [dict ] = None ):
683698 """
684699 There are a number of services where access tokens and ID tokens can
@@ -830,7 +845,8 @@ def finalize(self, issuer, response, behaviour_args: Optional[dict] = None):
830845 'userinfo' : inforesp ,
831846 'state' : authorization_response ['state' ],
832847 'token' : token ['access_token' ],
833- 'id_token' : _id_token
848+ 'id_token' : _id_token ,
849+ 'session_state' : authorization_response .get ('session_state' , '' )
834850 }
835851
836852 def has_active_authentication (self , state ):
@@ -898,7 +914,9 @@ def get_valid_access_token(self, state):
898914 else :
899915 raise OidcServiceError ('No valid access token' )
900916
901- def logout (self , state , client = None , post_logout_redirect_uri = '' ):
917+ def logout (self , state : str ,
918+ client : Optional [Client ] = None ,
919+ post_logout_redirect_uri : Optional [str ] = '' ) -> dict :
902920 """
903921 Does a RP initiated logout from an OP. After logout the user will be
904922 redirect by the OP to a URL of choice (post_logout_redirect_uri).
@@ -929,6 +947,17 @@ def logout(self, state, client=None, post_logout_redirect_uri=''):
929947
930948 return resp
931949
950+ def close (self , state : str ,
951+ issuer : Optional [str ] = '' ,
952+ post_logout_redirect_uri : Optional [str ] = '' ) -> dict :
953+ if issuer :
954+ client = self .issuer2rp [issuer ]
955+ else :
956+ client = self .get_client_from_session_key (state )
957+
958+ return self .logout (state = state , client = client ,
959+ post_logout_redirect_uri = post_logout_redirect_uri )
960+
932961 def clear_session (self , state ):
933962 client = self .get_client_from_session_key (state )
934963 client .client_get ("service_context" ).state .remove_state (state )
0 commit comments