From 7e375d1fb823ee80850ab989209986dbb38063d6 Mon Sep 17 00:00:00 2001 From: Bartosz Woronicz Date: Thu, 10 Oct 2024 20:36:37 +0200 Subject: [PATCH] add ability to manage OIDCResponseType In the certains situation customers using tools like Authentik or Zitadel may encounter issue with using id_token as in that case it may also return access_token despite not set deliberately The `code` flow is now the preffered approach for OIDC hence the ability for setting that options gives more flexibility. Implements: oidc-response-type option Closes-Bug: #2084184 Change-Id: I251dffbdf97998998066d5efd2d8d9386ecd19e5 --- config.yaml | 8 ++++++++ src/charm.py | 28 ++++++++++++++++++++++++++ templates/apache-openidc-location.conf | 4 +++- unit_tests/test_charm.py | 10 +++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 9c7eaa6..717d3e8 100644 --- a/config.yaml +++ b/config.yaml @@ -94,6 +94,14 @@ options: 'client-cookie:persistent:store_id_token'. When using multiple units of Keystone behind a proxy, use 'client-cookie:persistent' if you are not using shared session storage for Keystone. + oidc-response-type: + default: 'id_token' + type: string + description: | + Define the OIDCResponseType for mod_auth_openidc uses limit + the responses type. It must be one of the following: + code|id_token|id_token token|code id_token|code token|code id_token token + Empty string will remove that option completely. auth-type: default: 'auth-openidc' type: string diff --git a/src/charm.py b/src/charm.py index bed2a9f..f432b72 100755 --- a/src/charm.py +++ b/src/charm.py @@ -187,6 +187,15 @@ class KeystoneOpenIDCCharm(ops_openstack.core.OSBaseCharm): CONFIG_FILE_OWNER = 'root' CONFIG_FILE_GROUP = 'www-data' + OIDCRESPONSETYPE_VALUES = ( + 'code', + 'id_token', + 'id_token token', + 'code id_token', + 'code token', + 'code id_token token' + ) + release = 'xena' # First release supported. auth_method = 'openid' # the driver to be used. @@ -282,6 +291,24 @@ class KeystoneOpenIDCCharm(ops_openstack.core.OSBaseCharm): data['idp-name'] = json.dumps(self.options.idp_id) data['user-facing-name'] = json.dumps(self.options.user_facing_name) + def _check_oidcresponsetype(self): + """Make sure that the OIDCResponseType got correct value + + As in description the allowed values are: + code|id_token|id_token token|code id_token| + code token|code id_token token + Otherwise raise CharmConfigError + """ + options = KeystoneOpenIDCOptions(self) + if options.oidc_response_type not in self.OIDCRESPONSETYPE_VALUES: + valid_values = '|'.join(self.OIDCRESPONSETYPE_VALUES) + msg = ( + f"Incorrect oidc-response-type:{options.oidc_response_type}.", + f"Should be one of the following: {valid_values}." + ) + logger.error(msg) + raise CharmConfigError(msg) + def _on_config_changed(self, event): if not self.is_data_ready(): logger.debug('relation data is not ready yet (%s)', event) @@ -294,6 +321,7 @@ class KeystoneOpenIDCCharm(ops_openstack.core.OSBaseCharm): self.update_config_if_needed() self.update_principal_data() self._update_websso_data() + self._check_oidcresponsetype() def update_config_if_needed(self): with ch_host.restart_on_change( diff --git a/templates/apache-openidc-location.conf b/templates/apache-openidc-location.conf index 65af0a4..e8529a9 100644 --- a/templates/apache-openidc-location.conf +++ b/templates/apache-openidc-location.conf @@ -1,6 +1,8 @@ {# -*- mode: apache -*- #} OIDCClaimPrefix "OIDC-" -OIDCResponseType "id_token" +{% if options.oidc_response_type -%} +OIDCResponseType {{ options.oidc_response_type }} +{% endif -%} OIDCScope "openid email profile" {% if options.oidc_session_type -%} diff --git a/unit_tests/test_charm.py b/unit_tests/test_charm.py index f419364..101fd45 100644 --- a/unit_tests/test_charm.py +++ b/unit_tests/test_charm.py @@ -203,3 +203,13 @@ class TestCharm(BaseTestCharm): data = self.harness.get_relation_data(rid, 'keystone-openidc/0') expected['user-facing-name'] = json.dumps('My IdP') self.assertDictEqual(data, expected) + + def test_check_oidcresponsetype(self): + opts = { + 'oidc-response-type': 'invalid_option'} + self.harness.update_config( + key_values=opts) + self.assertRaises( + charm.CharmConfigError, + self.harness.charm._check_oidcresponsetype + )