+ def idp_initiated_logout(self):
+ """
+ Logout all SP sessions when the logout comes from the IdP.
+
+ For the current user only.
+
+ Only use HTTP-Redirect to start the logout. This is guaranteed
+ to be supported in SAML 2.
+ """
+ self.debug("IdP-initiated SAML2 logout")
+ us = UserSession()
+ user = us.get_user()
+
+ saml_sessions = self.sessionfactory
+ # pylint: disable=unused-variable
+ (mech, session) = saml_sessions.get_next_logout(
+ logout_mechs=[lasso.SAML2_METADATA_BINDING_REDIRECT])
+ if session is None:
+ return
+
+ logout = self.idp.get_logout_handler()
+ logout.setSessionFromDump(session.login_session)
+ logout.initRequest(session.provider_id)
+ try:
+ logout.buildRequestMsg()
+ except lasso.Error, e:
+ self.error('failure to build logout request msg: %s' % e)
+ raise cherrypy.HTTPRedirect(400, 'Failed to log out user: %s '
+ % e)
+
+ # Add a fake session to indicate where the user should
+ # be redirected to when all SP's are logged out.
+ idpurl = self._root.instance_base_url()
+ session_id = "_" + uuid.uuid4().hex.upper()
+ saml_sessions.add_session(session_id, idpurl, user.name, "", "",
+ [lasso.SAML2_METADATA_BINDING_REDIRECT])
+ init_session = saml_sessions.get_session_by_id(session_id)
+ saml_sessions.start_logout(init_session, relaystate=idpurl)
+
+ # Add the logout request id we just created to the session to be
+ # logged out so that when it responds we can find the right
+ # session.
+ session.set_logoutstate(request_id=logout.request.id)
+ saml_sessions.start_logout(session, initial=False)
+
+ self.debug('Sending initial logout request to %s' % logout.msgUrl)
+ raise cherrypy.HTTPRedirect(logout.msgUrl)
+