From 43f0a85dd5c19e9ddeb1c4b7563508339f9ec6cb Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 14 Dec 2018 01:44:45 +0100 Subject: [PATCH] pass id_token on logout from FranceConnect (fixes #28997) --- tests/test_fc_auth.py | 8 +++++--- wcs/qommon/ident/franceconnect.py | 12 +++++++++--- wcs/root.py | 5 ++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/test_fc_auth.py b/tests/test_fc_auth.py index 44b211b6e..8b446f104 100644 --- a/tests/test_fc_auth.py +++ b/tests/test_fc_auth.py @@ -168,9 +168,11 @@ def test_fc_login_page(caplog): assert session.extra_user_variables['fc_sub'] == 'ymca' resp = app.get('/logout') - assert resp.location.endswith('/ident/fc/logout') - resp = resp.follow() - assert resp.location == 'https://fcp.integ01.dev-franceconnect.fr/api/v1/logout?post_logout_redirect_uri=http%3A%2F%2Fexample.net' + splitted = urlparse.urlsplit(resp.location) + assert urlparse.urlunsplit((splitted.scheme, splitted.netloc, splitted.path, '', '')) \ + == 'https://fcp.integ01.dev-franceconnect.fr/api/v1/logout' + assert urlparse.parse_qs(splitted.query)['post_logout_redirect_uri'] == ['http://example.net'] + assert urlparse.parse_qs(splitted.query)['id_token_hint'] assert not get_session(app) # Test error handling path diff --git a/wcs/qommon/ident/franceconnect.py b/wcs/qommon/ident/franceconnect.py index 416cbd28f..56d1ac679 100644 --- a/wcs/qommon/ident/franceconnect.py +++ b/wcs/qommon/ident/franceconnect.py @@ -327,13 +327,14 @@ class FCAuthMethod(AuthMethod): return None # check id_token nonce id_token = result['id_token'] + access_token = result['access_token'] header, payload, signature = id_token.split('.') payload = json_loads(base64url_decode(payload)) nonce = hashlib.sha256(str(session.id)).hexdigest() if payload['nonce'] != nonce: logger.error('FranceConnect returned nonce did not match') return None - return result['access_token'] + return access_token, id_token def get_user_info(self, access_token): logger = get_logger() @@ -436,7 +437,7 @@ class FCAuthMethod(AuthMethod): logger.error(_('FranceConnect authentication failed: %s'), _(msg) if msg else error) return redirect(next_url) - access_token = self.get_access_token(request.form['code']) + access_token, id_token = self.get_access_token(request.form['code']) if not access_token: return redirect(next_url) user_info = self.get_user_info(access_token) @@ -448,7 +449,8 @@ class FCAuthMethod(AuthMethod): session_var_fc_user = {} for key in flattened_user_info: session_var_fc_user['fc_' + key] = flattened_user_info[key] - + session_var_fc_user['fc_access_token'] = access_token + session_var_fc_user['fc_id_token'] = id_token # Lookup or create user sub = user_info['sub'] user = None @@ -471,9 +473,13 @@ class FCAuthMethod(AuthMethod): return redirect(next_url) def logout(self): + session = get_session() + id_token = session.extra_user_variables['fc_id_token'] + get_session_manager().expire_session() logout_url = self.get_logout_url() post_logout_redirect_uri = get_publisher().get_frontoffice_url() logout_url += '?' + urllib.urlencode({ + 'id_token_hint': id_token, 'post_logout_redirect_uri': post_logout_redirect_uri, }) return redirect(logout_url) diff --git a/wcs/root.py b/wcs/root.py index 8068e956a..50c822c69 100644 --- a/wcs/root.py +++ b/wcs/root.py @@ -265,9 +265,8 @@ class RootDirectory(Directory): return redirect(get_publisher().get_root_url()) ident_methods = get_cfg('identification', {}).get('methods', []) - if 'fc' in ident_methods and session.extra_user_variables and 'fc_sub' in session.extra_user_variables: - get_session_manager().expire_session() - return redirect(get_publisher().get_root_url() + 'ident/fc/logout') + if 'fc' in ident_methods and session.extra_user_variables and 'fc_id_token' in session.extra_user_variables: + return get_publisher().ident_methods['fc']().logout() if not 'idp' in ident_methods: get_session_manager().expire_session()