From 9d0f618e23dec43a450251972cd4e2e05a36cbfb Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 11 Sep 2026 13:06:19 +0200 Subject: [PATCH] refactor(sso): compute the app logout target once in the sso lookup The previous commit wrote the same proxy-aware logout expression into four javascript.js.j2 templates. The rule it encodes - sign out of oauth2-proxy first when the app is proxy-gated, else go straight to the provider - belongs where proxy-gating is already decided. utils/roles/applications/services/sso.py gains logout_url(url, is_proxy_gated) next to get_sso_config, with OAUTH2_SIGN_OUT_PATH as the path constant; the rd value is quoted exactly as Jinja's urlencode filter does it. The sso lookup exposes it as the logout_url term: it renders OIDC through the templar, takes is_proxy_gated from the same resolution, and refuses a context without OIDC. Prometheus, Checkmk, Baserow and Jitsi now render lookup('sso', application_id, 'logout_url'). Behaviour is unchanged: the resolver tests pin the rd encoding against jinja2's do_urlencode, and the lookup tests cover a proxy-gated app, an OIDC-native app, a disabled SSO and a missing OIDC. Co-Authored-By: Claude Opus 5 (1M context) --- plugins/lookup/sso.py | 15 +++++- .../templates/javascript.js.j2 | 2 +- .../templates/javascript.js.j2 | 2 +- .../web-app-jitsi/templates/javascript.js.j2 | 2 +- .../templates/javascript.js.j2 | 2 +- .../plugins/lookup/test_sso_logout_url.py | 51 +++++++++++++++++++ .../roles/applications/services/test_sso.py | 22 ++++++++ utils/roles/applications/services/sso.py | 14 +++++ 8 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 tests/unit/python/plugins/lookup/test_sso_logout_url.py diff --git a/plugins/lookup/sso.py b/plugins/lookup/sso.py index 98455fb33d..3aa8dfd9f5 100644 --- a/plugins/lookup/sso.py +++ b/plugins/lookup/sso.py @@ -8,6 +8,8 @@ API (STRICT): - {{ lookup('sso', application_id, 'flavor') }} → str - {{ lookup('sso', application_id, 'enabled') }} → bool - {{ lookup('sso', application_id, 'shared') }} → bool + - {{ lookup('sso', application_id, 'logout_url') }} → str, oauth2-proxy + sign-out wrapping OIDC.CLIENT.LOGOUT_URL when the app is proxy-gated Wraps ``utils.roles.applications.services.sso.get_sso_config`` so templates and tasks share one source of truth with Python callers @@ -22,7 +24,7 @@ from ansible.errors import AnsibleError from ansible.plugins.loader import lookup_loader from ansible.plugins.lookup import LookupBase -from utils.roles.applications.services.sso import get_sso_config +from utils.roles.applications.services.sso import get_sso_config, logout_url class LookupModule(LookupBase): @@ -51,6 +53,17 @@ class LookupModule(LookupBase): resolved = get_sso_config(applications, application_id) + if want == "logout_url": + if "OIDC" not in vars_: + raise AnsibleError( + "sso: 'logout_url' needs OIDC in the templating context" + ) + oidc = self._templar.template(vars_["OIDC"]) + return [ + logout_url( + str(oidc["CLIENT"]["LOGOUT_URL"]), bool(resolved["is_proxy_gated"]) + ) + ] if want == "all": return [resolved] if want not in resolved: diff --git a/roles/web-app-baserow/templates/javascript.js.j2 b/roles/web-app-baserow/templates/javascript.js.j2 index a8b83f405e..8f947dae32 100644 --- a/roles/web-app-baserow/templates/javascript.js.j2 +++ b/roles/web-app-baserow/templates/javascript.js.j2 @@ -1,5 +1,5 @@ (function () { - const LOGOUT_URL = {{ (('/oauth2/sign_out?rd=' ~ (OIDC.CLIENT.LOGOUT_URL | urlencode)) if (lookup('sso', application_id, 'is_proxy_gated') | bool) else OIDC.CLIENT.LOGOUT_URL) | to_json }}; + const LOGOUT_URL = {{ lookup('sso', application_id, 'logout_url') | to_json }}; const INJECTED_ATTR = "data-injected-logout"; const LOGOUT_SVG = '