From ab66a192f46f375037d951587e9fb8bc03040830 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 22 Mar 2024 10:52:25 -0400 Subject: [PATCH] Added OPENSTACK_KEYSTONE_MFA_TOTP_ENABLED to config options Starting from Openstack Bobcat (2023.2) Multi Factor Authentication was added for Horizon. This change introduced a new variable called OPENSTACK_KEYSTONE_MFA_TOTP_ENABLED, which if set to True will display a new form requesting for the user's TOTP code for MFA enabled users. This change provides the missing OPENSTACK_KEYSTONE_MFA_TOTP_ENABLED config option for the charm, allowing the user to enable from the charm's configuration. If the value is set to True, the new bobcat template will render the following values: OPENSTACK_KEYSTONE_MFA_TOTP_ENABLED = True AUTHENTICATION_PLUGINS = [ 'openstack_auth.plugin.totp.TotpPlugin', 'openstack_auth.plugin.password.PasswordPlugin', 'openstack_auth.plugin.token.TokenPlugin' ] Closes-Bug: #2058689 Change-Id: Ifedf587356693b58612b1fc4d7404f0f446158ce --- config.yaml | 9 +++++++++ hooks/horizon_contexts.py | 2 ++ templates/bobcat/local_settings.py | 10 ++++++++++ unit_tests/test_horizon_contexts.py | 27 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/config.yaml b/config.yaml index 30a30864..b7fc9cd2 100644 --- a/config.yaml +++ b/config.yaml @@ -512,6 +512,7 @@ options: this option sets True as the default value, which is consistent with the default value 'WSGISocketRotation On' in Apache. This option should be used with caution. Please read the Apache doc page for more information. + extra-regions: type: string default: "{}" @@ -528,3 +529,11 @@ options: "another cluster": "https://another.example.com/identity/v3" } + mfa-totp-enabled: + type: boolean + default: False + description: | + Allow users to enable TOTP Authentication form. If not configured, this option sets False + as the default value, which in turns does not display the form for MFA enabled users. If + this option is set to True, Horizon will display a second login form requesting the TOTP + code for MFA enabled users. diff --git a/hooks/horizon_contexts.py b/hooks/horizon_contexts.py index 79fd720c..2676b021 100644 --- a/hooks/horizon_contexts.py +++ b/hooks/horizon_contexts.py @@ -304,6 +304,8 @@ class HorizonContext(OSContextGenerator): config('enable-router-panel'), 'retrieve_network_data_when_listing_instances': config('retrieve-network-data-when-listing-instances'), + 'openstack_keystone_mfa_totp_enabled': + config('mfa-totp-enabled'), } return ctxt diff --git a/templates/bobcat/local_settings.py b/templates/bobcat/local_settings.py index 2b7c1c3d..5e489e53 100644 --- a/templates/bobcat/local_settings.py +++ b/templates/bobcat/local_settings.py @@ -1053,3 +1053,13 @@ SITE_BRANDING_LINK = "{{ site_branding_link }}" {%- if help_url %} HORIZON_CONFIG["help_url"] = "{{ help_url }}" {%- endif %} + +{%- if openstack_keystone_mfa_totp_enabled %} +OPENSTACK_KEYSTONE_MFA_TOTP_ENABLED = "{{ openstack_keystone_mfa_totp_enabled }}" + +AUTHENTICATION_PLUGINS = [ + 'openstack_auth.plugin.totp.TotpPlugin', + 'openstack_auth.plugin.password.PasswordPlugin', + 'openstack_auth.plugin.token.TokenPlugin' +] +{%- endif %} diff --git a/unit_tests/test_horizon_contexts.py b/unit_tests/test_horizon_contexts.py index 7e960e40..7afcdb8e 100644 --- a/unit_tests/test_horizon_contexts.py +++ b/unit_tests/test_horizon_contexts.py @@ -147,6 +147,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -189,6 +190,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -232,6 +234,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -277,6 +280,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": True, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -321,6 +325,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": False, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -364,6 +369,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -406,6 +412,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -448,6 +455,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -491,6 +499,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -537,6 +546,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -579,6 +589,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -629,6 +640,7 @@ class TestHorizonContexts(CharmTestCase): "enable_router_panel": True, "retrieve_network_data_when_listing_instances": ( False), + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -670,6 +682,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_key": None, "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, + "openstack_keystone_mfa_totp_enabled": False, "retrieve_network_data_when_listing_instances": True, } ) @@ -713,6 +726,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -756,6 +770,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -799,6 +814,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -842,6 +858,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -885,6 +902,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -928,6 +946,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -975,6 +994,7 @@ class TestHorizonContexts(CharmTestCase): "create_instance_flavor_sort_reverse": False, "enable_router_panel": True, "retrieve_network_data_when_listing_instances": True, + "openstack_keystone_mfa_totp_enabled": False, } ) @@ -984,6 +1004,13 @@ class TestHorizonContexts(CharmTestCase): self.assertTrue(horizon_contexts .HorizonContext()()['disable_instance_snapshot']) + def test_HorizonContext_can_set_openstack_keystone_mfa_totp_enabled(self): + self.maxDiff = 900 + self.test_config.set('mfa-totp-enabled', True) + self.assertTrue(horizon_contexts + .HorizonContext()() + ['openstack_keystone_mfa_totp_enabled']) + def test_IdentityServiceContext_not_related(self): self.relation_ids.return_value = [] self.context_complete.return_value = False