Add domain scope support for scope types

This commit makes it easier for services to protect APIs meant for
domain-only operations. It does this by making "domain-scope" an
official scope type to check for during policy enforcement.

A good example of where this would be useful is protecting the user
API in keystone, since user's are technically owned by domains.

This commit bumps the version of oslo.context to 2.22.0, which also
has domain support.

Depends-On: https://review.openstack.org/#/c/613635/

Change-Id: Ifc83a5f261bc823060eca5c4d0a4bf07966794c4
This commit is contained in:
Lance Bragstad 2018-10-17 21:11:14 +00:00
parent fe898122c8
commit 7a2d79eafc
5 changed files with 108 additions and 10 deletions

View File

@ -28,7 +28,7 @@ netifaces==0.10.4
openstackdocstheme==1.18.1
os-client-config==1.28.0
oslo.config==5.2.0
oslo.context==2.21.0
oslo.context==2.22.0
oslo.i18n==3.15.3
oslo.serialization==2.18.0
oslo.utils==3.33.0

View File

@ -864,12 +864,11 @@ class Enforcer(object):
# attributes provided in `creds`.
if creds.get('system'):
token_scope = 'system'
elif creds.get('domain_id'):
token_scope = 'domain'
else:
# If the token isn't system-scoped then we're dealing with
# either a domain-scoped token or a project-scoped token.
# From a policy perspective, both are "project" operations.
# Whether or not the project is a domain depends on where
# it sits in the hierarchy.
# If the token isn't system-scoped or domain-scoped then
# we're dealing with a project-scoped token.
token_scope = 'project'
registered_rule = self.registered_rules.get(rule)

View File

@ -790,6 +790,105 @@ class EnforcerTest(base.PolicyBaseTestCase):
target_dict = {}
self.enforcer.enforce('fake_rule', target_dict, policy_values)
def test_enforcer_understands_system_scope(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['system']
)
self.enforcer.register_default(rule)
ctx = context.RequestContext(system_scope='all')
target_dict = {}
self.enforcer.enforce('fake_rule', target_dict, ctx)
def test_enforcer_raises_invalid_scope_with_system_scope_type(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['system']
)
self.enforcer.register_default(rule)
# model a domain-scoped token, which should fail enforcement
ctx = context.RequestContext(domain_id='fake')
target_dict = {}
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
# model a project-scoped token, which should fail enforcement
ctx = context.RequestContext(project_id='fake')
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
def test_enforcer_understands_domain_scope(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['domain']
)
self.enforcer.register_default(rule)
ctx = context.RequestContext(domain_id='fake')
target_dict = {}
self.enforcer.enforce('fake_rule', target_dict, ctx)
def test_enforcer_raises_invalid_scope_with_domain_scope_type(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['domain']
)
self.enforcer.register_default(rule)
# model a system-scoped token, which should fail enforcement
ctx = context.RequestContext(system_scope='all')
target_dict = {}
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
# model a project-scoped token, which should fail enforcement
ctx = context.RequestContext(project_id='fake')
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
def test_enforcer_understands_project_scope(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['project']
)
self.enforcer.register_default(rule)
ctx = context.RequestContext(project_id='fake')
target_dict = {}
self.enforcer.enforce('fake_rule', target_dict, ctx)
def test_enforcer_raises_invalid_scope_with_project_scope_type(self):
self.conf.set_override('enforce_scope', True, group='oslo_policy')
rule = policy.RuleDefault(
name='fake_rule', check_str='role:test', scope_types=['project']
)
self.enforcer.register_default(rule)
# model a system-scoped token, which should fail enforcement
ctx = context.RequestContext(system_scope='all')
target_dict = {}
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
# model a domain-scoped token, which should fail enforcement
ctx = context.RequestContext(domain_id='fake')
self.assertRaises(
policy.InvalidScope, self.enforcer.enforce, 'fake_rule',
target_dict, ctx
)
class EnforcerNoPolicyFileTest(base.PolicyBaseTestCase):
def setUp(self):
@ -1013,10 +1112,10 @@ class RuleDefaultTestCase(base.PolicyBaseTestCase):
opt = policy.RuleDefault(
name='foo',
check_str='role:bar',
scope_types=['project', 'system']
scope_types=['project', 'domain', 'system']
)
self.assertEqual(opt.scope_types, ['project', 'system'])
self.assertEqual(opt.scope_types, ['project', 'domain', 'system'])
def test_ensure_scope_types_are_unique(self):
self.assertRaises(

View File

@ -4,7 +4,7 @@
requests>=2.14.2 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0
oslo.context>=2.21.0 # Apache-2.0
oslo.context>=2.22.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
PyYAML>=3.12 # MIT

View File

@ -5,7 +5,7 @@ hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
requests-mock>=1.1.0 # Apache-2.0
stestr>=2.0.0 # Apache-2.0
oslo.context>=2.21.0 # Apache-2.0
oslo.context>=2.22.0 # Apache-2.0
# computes code coverage percentages
coverage!=4.4,>=4.0 # Apache-2.0