From 8f1ea08a6274659f1777326cc7deb32efb5b4daa Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 19 May 2022 22:04:25 +0200 Subject: [PATCH] idp_oidc: add iss and sid parameter to frontchannel_logout_uri (#65475) --- src/authentic2_idp_oidc/utils.py | 7 ++++--- tests/idp_oidc/test_misc.py | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/authentic2_idp_oidc/utils.py b/src/authentic2_idp_oidc/utils.py index 39bdf5cc..76ed2df5 100644 --- a/src/authentic2_idp_oidc/utils.py +++ b/src/authentic2_idp_oidc/utils.py @@ -30,6 +30,7 @@ from jwcrypto.jwt import JWT from authentic2 import hooks from authentic2.attributes_ng.engine import get_attributes from authentic2.utils import crypto +from authentic2.utils.misc import make_url from authentic2.utils.template import Template from . import app_settings @@ -294,13 +295,13 @@ def add_oidc_session(request, client): oidc_sessions = request.session.setdefault('oidc_sessions', {}) if not client.frontchannel_logout_uri: return - uri = client.frontchannel_logout_uri + sid = get_session_id(request, client) + iss = get_issuer(request) + uri = make_url(client.frontchannel_logout_uri, params={'iss': iss, 'sid': sid}, resolve=False) oidc_session = { 'frontchannel_logout_uri': uri, 'frontchannel_timeout': client.frontchannel_timeout, 'name': client.name, - 'sid': get_session_id(request, client), - 'iss': get_issuer(request), } if oidc_sessions.get(uri) == oidc_session: # already present diff --git a/tests/idp_oidc/test_misc.py b/tests/idp_oidc/test_misc.py index 3f7f1188..eb2233ee 100644 --- a/tests/idp_oidc/test_misc.py +++ b/tests/idp_oidc/test_misc.py @@ -19,6 +19,7 @@ import datetime import functools import json import urllib.parse +from unittest import mock import pytest from django.contrib.auth import get_user_model @@ -40,7 +41,13 @@ from authentic2.models import Attribute, AuthorizedRole from authentic2.utils.misc import good_next_url, make_url from authentic2_auth_oidc.utils import parse_timestamp from authentic2_idp_oidc.models import OIDCAccessToken, OIDCAuthorization, OIDCClaim, OIDCClient, OIDCCode -from authentic2_idp_oidc.utils import base64url, get_first_ec_sig_key, get_first_rsa_sig_key, make_sub +from authentic2_idp_oidc.utils import ( + base64url, + get_first_ec_sig_key, + get_first_rsa_sig_key, + get_session_id, + make_sub, +) from .. import utils from .conftest import bearer_authentication_headers, client_authentication_headers @@ -202,7 +209,7 @@ def test_login_from_client_with_home_url(oidc_client, app, simple_user): @pytest.mark.parametrize('do_not_ask_again', [(True,), (False,)]) @pytest.mark.parametrize('login_first', [(True,), (False,)]) def test_authorization_code_sso( - login_first, do_not_ask_again, oidc_client, oidc_settings, simple_user, app, caplog + login_first, do_not_ask_again, oidc_client, oidc_settings, simple_user, app, caplog, rf ): redirect_uri = oidc_client.redirect_uris.split()[0] params = { @@ -398,8 +405,15 @@ def test_authorization_code_sso( response = app.get(make_url('account_management')) response = response.click('Logout') if oidc_client.frontchannel_logout_uri: - iframes = response.pyquery('iframe[src="https://example.com/southpark/logout/"]') + iframes = response.pyquery('iframe[src^="https://example.com/southpark/logout/"]') assert iframes + src = iframes.attr('src') + assert '?' in src + src_qd = QueryDict(src.split('?', 1)[1]) + assert 'iss' in src_qd and src_qd['iss'] == 'http://testserver/' + assert 'sid' in src_qd and src_qd['sid'] == get_session_id( + mock.Mock(session=app.session), oidc_client + ) if oidc_client.frontchannel_timeout: assert iframes.attr('onload').endswith(', %d)' % oidc_client.frontchannel_timeout) else: -- 2.35.1