Fix reference cycle caused by deprecated sample override
In the sample policy generator, we create a rule that maps the
deprecated name of a policy to the new rule name. For example:
identity:old_rule: rule:identity:new_rule
However, in the policy code, if we see an override of a deprecated
name and no override for the new name, we apply the value of the
deprecated name to the new name. In the above case, this results
in us creating a rule that looks like:
identity:new_rule: rule:identity:new_rule
which is a circular reference and nonsense.
To fix this, I added a check to the deprecated rule logic that looks
for instances where the old override is just a reference to the new
rule. If that's the case, then we don't need to do anything because
it's already doing the right thing.
Change-Id: Ifd14993bc84e83c13abab3456fbf670c06e5806f
Closes-Bug: 1843931
(cherry picked from commit 82a2c8d8b7
)
This commit is contained in:
parent
b1eb97d6f3
commit
0a4adba1a5
|
@ -668,8 +668,14 @@ class Enforcer(object):
|
|||
# the default deprecated policy, override the new policy's default
|
||||
# with the old check string. This should prevents unwanted exposure
|
||||
# to APIs on upgrade.
|
||||
# There's one exception to this: When we generate a sample policy,
|
||||
# we set the deprecated rule name to reference the new rule. If we
|
||||
# see that the deprecated override rule is just the new rule, then
|
||||
# we shouldn't mess with it.
|
||||
if (self.file_rules[deprecated_rule.name].check
|
||||
!= _parser.parse_rule(deprecated_rule.check_str)):
|
||||
!= _parser.parse_rule(deprecated_rule.check_str) and
|
||||
str(self.file_rules[deprecated_rule.name].check)
|
||||
!= 'rule:%s' % default.name):
|
||||
if default.name not in self.file_rules.keys():
|
||||
self.rules[default.name] = self.file_rules[
|
||||
deprecated_rule.name
|
||||
|
|
|
@ -1452,6 +1452,39 @@ class DocumentedRuleDefaultDeprecationTestCase(base.PolicyBaseTestCase):
|
|||
self.enforcer.enforce('foo:create_bar', {}, {'roles': ['bazz']})
|
||||
)
|
||||
|
||||
def test_override_deprecated_policy_with_new_rule(self):
|
||||
# Simulate an operator overriding a deprecated policy with a reference
|
||||
# to the new policy, as done by the sample policy generator.
|
||||
rules = jsonutils.dumps({'old_rule': 'rule:new_rule'})
|
||||
self.create_config_file('policy.json', rules)
|
||||
|
||||
# Deprecate the policy name in favor of something better.
|
||||
deprecated_rule = policy.DeprecatedRule(
|
||||
name='old_rule',
|
||||
check_str='role:bang'
|
||||
)
|
||||
rule_list = [policy.DocumentedRuleDefault(
|
||||
name='new_rule',
|
||||
check_str='role:bang',
|
||||
description='Replacement for old_rule.',
|
||||
operations=[{'path': '/v1/bars', 'method': 'POST'}],
|
||||
deprecated_rule=deprecated_rule,
|
||||
deprecated_reason='"old_rule" is a bad name',
|
||||
deprecated_since='N'
|
||||
)]
|
||||
self.enforcer.register_defaults(rule_list)
|
||||
|
||||
# Make sure the override supplied by the operator using the old policy
|
||||
# name is used in favor of the old or new default.
|
||||
self.assertFalse(
|
||||
self.enforcer.enforce('new_rule', {}, {'roles': ['fizz']})
|
||||
)
|
||||
self.assertTrue(
|
||||
self.enforcer.enforce('new_rule', {}, {'roles': ['bang']})
|
||||
)
|
||||
# Verify that we didn't overwrite the new rule.
|
||||
self.assertEqual('bang', self.enforcer.rules['new_rule'].match)
|
||||
|
||||
|
||||
class DocumentedRuleDefaultTestCase(base.PolicyBaseTestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue