126
126
% self._plugin.__class__.__name__)
127
127
return getattr(self._plugin, native_sorting_attr_name, False)
129
def _is_visible(self, context, attr_name, data):
130
action = "%s:%s" % (self._plugin_handlers[self.SHOW], attr_name)
131
# Optimistically init authz_check to True
134
attr = (attributes.RESOURCE_ATTRIBUTE_MAP
135
[self._collection].get(attr_name))
136
if attr and attr.get('enforce_policy'):
137
authz_check = policy.check_if_exists(
138
context, action, data)
140
# The extension was not configured for adding its resources
141
# to the global resource attribute map. Policy check should
143
LOG.debug(_("The resource %(resource)s was not found in the "
144
"RESOURCE_ATTRIBUTE_MAP; unable to perform authZ "
145
"check for attribute %(attr)s"),
146
{'resource': self._collection,
148
except exceptions.PolicyRuleNotFound:
149
# Just ignore the exception. Do not even log it, as this will add
150
# a lot of unnecessary info in the log (and take time as well to
151
# write info to the logger)
153
attr_val = self._attr_info.get(attr_name)
154
return attr_val and attr_val['is_visible'] and authz_check
129
def _exclude_attributes_by_policy(self, context, data):
130
"""Identifies attributes to exclude according to authZ policies.
132
Return a list of attribute names which should be stripped from the
133
response returned to the user because the user is not authorized
136
attributes_to_exclude = []
137
for attr_name in data.keys():
138
attr_data = self._attr_info.get(attr_name)
139
if attr_data and attr_data['is_visible']:
142
'%s:%s' % (self._plugin_handlers[self.SHOW], attr_name),
144
might_not_exist=True):
145
# this attribute is visible, check next one
147
# if the code reaches this point then either the policy check
148
# failed or the attribute was not visible in the first place
149
attributes_to_exclude.append(attr_name)
150
return attributes_to_exclude
156
152
def _view(self, context, data, fields_to_strip=None):
157
# make sure fields_to_strip is iterable
153
"""Build a view of an API resource.
155
:param context: the neutron context
156
:param data: the object for which a view is being created
157
:param fields_to_strip: attributes to remove from the view
159
:returns: a view of the object which includes only attributes
160
visible according to API resource declaration and authZ policies.
162
fields_to_strip = ((fields_to_strip or []) +
163
self._exclude_attributes_by_policy(context, data))
164
return self._filter_attributes(context, data, fields_to_strip)
166
def _filter_attributes(self, context, data, fields_to_strip=None):
158
167
if not fields_to_strip:
161
169
return dict(item for item in data.iteritems()
162
if (self._is_visible(context, item[0], data) and
163
item[0] not in fields_to_strip))
170
if (item[0] not in fields_to_strip))
165
172
def _do_field_list(self, original_fields):
166
173
fields_to_add = None
246
252
self._plugin_handlers[self.SHOW],
248
254
plugin=self._plugin)]
255
# Use the first element in the list for discriminating which attributes
256
# should be filtered out because of authZ policies
257
# fields_to_add contains a list of attributes added for request policy
258
# checks but that were not required by the user. They should be
260
fields_to_strip = fields_to_add or []
262
fields_to_strip += self._exclude_attributes_by_policy(
263
request.context, obj_list[0])
249
264
collection = {self._collection:
250
[self._view(request.context, obj,
251
fields_to_strip=fields_to_add)
265
[self._filter_attributes(
266
request.context, obj,
267
fields_to_strip=fields_to_strip)
252
268
for obj in obj_list]}
253
269
pagination_links = pagination_helper.get_links(obj_list)
254
270
if pagination_links:
255
271
collection[self._collection + "_links"] = pagination_links
257
272
return collection
259
274
def _item(self, request, id, do_authz=False, field_list=None,
316
335
kwargs = {self._resource: item}
318
337
kwargs[self._parent_id_name] = parent_id
319
objs.append(self._view(request.context,
320
obj_creator(request.context,
338
fields_to_strip = self._exclude_attributes_by_policy(
339
request.context, item)
340
objs.append(self._filter_attributes(
342
obj_creator(request.context, **kwargs),
343
fields_to_strip=fields_to_strip))
323
345
# Note(salvatore-orlando): broad catch as in theory a plugin
324
346
# could raise any kind of exception
405
429
# plugin does atomic bulk create operations
406
430
obj_creator = getattr(self._plugin, "%s_bulk" % action)
407
431
objs = obj_creator(request.context, body, **kwargs)
408
return notify({self._collection: [self._view(request.context, obj)
432
# Use first element of list to discriminate attributes which
433
# should be removed because of authZ policies
434
fields_to_strip = self._exclude_attributes_by_policy(
435
request.context, objs[0])
436
return notify({self._collection: [self._filter_attributes(
437
request.context, obj, fields_to_strip=fields_to_strip)
411
440
obj_creator = getattr(self._plugin, action)
412
441
if self._collection in body:
484
514
if (value.get('required_by_policy') or
485
515
value.get('primary_key') or
486
516
'default' not in value)]
517
# Ensure policy engine is initialized
487
519
orig_obj = self._item(request, id, field_list=field_list,
488
520
parent_id=parent_id)
489
521
orig_object_copy = copy.copy(orig_obj)
490
522
orig_obj.update(body[self._resource])
523
# Make a list of attributes to be updated to inform the policy engine
524
# which attributes are set explicitly so that it can distinguish them
525
# from the ones that are set to their default values.
526
orig_obj[const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys()
492
528
policy.enforce(request.context,