Add Policy enforcement for several Metadata Definition delete APIs

Several Metadata Definition delete APIs do not have RBAC. This
patchset add policy enforcment to the following APIs:

    - `Delete namespace`
    - `Delete object`
    - `Remove resource type association`
    - `Remove property definition`
    - `Delete tag definition`
    - `Delete all tag definitions`

The following actions are enforce and added to the policy.json:

    - `delete_metadef_namespace`
    - `delete_metadef_object`
    - `remove_metadef_resource_type_association`
    - `remove_metadef_property`
    - `delete_metadef_tag`
    - `delete_metadef_tags`

Most other APIs have policy enforcement, so the ones above should as
well. Without adding policy enforcement for the above APIs, all roles
can peform the delete APIs noted above.

Change-Id: I8cd6eb26b0d3401fa4667384c31e4c56d838d42b
Closes-Bug: #1782840
Co-Authored-By: julian.sy@att.com
This commit is contained in:
Rick Bartra 2018-07-20 17:42:09 -04:00 committed by Sophie Huang
parent 53df9ade64
commit d2cc0dc566
6 changed files with 370 additions and 1 deletions

View File

@ -194,21 +194,26 @@ can also be used to set policies for Image service actions.
"get_metadef_objects":"", "get_metadef_objects":"",
"modify_metadef_object":"", "modify_metadef_object":"",
"add_metadef_object":"", "add_metadef_object":"",
"delete_metadef_object":"",
"list_metadef_resource_types":"", "list_metadef_resource_types":"",
"get_metadef_resource_type":"", "get_metadef_resource_type":"",
"add_metadef_resource_type_association":"", "add_metadef_resource_type_association":"",
"remove_metadef_resource_type_association":"",
"get_metadef_property":"", "get_metadef_property":"",
"get_metadef_properties":"", "get_metadef_properties":"",
"modify_metadef_property":"", "modify_metadef_property":"",
"add_metadef_property":"", "add_metadef_property":"",
"remove_metadef_property":"",
"get_metadef_tag":"", "get_metadef_tag":"",
"get_metadef_tags":"", "get_metadef_tags":"",
"modify_metadef_tag":"", "modify_metadef_tag":"",
"add_metadef_tag":"", "add_metadef_tag":"",
"add_metadef_tags":"" "add_metadef_tags":"",
"delete_metadef_tag":"",
"delete_metadef_tags":""
} }
For each parameter, use ``"rule:restricted"`` to restrict access to all For each parameter, use ``"rule:restricted"`` to restrict access to all

View File

@ -454,6 +454,10 @@ class MetadefNamespaceProxy(glance.domain.proxy.MetadefNamespace):
self.policy = policy self.policy = policy
super(MetadefNamespaceProxy, self).__init__(namespace) super(MetadefNamespaceProxy, self).__init__(namespace)
def delete(self):
self.policy.enforce(self.context, 'delete_metadef_namespace', {})
return super(MetadefNamespaceProxy, self).delete()
class MetadefNamespaceRepoProxy(glance.domain.proxy.MetadefNamespaceRepo): class MetadefNamespaceRepoProxy(glance.domain.proxy.MetadefNamespaceRepo):
@ -483,6 +487,14 @@ class MetadefNamespaceRepoProxy(glance.domain.proxy.MetadefNamespaceRepo):
self.policy.enforce(self.context, 'add_metadef_namespace', {}) self.policy.enforce(self.context, 'add_metadef_namespace', {})
return super(MetadefNamespaceRepoProxy, self).add(namespace) return super(MetadefNamespaceRepoProxy, self).add(namespace)
def remove(self, namespace):
self.policy.enforce(self.context, 'delete_metadef_namespace', {})
return super(MetadefNamespaceRepoProxy, self).remove(namespace)
def remove_tags(self, namespace):
self.policy.enforce(self.context, 'delete_metadef_tags', {})
return super(MetadefNamespaceRepoProxy, self).remove_tags(namespace)
class MetadefNamespaceFactoryProxy( class MetadefNamespaceFactoryProxy(
glance.domain.proxy.MetadefNamespaceFactory): glance.domain.proxy.MetadefNamespaceFactory):
@ -507,6 +519,10 @@ class MetadefObjectProxy(glance.domain.proxy.MetadefObject):
self.policy = policy self.policy = policy
super(MetadefObjectProxy, self).__init__(meta_object) super(MetadefObjectProxy, self).__init__(meta_object)
def delete(self):
self.policy.enforce(self.context, 'delete_metadef_object', {})
return super(MetadefObjectProxy, self).delete()
class MetadefObjectRepoProxy(glance.domain.proxy.MetadefObjectRepo): class MetadefObjectRepoProxy(glance.domain.proxy.MetadefObjectRepo):
@ -536,6 +552,10 @@ class MetadefObjectRepoProxy(glance.domain.proxy.MetadefObjectRepo):
self.policy.enforce(self.context, 'add_metadef_object', {}) self.policy.enforce(self.context, 'add_metadef_object', {})
return super(MetadefObjectRepoProxy, self).add(meta_object) return super(MetadefObjectRepoProxy, self).add(meta_object)
def remove(self, meta_object):
self.policy.enforce(self.context, 'delete_metadef_object', {})
return super(MetadefObjectRepoProxy, self).remove(meta_object)
class MetadefObjectFactoryProxy(glance.domain.proxy.MetadefObjectFactory): class MetadefObjectFactoryProxy(glance.domain.proxy.MetadefObjectFactory):
@ -559,6 +579,11 @@ class MetadefResourceTypeProxy(glance.domain.proxy.MetadefResourceType):
self.policy = policy self.policy = policy
super(MetadefResourceTypeProxy, self).__init__(meta_resource_type) super(MetadefResourceTypeProxy, self).__init__(meta_resource_type)
def delete(self):
self.policy.enforce(self.context,
'remove_metadef_resource_type_association', {})
return super(MetadefResourceTypeProxy, self).delete()
class MetadefResourceTypeRepoProxy( class MetadefResourceTypeRepoProxy(
glance.domain.proxy.MetadefResourceTypeRepo): glance.domain.proxy.MetadefResourceTypeRepo):
@ -586,6 +611,12 @@ class MetadefResourceTypeRepoProxy(
'add_metadef_resource_type_association', {}) 'add_metadef_resource_type_association', {})
return super(MetadefResourceTypeRepoProxy, self).add(resource_type) return super(MetadefResourceTypeRepoProxy, self).add(resource_type)
def remove(self, *args, **kwargs):
self.policy.enforce(self.context,
'remove_metadef_resource_type_association', {})
return super(MetadefResourceTypeRepoProxy,
self).remove(*args, **kwargs)
class MetadefResourceTypeFactoryProxy( class MetadefResourceTypeFactoryProxy(
glance.domain.proxy.MetadefResourceTypeFactory): glance.domain.proxy.MetadefResourceTypeFactory):
@ -610,6 +641,10 @@ class MetadefPropertyProxy(glance.domain.proxy.MetadefProperty):
self.policy = policy self.policy = policy
super(MetadefPropertyProxy, self).__init__(namespace_property) super(MetadefPropertyProxy, self).__init__(namespace_property)
def delete(self):
self.policy.enforce(self.context, 'remove_metadef_property', {})
return super(MetadefPropertyProxy, self).delete()
class MetadefPropertyRepoProxy(glance.domain.proxy.MetadefPropertyRepo): class MetadefPropertyRepoProxy(glance.domain.proxy.MetadefPropertyRepo):
@ -643,6 +678,10 @@ class MetadefPropertyRepoProxy(glance.domain.proxy.MetadefPropertyRepo):
return super(MetadefPropertyRepoProxy, self).add( return super(MetadefPropertyRepoProxy, self).add(
namespace_property) namespace_property)
def remove(self, *args, **kwargs):
self.policy.enforce(self.context, 'remove_metadef_property', {})
return super(MetadefPropertyRepoProxy, self).remove(*args, **kwargs)
class MetadefPropertyFactoryProxy(glance.domain.proxy.MetadefPropertyFactory): class MetadefPropertyFactoryProxy(glance.domain.proxy.MetadefPropertyFactory):
@ -665,6 +704,10 @@ class MetadefTagProxy(glance.domain.proxy.MetadefTag):
self.policy = policy self.policy = policy
super(MetadefTagProxy, self).__init__(meta_tag) super(MetadefTagProxy, self).__init__(meta_tag)
def delete(self):
self.policy.enforce(self.context, 'delete_metadef_tag', {})
return super(MetadefTagProxy, self).delete()
class MetadefTagRepoProxy(glance.domain.proxy.MetadefTagRepo): class MetadefTagRepoProxy(glance.domain.proxy.MetadefTagRepo):
@ -698,6 +741,10 @@ class MetadefTagRepoProxy(glance.domain.proxy.MetadefTagRepo):
self.policy.enforce(self.context, 'add_metadef_tags', {}) self.policy.enforce(self.context, 'add_metadef_tags', {})
return super(MetadefTagRepoProxy, self).add_tags(meta_tags) return super(MetadefTagRepoProxy, self).add_tags(meta_tags)
def remove(self, meta_tag):
self.policy.enforce(self.context, 'delete_metadef_tag', {})
return super(MetadefTagRepoProxy, self).remove(meta_tag)
class MetadefTagFactoryProxy(glance.domain.proxy.MetadefTagFactory): class MetadefTagFactoryProxy(glance.domain.proxy.MetadefTagFactory):

View File

@ -20,11 +20,14 @@ metadef_policies = [
policy.RuleDefault(name="modify_metadef_namespace", policy.RuleDefault(name="modify_metadef_namespace",
check_str="rule:default"), check_str="rule:default"),
policy.RuleDefault(name="add_metadef_namespace", check_str="rule:default"), policy.RuleDefault(name="add_metadef_namespace", check_str="rule:default"),
policy.RuleDefault(name="delete_metadef_namespace",
check_str="rule:default"),
policy.RuleDefault(name="get_metadef_object", check_str="rule:default"), policy.RuleDefault(name="get_metadef_object", check_str="rule:default"),
policy.RuleDefault(name="get_metadef_objects", check_str="rule:default"), policy.RuleDefault(name="get_metadef_objects", check_str="rule:default"),
policy.RuleDefault(name="modify_metadef_object", check_str="rule:default"), policy.RuleDefault(name="modify_metadef_object", check_str="rule:default"),
policy.RuleDefault(name="add_metadef_object", check_str="rule:default"), policy.RuleDefault(name="add_metadef_object", check_str="rule:default"),
policy.RuleDefault(name="delete_metadef_object", check_str="rule:default"),
policy.RuleDefault(name="list_metadef_resource_types", policy.RuleDefault(name="list_metadef_resource_types",
check_str="rule:default"), check_str="rule:default"),
@ -32,6 +35,8 @@ metadef_policies = [
check_str="rule:default"), check_str="rule:default"),
policy.RuleDefault(name="add_metadef_resource_type_association", policy.RuleDefault(name="add_metadef_resource_type_association",
check_str="rule:default"), check_str="rule:default"),
policy.RuleDefault(name="remove_metadef_resource_type_association",
check_str="rule:default"),
policy.RuleDefault(name="get_metadef_property", check_str="rule:default"), policy.RuleDefault(name="get_metadef_property", check_str="rule:default"),
policy.RuleDefault(name="get_metadef_properties", policy.RuleDefault(name="get_metadef_properties",
@ -39,12 +44,16 @@ metadef_policies = [
policy.RuleDefault(name="modify_metadef_property", policy.RuleDefault(name="modify_metadef_property",
check_str="rule:default"), check_str="rule:default"),
policy.RuleDefault(name="add_metadef_property", check_str="rule:default"), policy.RuleDefault(name="add_metadef_property", check_str="rule:default"),
policy.RuleDefault(name="remove_metadef_property",
check_str="rule:default"),
policy.RuleDefault(name="get_metadef_tag", check_str="rule:default"), policy.RuleDefault(name="get_metadef_tag", check_str="rule:default"),
policy.RuleDefault(name="get_metadef_tags", check_str="rule:default"), policy.RuleDefault(name="get_metadef_tags", check_str="rule:default"),
policy.RuleDefault(name="modify_metadef_tag", check_str="rule:default"), policy.RuleDefault(name="modify_metadef_tag", check_str="rule:default"),
policy.RuleDefault(name="add_metadef_tag", check_str="rule:default"), policy.RuleDefault(name="add_metadef_tag", check_str="rule:default"),
policy.RuleDefault(name="add_metadef_tags", check_str="rule:default"), policy.RuleDefault(name="add_metadef_tags", check_str="rule:default"),
policy.RuleDefault(name="delete_metadef_tag", check_str="rule:default"),
policy.RuleDefault(name="delete_metadef_tags", check_str="rule:default"),
] ]

View File

@ -36,26 +36,32 @@
"get_metadef_namespaces":"", "get_metadef_namespaces":"",
"modify_metadef_namespace":"", "modify_metadef_namespace":"",
"add_metadef_namespace":"", "add_metadef_namespace":"",
"delete_metadef_namespace": "",
"get_metadef_object":"", "get_metadef_object":"",
"get_metadef_objects":"", "get_metadef_objects":"",
"modify_metadef_object":"", "modify_metadef_object":"",
"add_metadef_object":"", "add_metadef_object":"",
"delete_metadef_object": "",
"list_metadef_resource_types":"", "list_metadef_resource_types":"",
"get_metadef_resource_type":"", "get_metadef_resource_type":"",
"add_metadef_resource_type_association":"", "add_metadef_resource_type_association":"",
"remove_metadef_resource_type_association": "",
"get_metadef_property":"", "get_metadef_property":"",
"get_metadef_properties":"", "get_metadef_properties":"",
"modify_metadef_property":"", "modify_metadef_property":"",
"add_metadef_property":"", "add_metadef_property":"",
"remove_metadef_property": "",
"get_metadef_tag":"", "get_metadef_tag":"",
"get_metadef_tags":"", "get_metadef_tags":"",
"modify_metadef_tag":"", "modify_metadef_tag":"",
"add_metadef_tag":"", "add_metadef_tag":"",
"add_metadef_tags":"", "add_metadef_tags":"",
"delete_metadef_tag": "",
"delete_metadef_tags": "",
"deactivate": "", "deactivate": "",
"reactivate": "" "reactivate": ""

View File

@ -160,6 +160,94 @@ class TaskFactoryStub(object):
return 'new_task' return 'new_task'
class MdNamespaceRepoStub(object):
def add(self, namespace):
return 'mdns_add'
def get(self, namespace):
return 'mdns_get'
def list(self, *args, **kwargs):
return ['mdns_list']
def save(self, namespace):
return 'mdns_save'
def remove(self, namespace):
return 'mdns_remove'
def remove_tags(self, namespace):
return 'mdtags_remove'
class MdObjectRepoStub(object):
def add(self, obj):
return 'mdobj_add'
def get(self, ns, obj_name):
return 'mdobj_get'
def list(self, *args, **kwargs):
return ['mdobj_list']
def save(self, obj):
return 'mdobj_save'
def remove(self, obj):
return 'mdobj_remove'
class MdResourceTypeRepoStub(object):
def add(self, rt):
return 'mdrt_add'
def get(self, *args, **kwargs):
return 'mdrt_get'
def list(self, *args, **kwargs):
return ['mdrt_list']
def remove(self, *args, **kwargs):
return 'mdrt_remove'
class MdPropertyRepoStub(object):
def add(self, prop):
return 'mdprop_add'
def get(self, ns, prop_name):
return 'mdprop_get'
def list(self, *args, **kwargs):
return ['mdprop_list']
def save(self, prop):
return 'mdprop_save'
def remove(self, prop):
return 'mdprop_remove'
class MdTagRepoStub(object):
def add(self, tag):
return 'mdtag_add'
def add_tags(self, tags):
return ['mdtag_add_tags']
def get(self, ns, tag_name):
return 'mdtag_get'
def list(self, *args, **kwargs):
return ['mdtag_list']
def save(self, tag):
return 'mdtag_save'
def remove(self, tag):
return 'mdtag_remove'
class TestPolicyEnforcer(base.IsolatedUnitTest): class TestPolicyEnforcer(base.IsolatedUnitTest):
def test_policy_enforce_unregistered(self): def test_policy_enforce_unregistered(self):
@ -604,6 +692,204 @@ class TestTaskPolicy(test_utils.BaseTestCase):
task_repo.add(task) task_repo.add(task)
class TestMetadefPolicy(test_utils.BaseTestCase):
def setUp(self):
self.fakens = mock.Mock()
self.fakeobj = mock.Mock()
self.fakert = mock.Mock()
self.fakeprop = mock.Mock()
self.faketag = mock.Mock()
self.policy = unit_test_utils.FakePolicyEnforcer()
super(TestMetadefPolicy, self).setUp()
def test_md_namespace_not_allowed(self):
rules = {'get_metadef_namespace': False,
'get_metadef_namespaces': False,
'modify_metadef_namespace': False,
'add_metadef_namespace': False,
'delete_metadef_namespace': False}
self.policy.set_rules(rules)
mdns_repo = glance.api.policy.MetadefNamespaceRepoProxy(
MdNamespaceRepoStub(), {}, self.policy)
self.assertRaises(exception.Forbidden, mdns_repo.add, self.fakens)
self.assertRaises(exception.Forbidden, mdns_repo.get, self.fakens)
self.assertRaises(exception.Forbidden, mdns_repo.list)
self.assertRaises(exception.Forbidden, mdns_repo.remove, self.fakens)
self.assertRaises(exception.Forbidden, mdns_repo.save, self.fakens)
def test_md_namespace_allowed(self):
rules = {'get_metadef_namespace': True,
'get_metadef_namespaces': True,
'modify_metadef_namespace': True,
'add_metadef_namespace': True,
'delete_metadef_namespace': True}
self.policy.set_rules(rules)
mdns_repo = glance.api.policy.MetadefNamespaceRepoProxy(
MdNamespaceRepoStub(), {}, self.policy)
self.assertEqual(None, mdns_repo.add(self.fakens))
self.assertEqual('mdns_get',
mdns_repo.get(self.fakens).namespace_input)
self.assertEqual(['mdns_list'],
[ns.namespace_input for ns in mdns_repo.list()])
self.assertEqual('mdns_save',
mdns_repo.save(self.fakens).namespace_input)
self.assertEqual('mdns_remove',
mdns_repo.remove(self.fakens).namespace_input)
def test_md_object_not_allowed(self):
rules = {'get_metadef_object': False,
'get_metadef_objects': False,
'modify_metadef_object': False,
'add_metadef_object': False,
'delete_metadef_object': False}
self.policy.set_rules(rules)
mdobj_repo = glance.api.policy.MetadefObjectRepoProxy(
MdObjectRepoStub(), {}, self.policy)
self.assertRaises(exception.Forbidden, mdobj_repo.add, self.fakeobj)
self.assertRaises(exception.Forbidden, mdobj_repo.get, self.fakens,
self.fakeobj)
self.assertRaises(exception.Forbidden, mdobj_repo.list)
self.assertRaises(exception.Forbidden, mdobj_repo.remove, self.fakeobj)
self.assertRaises(exception.Forbidden, mdobj_repo.save, self.fakeobj)
def test_md_object_allowed(self):
rules = {'get_metadef_object': True,
'get_metadef_objects': True,
'modify_metadef_object': True,
'add_metadef_object': True,
'delete_metadef_object': True}
self.policy.set_rules(rules)
mdobj_repo = glance.api.policy.MetadefObjectRepoProxy(
MdObjectRepoStub(), {}, self.policy)
self.assertEqual(None, mdobj_repo.add(self.fakeobj))
self.assertEqual('mdobj_get',
mdobj_repo.get(self.fakens, 'fakeobj').meta_object)
self.assertEqual(['mdobj_list'],
[obj.meta_object for obj in mdobj_repo.list()])
self.assertEqual('mdobj_save',
mdobj_repo.save(self.fakeobj).meta_object)
self.assertEqual('mdobj_remove',
mdobj_repo.remove(self.fakeobj).meta_object)
def test_md_resource_type_not_allowed(self):
rules = {'get_metadef_resource_type': False,
'list_metadef_resource_types': False,
'add_metadef_resource_type_association': False,
'remove_metadef_resource_type_association': False}
self.policy.set_rules(rules)
mdrt_repo = glance.api.policy.MetadefResourceTypeRepoProxy(
MdResourceTypeRepoStub(), {}, self.policy)
self.assertRaises(exception.Forbidden, mdrt_repo.add, self.fakert)
self.assertRaises(exception.Forbidden, mdrt_repo.get, self.fakert)
self.assertRaises(exception.Forbidden, mdrt_repo.list)
self.assertRaises(exception.Forbidden, mdrt_repo.remove, self.fakert)
def test_md_resource_type_allowed(self):
rules = {'get_metadef_resource_type': True,
'list_metadef_resource_types': True,
'add_metadef_resource_type_association': True,
'remove_metadef_resource_type_association': True}
self.policy.set_rules(rules)
mdrt_repo = glance.api.policy.MetadefResourceTypeRepoProxy(
MdResourceTypeRepoStub(), {}, self.policy)
self.assertEqual(None, mdrt_repo.add(self.fakert))
self.assertEqual(
'mdrt_get', mdrt_repo.get(self.fakens,
'fakert').meta_resource_type)
self.assertEqual(['mdrt_list'],
[rt.meta_resource_type for rt in mdrt_repo.list()])
self.assertEqual('mdrt_remove',
mdrt_repo.remove(self.fakert).meta_resource_type)
def test_md_property_not_allowed(self):
rules = {'get_metadef_property': False,
'get_metadef_properties': False,
'modify_metadef_property': False,
'add_metadef_property': False,
'remove_metadef_property': False}
self.policy.set_rules(rules)
mdprop_repo = glance.api.policy.MetadefPropertyRepoProxy(
MdPropertyRepoStub(), {}, self.policy)
self.assertRaises(exception.Forbidden, mdprop_repo.add, self.fakeprop)
self.assertRaises(exception.Forbidden, mdprop_repo.get, self.fakens,
self.fakeprop)
self.assertRaises(exception.Forbidden, mdprop_repo.list)
self.assertRaises(exception.Forbidden, mdprop_repo.remove,
self.fakeprop)
self.assertRaises(exception.Forbidden, mdprop_repo.save, self.fakeprop)
def test_md_property_allowed(self):
rules = {'get_metadef_property': True,
'get_metadef_properties': True,
'modify_metadef_property': True,
'add_metadef_property': True,
'remove_metadef_property': True}
self.policy.set_rules(rules)
mdprop_repo = glance.api.policy.MetadefPropertyRepoProxy(
MdPropertyRepoStub(), {}, self.policy)
self.assertEqual(None, mdprop_repo.add(self.fakeprop))
self.assertEqual(
'mdprop_get', mdprop_repo.get(self.fakens,
'fakeprop').namespace_property)
self.assertEqual(['mdprop_list'],
[prop.namespace_property for prop
in mdprop_repo.list()])
self.assertEqual('mdprop_save',
mdprop_repo.save(self.fakeprop).namespace_property)
self.assertEqual('mdprop_remove',
mdprop_repo.remove(self.fakeprop).namespace_property)
def test_md_tag_not_allowed(self):
rules = {'get_metadef_tag': False,
'get_metadef_tags': False,
'modify_metadef_tag': False,
'add_metadef_tag': False,
'add_metadef_tags': False,
'delete_metadef_tag': False,
'delete_metadef_tags': False}
self.policy.set_rules(rules)
mdtag_repo = glance.api.policy.MetadefTagRepoProxy(
MdTagRepoStub(), {}, self.policy)
mdns_repo = glance.api.policy.MetadefNamespaceRepoProxy(
MdNamespaceRepoStub(), {}, self.policy)
self.assertRaises(exception.Forbidden, mdtag_repo.add, self.faketag)
self.assertRaises(exception.Forbidden, mdtag_repo.add_tags,
[self.faketag])
self.assertRaises(exception.Forbidden, mdtag_repo.get, self.fakens,
self.faketag)
self.assertRaises(exception.Forbidden, mdtag_repo.list)
self.assertRaises(exception.Forbidden, mdtag_repo.remove, self.faketag)
self.assertRaises(exception.Forbidden, mdns_repo.remove_tags,
self.fakens)
self.assertRaises(exception.Forbidden, mdtag_repo.save, self.faketag)
def test_md_tag_allowed(self):
rules = {'get_metadef_tag': True,
'get_metadef_tags': True,
'modify_metadef_tag': True,
'add_metadef_tag': True,
'add_metadef_tags': True,
'delete_metadef_tag': True,
'delete_metadef_tags': True}
self.policy.set_rules(rules)
mdtag_repo = glance.api.policy.MetadefTagRepoProxy(
MdTagRepoStub(), {}, self.policy)
mdns_repo = glance.api.policy.MetadefNamespaceRepoProxy(
MdNamespaceRepoStub(), {}, self.policy)
self.assertEqual(None, mdtag_repo.add(self.faketag))
self.assertEqual(None, mdtag_repo.add_tags([self.faketag]))
self.assertEqual('mdtag_get',
mdtag_repo.get(self.fakens, 'faketag').base)
self.assertEqual(['mdtag_list'],
[tag.base for tag in mdtag_repo.list()])
self.assertEqual('mdtag_save',
mdtag_repo.save(self.faketag).base)
self.assertEqual('mdtag_remove',
mdtag_repo.remove(self.faketag).base)
self.assertEqual('mdtags_remove',
mdns_repo.remove_tags(self.fakens).base)
class TestContextPolicyEnforcer(base.IsolatedUnitTest): class TestContextPolicyEnforcer(base.IsolatedUnitTest):
def _do_test_policy_influence_context_admin(self, def _do_test_policy_influence_context_admin(self,

View File

@ -0,0 +1,16 @@
---
features:
- |
Policy enforcement for several Metadata Definition delete APIs are
added in this release. The following actions are enforced
and added to the policy.json:
- ``delete_metadef_namespace``
- ``delete_metadef_object``
- ``remove_metadef_resource_type_association``
- ``remove_metadef_property``
- ``delete_metadef_tag``
- ``delete_metadef_tags``
This prevents roles that should not have access to these APIs from
performing the APIs associated with the actions above.