def _logout(self): logger.debug('user logout') try: session = UserSession(flask.session) except UninitialisedSession as e: logger.info('user was already logged out, doing nothing') return None id_token_jwt = session.id_token_jwt client = self.clients[session.current_provider] session.clear() if client.provider_end_session_endpoint: flask.session['end_session_state'] = rndstr() end_session_request = EndSessionRequest( id_token_hint=id_token_jwt, post_logout_redirect_uri=self._get_post_logout_redirect_uri( client), state=flask.session['end_session_state']) logger.debug('send endsession request: %s', end_session_request.to_json()) return redirect( end_session_request.request( client.provider_end_session_endpoint), 303) return None
def __call__(self): client = self.context.get_oauth2_client() # session = Session(self.request, use_session_data_manager=self.context.use_session_data_manager) # state is used to keep track of responses to outstanding requests (state). # https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/java/logout.adoc # session.set('end_session_state', rndstr()) args = { # 'state': session.get('end_session_state'), # TODO: .... # 'post_logout_redirect_uri': api.portal.get().absolute_url(), "redirect_uri": api.portal.get().absolute_url(), } pas = getToolByName(self.context, "acl_users") auth_cookie_name = pas.credentials_cookie_auth.cookie_name # end_req = client.construct_EndSessionRequest(request_args=args) end_req = EndSessionRequest(**args) logout_url = end_req.request(client.end_session_endpoint) self.request.response.setHeader("Cache-Control", "no-cache, must-revalidate") # TODO: change path with portal_path self.request.response.expireCookie(auth_cookie_name, path="/") self.request.response.expireCookie("auth_token", path="/") self.request.response.redirect(logout_url) return
def end_session_endpoint(): if flask.request.method == 'GET': # redirect from RP end_session_request = EndSessionRequest().deserialize(urlencode(flask.request.args)) flask.session['end_session_request'] = end_session_request.to_dict() return render_template('logout.jinja2') else: form = parse_qs(flask.request.get_data().decode('utf-8')) if 'logout' in form: return do_logout(EndSessionRequest().from_dict(flask.session['end_session_request'])) else: return make_response('You chose not to logout')
def _logout(self): id_token_jwt = flask.session['id_token_jwt'] flask.session.clear() if 'end_session_endpoint' in self.client.provider_info: flask.session['end_session_state'] = rndstr() end_session_request = EndSessionRequest( id_token_hint=id_token_jwt, post_logout_redirect_uri=self.client_registration_info['post_logout_redirect_uris'][0], state=flask.session['end_session_state']) return redirect(end_session_request.request(self.client.provider_info['end_session_endpoint']), 303) return None
def logout(): end_session_request = EndSessionRequest().deserialize( urlencode(request.args)) session['end_session_request'] = end_session_request.to_dict() try: redirect_url = logout_user() except InvalidSubjectIdentifier as error: raise BadRequest('Logout unsuccessful') return render_template('views/logout_info.html', next_url=redirect_url)
def test_parse_end_session_request(self): esreq = EndSessionRequest(id_token=IDTOKEN.to_jwt(key=KC_SYM_S.get( alg2keytype("HS256")), algorithm="HS256"), redirect_url="http://example.org/jqauthz", state="state0") request = self.srv.parse_end_session_request( query=esreq.to_urlencoded()) assert isinstance(request, EndSessionRequest) assert _eq(request.keys(), ['id_token', 'redirect_url', 'state']) assert request["state"] == "state0" assert request["id_token"]["aud"] == ["client_1"]
def test_parse_end_session_request(self): esreq = EndSessionRequest( id_token=IDTOKEN.to_jwt(key=KC_SYM_S.get(alg2keytype("HS256")), algorithm="HS256"), redirect_url="http://example.org/jqauthz", state="state0") request = self.srv.parse_end_session_request( query=esreq.to_urlencoded()) assert isinstance(request, EndSessionRequest) assert _eq(request.keys(), ['id_token', 'redirect_url', 'state']) assert request["state"] == "state0" assert request["id_token"]["aud"] == ["client_1"]
def end_session_endpoint(): if flask.request.method == "GET": # redirect from RP end_session_request = EndSessionRequest().deserialize( urlencode(flask.request.args)) flask.session["end_session_request"] = end_session_request.to_dict() return render_template("logout.jinja2") else: form = parse_qs(flask.request.get_data().decode("utf-8")) if "logout" in form: return do_logout(EndSessionRequest().from_dict( flask.session["end_session_request"])) else: return make_response("You chose not to logout")
def _provider_logout_url(id_token_jwt): client = current_app.extensions['oidc_client'] endpoint = client.client.provider_info.get('end_session_endpoint') logout_urls = client.client_registration_info['post_logout_redirect_uris'] if not endpoint: return None session['end_session_state'] = rndstr() end_session_request = EndSessionRequest( id_token_hint=id_token_jwt, post_logout_redirect_uri=logout_urls[0], state=session['end_session_state']) return end_session_request.request(endpoint)
def logout_user(self, subject_identifier=None, end_session_request=None): # type: (Optional[str], Optional[oic.oic.message.EndSessionRequest]) -> None if not end_session_request: end_session_request = EndSessionRequest() if 'id_token_hint' in end_session_request: id_token = IdToken().from_jwt(end_session_request['id_token_hint'], key=[self.signing_key]) subject_identifier = id_token['sub'] self.authz_state.delete_state_for_subject_identifier(subject_identifier)
def test_no_post_logout_redirect_uri(self): self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [ "https://example.com/plru", "https://example.com/plru2", ] esr = EndSessionRequest(state="foo") assert self.provider.verify_post_logout_redirect_uri(esr, CLIENT_ID) is None
def test_wrong_post_logout_redirect_uri(self): self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [ "https://example.com/plru" ] esr = EndSessionRequest( state="foo", post_logout_redirect_uri="https://localhost:8087/plru") assert self.provider.verify_post_logout_redirect_uri(esr, CLIENT_ID) is None
def _logout(self): logger.debug('user logout') id_token_jwt = flask.session['id_token_jwt'] flask.session.clear() if 'end_session_endpoint' in self.client.provider_info: flask.session['end_session_state'] = rndstr() end_session_request = EndSessionRequest( id_token_hint=id_token_jwt, post_logout_redirect_uri=self. client_registration_info['post_logout_redirect_uris'][0], state=flask.session['end_session_state']) logger.debug('send endsession request: %s', end_session_request.to_json()) return redirect( end_session_request.request( self.client.provider_info['end_session_endpoint']), 303) return None
def test_let_user_verify_logout(self): self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [ "https://localhost:8087/plru" ] esr = EndSessionRequest( state="foo", post_logout_redirect_uri="https://localhost:8087/plru") res = self.provider.let_user_verify_logout("user", esr, None, None) assert isinstance(res, Response) assert res.headers == [("Content-type", "text/html")] assert res.status_code == 200
def test_post_logout_redirect_with_unknown_post_logout_redirect_uri(self): auth_req = AuthorizationRequest( response_type='code id_token token', scope='openid', client_id='client1', redirect_uri='https://client.example.com/redirect') auth_resp = self.provider.authorize(auth_req, 'user1') end_session_request = EndSessionRequest( id_token_hint=auth_resp['id_token'], post_logout_redirect_uri='https://client.example.com/unknown') assert self.provider.do_post_logout_redirect( end_session_request) is None
def do_logout(): end_session_request = EndSessionRequest().deserialize(urlencode(flask.request.args)).to_dict() try: current_app.provider.logout_user(end_session_request=end_session_request) except InvalidSubjectIdentifier as e: return make_response('Logout unsuccessful!', 400) redirect_url = current_app.provider.do_post_logout_redirect(end_session_request) if redirect_url: return redirect(redirect_url, 303) return make_response('Logout successful!')
def _logout(self): logger.debug('user logout') session = UserSession(flask.session) id_token_jwt = session.id_token_jwt client = self.clients[session.current_provider] session.clear() if client.provider_end_session_endpoint: flask.session['end_session_state'] = rndstr() end_session_request = EndSessionRequest( id_token_hint=id_token_jwt, post_logout_redirect_uri=self._get_post_logout_redirect_uri(), state=flask.session['end_session_state']) logger.debug('send endsession request: %s', end_session_request.to_json()) return redirect( end_session_request.request( client.provider_end_session_endpoint), 303) return None
def logout_user(): params = session['end_session_request'] current_app.logger.info("logout_user:{}".format(params)) params.update({'id_token_hint': session['id_token_jwt']}) current_app.logger.info("logout_user_post_update:{}".format(params)) request = EndSessionRequest().from_dict(params) current_app.provider.logout_user(end_session_request=request) return current_app.provider.do_post_logout_redirect(request)
def test_post_logout_redirect(self): auth_req = AuthorizationRequest( response_type='code id_token token', scope='openid', client_id='client1', redirect_uri='https://client.example.com/redirect') auth_resp = self.provider.authorize(auth_req, 'user1') end_session_request = EndSessionRequest( id_token_hint=auth_resp['id_token'], post_logout_redirect_uri='https://client.example.com/post_logout', state='state') redirect_url = self.provider.do_post_logout_redirect( end_session_request) assert redirect_url == EndSessionResponse( state='state').request('https://client.example.com/post_logout')
def test_logout_user_with_id_token_hint(self): auth_req = AuthorizationRequest( response_type='code id_token token', scope='openid', client_id='client1', redirect_uri='https://client.example.com/redirect') auth_resp = self.provider.authorize(auth_req, 'user1') self.provider.logout_user(end_session_request=EndSessionRequest( id_token_hint=auth_resp['id_token'])) with pytest.raises(InvalidAccessToken): self.provider.authz_state.introspect_access_token( auth_resp['access_token']) with pytest.raises(InvalidAuthorizationCode): self.provider.authz_state.exchange_code_for_token( auth_resp['code'])
def test_let_user_verify_logout_with_redirect(self): self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [ "https://localhost:8087/plru" ] esr = EndSessionRequest( state="foo", post_logout_redirect_uri="https://localhost:8087/plru") res = self.provider.let_user_verify_logout( "user", esr, None, "https://example.com/redirect") assert isinstance(res, Response) assert set(res.headers) == {("Content-type", "text/html")} assert res.status_code == 200 # make sure the redirect was propagated txt = '<input type="hidden" name="{}" value="{}"/>'.format( "post_logout_redirect_uri", "https://localhost:8087/plru") assert txt in res.message
def test_missing_post_logout_redirect_uri(self): esr = EndSessionRequest(state="foo") assert self.provider.verify_post_logout_redirect_uri(esr, CLIENT_ID) is None
def test_post_logout_redirect_without_post_logout_redirect_uri(self): assert self.provider.do_post_logout_redirect( EndSessionRequest()) is None
def test_post_logout_redirect_with_unknown_client_for_post_logout_redirect_uri( self): end_session_request = EndSessionRequest( post_logout_redirect_uri='https://client.example.com/post_logout') assert self.provider.do_post_logout_redirect( end_session_request) is None
application_type="web") RSREQ = RefreshSessionRequest(id_token="id_token", redirect_url="http://example.com/authz", state="state0") #key, type, usage, owner="." alg = "HS256" ktype = alg2keytype(alg) keys = KC_SYM_S.get(ktype) CSREQ = CheckSessionRequest( id_token=IDTOKEN.to_jwt(key=keys, algorithm="HS256")) ESREQ = EndSessionRequest(id_token=IDTOKEN.to_jwt(key=keys, algorithm="HS256"), redirect_url="http://example.org/jqauthz", state="state0") UINFO = Claims(name={"essential": True}, nickname=None, email={"essential": True}, email_verified={"essential": True}, picture=None) IDT2 = Claims(auth_time={ "essential": True, "acr": { "values": ["urn:mace:incommon:iap:silver"] } })