19
19
Policy engine for neutron. Largely copied from nova.
24
26
from oslo.config import cfg
26
28
from neutron.api.v2 import attributes
29
from neutron.common import constants as const
27
30
from neutron.common import exceptions
28
31
import neutron.common.utils as utils
29
32
from neutron import manager
119
122
policy.set_rules(policies)
122
def _is_attribute_explicitly_set(attribute_name, resource, target):
123
"""Verify that an attribute is present and has a non-default value."""
125
def _is_attribute_explicitly_set(attribute_name, resource, target, action):
126
"""Verify that an attribute is present and is explicitly set."""
127
if 'update' in action:
128
# In the case of update, the function should not pay attention to a
129
# default value of an attribute, but check whether it was explicitly
130
# marked as being updated instead.
131
return (attribute_name in target[const.ATTRIBUTES_TO_UPDATE] and
132
target[attribute_name] is not attributes.ATTR_NOT_SPECIFIED)
124
133
return ('default' in resource[attribute_name] and
125
134
attribute_name in target and
126
135
target[attribute_name] is not attributes.ATTR_NOT_SPECIFIED and
127
136
target[attribute_name] != resource[attribute_name]['default'])
139
def _should_validate_sub_attributes(attribute, sub_attr):
140
"""Verify that sub-attributes are iterable and should be validated."""
141
validate = attribute.get('validate')
142
return (validate and isinstance(sub_attr, collections.Iterable) and
143
any([k.startswith('type:dict') and
144
v for (k, v) in validate.iteritems()]))
130
147
def _build_subattr_match_rule(attr_name, attr, action, target):
131
148
"""Create the rule to match for sub-attribute policy checks."""
132
149
# TODO(salv-orlando): Instead of relying on validator info, introduce
164
181
action is being executed
165
182
(e.g.: create_router:external_gateway_info:network_id)
168
184
match_rule = policy.RuleCheck('rule', action)
169
185
resource, is_write = get_resource_and_action(action)
170
186
# Attribute-based checks shall not be enforced on GETs
175
191
for attribute_name in res_map[resource]:
176
192
if _is_attribute_explicitly_set(attribute_name,
177
193
res_map[resource],
179
195
attribute = res_map[resource][attribute_name]
180
196
if 'enforce_policy' in attribute:
181
197
attr_rule = policy.RuleCheck('rule', '%s:%s' %
182
198
(action, attribute_name))
183
# Build match entries for sub-attributes, if present
184
validate = attribute.get('validate')
185
if (validate and any([k.startswith('type:dict') and v
187
validate.iteritems()])):
199
# Build match entries for sub-attributes
200
if _should_validate_sub_attributes(
201
attribute, target[attribute_name]):
188
202
attr_rule = policy.AndCheck(
189
203
[attr_rule, _build_subattr_match_rule(
190
204
attribute_name, attribute,
318
332
def _prepare_check(context, action, target):
319
333
"""Prepare rule, target, and credentials for the policy engine."""
321
334
# Compare with None to distinguish case in which target is {}
322
335
if target is None:
326
339
return match_rule, target, credentials
329
def check(context, action, target, plugin=None):
342
def check(context, action, target, plugin=None, might_not_exist=False):
330
343
"""Verifies that the action is valid on the target in this context.
332
345
:param context: neutron context
337
350
location of the object e.g. ``{'project_id': context.project_id}``
338
351
:param plugin: currently unused and deprecated.
339
352
Kept for backward compatibility.
353
:param might_not_exist: If True the policy check is skipped (and the
354
function returns True) if the specified policy does not exist.
341
357
:return: Returns True if access is permitted else False.
343
return policy.check(*(_prepare_check(context, action, target)))
346
def check_if_exists(context, action, target):
347
"""Verify if the action can be authorized, and raise if it is unknown.
349
Check whether the action can be performed on the target within this
350
context, and raise a PolicyRuleNotFound exception if the action is
351
not defined in the policy engine.
353
# TODO(salvatore-orlando): Consider modifying oslo policy engine in
354
# order to allow to raise distinct exception when check fails and
355
# when policy is missing
356
# Raise if there's no match for requested action in the policy engine
357
if not policy._rules or action not in policy._rules:
358
raise exceptions.PolicyRuleNotFound(rule=action)
359
if might_not_exist and not (policy._rules and action in policy._rules):
359
361
return policy.check(*(_prepare_check(context, action, target)))
374
376
:raises neutron.exceptions.PolicyNotAuthorized: if verification fails.
378
379
rule, target, credentials = _prepare_check(context, action, target)
379
380
result = policy.check(rule, target, credentials, action=action)