From 1145f61c78b39e12e12d42177c9825026c0a1396 Mon Sep 17 00:00:00 2001 From: bmccandless Date: Tue, 29 Sep 2020 13:42:24 -0700 Subject: [PATCH] auth: logging out should keep the user on the same page (#1877) previous behavior is that logout would redirect to the index page. --- server/auth/auth_oauth.py | 25 +++++++++++++++++++++++-- server/test/unit/auth/test_oauth.py | 4 ++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/server/auth/auth_oauth.py b/server/auth/auth_oauth.py index a5107934..a2b6077f 100644 --- a/server/auth/auth_oauth.py +++ b/server/auth/auth_oauth.py @@ -114,6 +114,7 @@ class AuthTypeOAuth(AuthTypeClientBase): parse = urlparse(self.api_base_url) app.add_url_rule(f"{parse.path}/login", "login", self.login, methods=["GET"]) app.add_url_rule(f"{parse.path}/logout", "logout", self.logout, methods=["GET"]) + app.add_url_rule(f"{parse.path}/logout_redirect", "logout_redirect", self.logout_redirect, methods=["GET"]) app.add_url_rule(f"{parse.path}/oauth2/callback", "callback", self.callback, methods=["GET"]) def complete_setup(self, flask_app): @@ -166,12 +167,29 @@ class AuthTypeOAuth(AuthTypeClientBase): return response def logout(self): + """ + We would like for the user to remain on the same dataset after logout. oauth requires that + the redirect `returnTo` path be whitelisted by the oauth server, therefore a level of + indirection is used. We first redirect to a single path "logout_redirect", and logout_redirect + will redirect the user's browser back to the current page. + """ self.remove_tokens() - params = {"returnTo": self.web_base_url, "client_id": self.client_id} + redirect_path = request.args.get("dataset", "") + redirect_to = f"{self.web_base_url}/{redirect_path}" + session["oauth_logout_redirect"] = redirect_to + + return_to = f"{self.api_base_url}/logout_redirect" + params = {"returnTo": return_to, "client_id": self.client_id} response = redirect(self.client.api_base_url + "/v2/logout?" + urlencode(params)) self.update_response(response) return response + def logout_redirect(self): + oauth_logout_redirect = session.pop("oauth_logout_redirect", "/") + response = redirect(oauth_logout_redirect) + self.update_response(response) + return response + def callback(self): data = self.client.authorize_access_token() tokens = Tokens( @@ -253,7 +271,10 @@ class AuthTypeOAuth(AuthTypeClientBase): def get_logout_url(self, data_adaptor): """Return the url for the logout route""" - return f"{self.api_base_url}/logout" + if data_adaptor and current_app.app_config.is_multi_dataset(): + return f"{self.api_base_url}/logout?dataset={data_adaptor.uri_path}/" + else: + return f"{self.api_base_url}/logout" def check_jwt_payload(self, id_token): try: diff --git a/server/test/unit/auth/test_oauth.py b/server/test/unit/auth/test_oauth.py index d5be070b..728fccfe 100644 --- a/server/test/unit/auth/test_oauth.py +++ b/server/test/unit/auth/test_oauth.py @@ -112,7 +112,7 @@ class AuthTest(unittest.TestCase): logout_uri = config["config"]["authentication"]["logout"] self.assertEqual(login_uri, f"{server}/login?dataset=d/pbmc3k.cxg/") - self.assertEqual(logout_uri, f"{server}/logout") + self.assertEqual(logout_uri, f"{server}/logout?dataset=d/pbmc3k.cxg/") r = session.get(login_uri) # check that the login redirect worked @@ -151,7 +151,7 @@ class AuthTest(unittest.TestCase): r = session.get(logout_uri) # check that the logout redirect worked self.assertEqual(r.history[0].status_code, 302) - self.assertEqual(r.url, f"{server}") + self.assertEqual(r.url, f"{server}/d/pbmc3k.cxg/") config = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/config").json() userinfo = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json() self.assertFalse(userinfo["userinfo"]["is_authenticated"])