From 628db853fb902282ea260ea0c5f9ba213e6ea2b0 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 5 Dec 2024 18:15:29 +0100 Subject: [PATCH] Fix domain `immutable` lockdown A bug in the test design have hidden the issue with options of the domain. It is possible to set immutable to true during creation or update of the domain, but it is impossible to change it back through API. Reason is the check that refuses update operation when there are more then 1 updated props with immutable switched on. For projects it is no problem to send 1 update but for domain we pull additional base props (is_domain=true, domain_id=none, parent_id=none) in the get_project_from_domain method. And since the test for unsetting immutable started with immutable already unset (in difference to similar test for the project) it was never identified. - discard default props of the domain to keep the length check happy - ensure test for unsetting immutable starts with immutable domain Change-Id: I03ba754875050fdb93219e915fc099680679b6c4 --- .../common/resource_options/options/immutable.py | 14 ++++++++++++++ keystone/tests/unit/resource/test_backends.py | 11 ++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/keystone/common/resource_options/options/immutable.py b/keystone/common/resource_options/options/immutable.py index 8f0c44f209..2a0d8eb1a4 100644 --- a/keystone/common/resource_options/options/immutable.py +++ b/keystone/common/resource_options/options/immutable.py @@ -54,6 +54,20 @@ def check_immutable_update( immutable = check_resource_immutable(original_resource_ref) if immutable: new_options = new_resource_ref.get('options', {}) + if type == "domain": + if ( + new_resource_ref.get("is_domain", False) == True + and not new_resource_ref.get("domain_id") + and not new_resource_ref.get("parent_id") + ): + # To keep next check happy - reject certain props for the domain set by default in + # `get_project_from_domain` if those ARE default + new_resource_ref.pop("is_domain") + new_resource_ref.pop("domain_id") + new_resource_ref.pop("parent_id") + # If resource is currently immutable - raise error in attempt to + # update more then 1 property while making resource mutable + # (first make mutable then update rest) if ( (len(new_resource_ref.keys()) > 1) or (IMMUTABLE_OPT.option_name not in new_options) diff --git a/keystone/tests/unit/resource/test_backends.py b/keystone/tests/unit/resource/test_backends.py index 811a5d5d42..6c505ddc65 100644 --- a/keystone/tests/unit/resource/test_backends.py +++ b/keystone/tests/unit/resource/test_backends.py @@ -2184,13 +2184,18 @@ class ResourceTests: # domains are projects, this should be the same as the project version domain_id = uuid.uuid4().hex - domain = {'name': uuid.uuid4().hex, 'id': domain_id, 'is_domain': True} + domain = { + 'name': uuid.uuid4().hex, + 'id': domain_id, + 'is_domain': True, + 'options': {ro_opt.IMMUTABLE_OPT.option_name: True}, + } PROVIDERS.resource_api.create_domain(domain_id, domain) domain_via_manager = PROVIDERS.resource_api.get_domain(domain_id) self.assertTrue('options' in domain_via_manager) - self.assertFalse( - ro_opt.IMMUTABLE_OPT.option_name in domain_via_manager['options'] + self.assertTrue( + domain_via_manager['options'][ro_opt.IMMUTABLE_OPT.option_name] ) update_domain = {'options': {ro_opt.IMMUTABLE_OPT.option_name: False}}