|
18 | 18 |
|
19 | 19 | # pylint: disable=line-too-long
|
20 | 20 |
|
21 |
| -from neutron.conf.policies import base, network |
| 21 | +import re |
| 22 | + |
| 23 | +from neutron.conf import policies |
22 | 24 | from oslo_policy import policy
|
23 | 25 |
|
24 | 26 | rules = [
|
|
33 | 35 | # A common helper to define that the user is a manager and the resource
|
34 | 36 | # target is in the same domain as the user is scoped to.
|
35 | 37 | policy.RuleDefault(
|
36 |
| - name='is_domain_manager_owner', |
37 |
| - check_str='rule:is_domain_manager and domain_id:%(domain_id)s', |
| 38 | + name='is_project_manager_owner', |
| 39 | + check_str='rule:is_domain_manager and project_id:%(project_id)s', |
38 | 40 | description='Rule for domain manager ownership',
|
39 | 41 | ),
|
40 | 42 |
|
|
44 | 46 | # allow provider networks, if the prior rule changes, then we can open up a security hole.
|
45 | 47 | policy.RuleDefault(
|
46 | 48 | name='create_network',
|
47 |
| - check_str='rule:is_domain_manager_owner or rule:base_create_network', |
| 49 | + check_str='rule:is_project_manager_owner or rule:base_create_network', |
48 | 50 | description='Create a network',
|
49 | 51 | ),
|
50 | 52 | policy.RuleDefault(
|
51 | 53 | name='delete_network',
|
52 |
| - check_str='rule:is_domain_manager_owner or rule:base_delete_network', |
| 54 | + check_str='rule:is_project_manager_owner or rule:base_delete_network', |
53 | 55 | description='Delete a network',
|
54 | 56 | ),
|
55 | 57 | policy.RuleDefault(
|
56 | 58 | name='create_network:segments',
|
57 |
| - check_str='rule:is_domain_manager_owner or rule:base_create_network:segments', |
| 59 | + check_str='rule:is_project_manager_owner or rule:base_create_network:segments', |
58 | 60 | description='Specify ``segments`` attribute when creating a network',
|
59 | 61 | ),
|
60 | 62 | policy.RuleDefault(
|
61 | 63 | name='create_network:provider:network_type',
|
62 |
| - check_str='rule:is_domain_manager_owner or rule:base_create_network:provider:physical_network', |
| 64 | + check_str='rule:is_project_manager_owner or rule:base_create_network:provider:physical_network', |
63 | 65 | description='Specify ``provider:network_type`` when creating a network',
|
64 | 66 | ),
|
65 | 67 | policy.RuleDefault(
|
66 | 68 | name='create_network:provider:physical_network',
|
67 |
| - check_str='rule:is_domain_manager_owner or rule:base_create_network:provider:network_type', |
| 69 | + check_str='rule:is_project_manager_owner or rule:base_create_network:provider:network_type', |
68 | 70 | description='Specify ``provider:physical_network`` when creating a network',
|
69 | 71 | ),
|
70 | 72 | policy.RuleDefault(
|
71 | 73 | name='create_network:provider:segmentation_id',
|
72 |
| - check_str='rule:is_domain_manager_owner or rule:base_create_network:provider:segmentation_id', |
| 74 | + check_str='rule:is_project_manager_owner or rule:base_create_network:provider:segmentation_id', |
73 | 75 | description='Specify ``provider:segmentation_id`` when creating a network',
|
74 | 76 | ),
|
75 | 77 | ]
|
76 | 78 |
|
77 | 79 |
|
78 |
| -def basify(rule): |
79 |
| - """Do a copy of the existing rule with a base_ name prefix""" |
| 80 | +class MissingRuleException(Exception): |
| 81 | + """ |
| 82 | + Raised when a rule cannot be resolved |
| 83 | + """ |
| 84 | + |
| 85 | + |
| 86 | +def _find_rule(name, rule_list): |
| 87 | + """Return a named rule if it exists or None""" |
| 88 | + |
| 89 | + for rule in rule_list: |
| 90 | + if rule.name == name: |
| 91 | + return rule |
| 92 | + |
| 93 | + raise MissingRuleException('unable to resolve referenced rule ' + name) |
| 94 | + |
| 95 | + |
| 96 | +def _wrap_check_str(tokens): |
| 97 | + """If the check string is more than one token, wrap it in parenteses""" |
| 98 | + |
| 99 | + if len(tokens) > 1: |
| 100 | + tokens.insert(0, '(') |
| 101 | + tokens.append(')') |
| 102 | + |
| 103 | + return tokens |
| 104 | + |
| 105 | + |
| 106 | +def _recurse_build_check_str(check_str, rule_list): |
| 107 | + """ |
| 108 | + Given a check string, this does macro expansion of rule:roo strings |
| 109 | + removing and inlining them. |
| 110 | + """ |
| 111 | + |
| 112 | + out = [] |
80 | 113 |
|
81 |
| - return policy.RuleDefault( |
82 |
| - name='base_' + rule.name, check_str=rule.check_str, description=rule.description) |
| 114 | + for token in re.split(r'\s+', check_str): |
| 115 | + if token.isspace(): |
| 116 | + continue |
83 | 117 |
|
| 118 | + # Handle leading parentheses. |
| 119 | + clean = token.lstrip('(') |
| 120 | + for _ in range(len(token) - len(clean)): |
| 121 | + out.append('(') |
84 | 122 |
|
85 |
| -def inherited(rule): |
86 |
| - """Is the rule inherited by one that we have defined?""" |
| 123 | + # Handle trailing parentheses. |
| 124 | + token = clean |
87 | 125 |
|
88 |
| - return any(rule.name == my_rule.name for my_rule in rules) |
| 126 | + clean = token.rstrip(')') |
| 127 | + trail = len(token) - len(clean) |
| 128 | + |
| 129 | + # If the token is a rule, then expand it. |
| 130 | + matches = re.match(r'rule:([\w_]+)', clean) |
| 131 | + if matches: |
| 132 | + rule = _find_rule(matches.group(1), rule_list) |
| 133 | + sub_check_str = _recurse_build_check_str(rule.check_str, rule_list) |
| 134 | + out.extend(_wrap_check_str(sub_check_str)) |
| 135 | + else: |
| 136 | + out.append(clean) |
| 137 | + |
| 138 | + for _ in range(trail): |
| 139 | + out.append(')') |
| 140 | + |
| 141 | + return out |
| 142 | + |
| 143 | + |
| 144 | +def _build_check_str(check_str, rule_list): |
| 145 | + """ |
| 146 | + Given a check string, this does macro expansion of rule:roo strings |
| 147 | + removing and inlining them. |
| 148 | + """ |
| 149 | + |
| 150 | + check_str = ' '.join(_recurse_build_check_str(check_str, rule_list)) |
| 151 | + check_str = re.sub(r'\( ', '(', check_str) |
| 152 | + check_str = re.sub(r' \)', ')', check_str) |
| 153 | + return check_str |
89 | 154 |
|
90 | 155 |
|
91 | 156 | def list_rules():
|
92 | 157 | """Implements the "oslo.policy.policies" entry point"""
|
93 | 158 |
|
94 |
| - # Okay now for the "hard" bit. We reference built in rules directly from neutron so |
95 |
| - # we can augment the exact rules for a specific version, thus we pick up any changes. |
96 |
| - # We prefix the existing rules with "base_" as already seen above but only if they |
97 |
| - # are redefined (and by implication referenced) from one of ours. |
98 |
| - network_rules = [basify(rule) for rule in network.list_rules() if inherited(rule)] |
| 159 | + # For every defined rule, look for a corresponding one sourced directly |
| 160 | + # from neutron, this means we can augment the exact rule defined for a |
| 161 | + # specific version of neutron, |
| 162 | + network_rules = list(policies.list_rules()) |
| 163 | + |
| 164 | + inherited_network_rules = [] |
| 165 | + |
| 166 | + for rule in rules: |
| 167 | + try: |
| 168 | + network_rule = _find_rule(rule.name, network_rules) |
| 169 | + |
| 170 | + check_str = _build_check_str(network_rule.check_str, network_rules) |
| 171 | + |
| 172 | + inherited_network_rules.append(policy.RuleDefault( |
| 173 | + name='base_' + rule.name, |
| 174 | + check_str=check_str, |
| 175 | + description=rule.description, |
| 176 | + )) |
| 177 | + except MissingRuleException: |
| 178 | + pass |
| 179 | + |
| 180 | + return inherited_network_rules + rules |
99 | 181 |
|
100 |
| - # Those rules will also rely on base rules, so include them too in the final output. |
101 |
| - return base.list_rules() + network_rules + rules |
102 | 182 |
|
103 | 183 | # vi: ts=4 et:
|
0 commit comments