~corey.bryant/ubuntu/trusty/neutron/lp1318721

« back to all changes in this revision

Viewing changes to neutron/api/v2/base.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Corey Bryant
  • Date: 2014-10-06 09:15:06 UTC
  • mfrom: (28.1.4 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20141006091506-cesvev43moce4y74
Tags: 1:2014.1.3-0ubuntu1
[ Corey Bryant ]
* Resynchronize with stable/icehouse (4a0210e) (LP: #1377136):
  - [3a30d19] Deletes floating ip related connection states
  - [dd4b77f] Forbid regular users to reset admin-only attrs to default values
  - [dc2c893] Add delete operations for the ODL MechanismDriver
  - [b51e2c7] Add missing ml2 plugin to migration 1fcfc149aca4
  - [a17a500] Don't convert numeric protocol values to int
  - [3a85946] NSX: Optionally not enforce nat rule match length check
  - [645f984] Don't spawn metadata-proxy for non-isolated nets
  - [b464d89] Big Switch: Check for 'id' in port before lookup
  - [3116ffa] use TRUE in SQL for boolean var
  - [3520e66] call security_groups_member_updated in port_update
  - [50e1534] Don't allow user to set firewall rule with port and no protocol
  - [0061533] BSN: Add context to backend request for debugging
  - [6de6d61] Improve ODL ML2 Exception Handling
  - [2a4153d] Send network name and uuid to subnet create
  - [b5e3c9a] BSN: Allow concurrent reads to consistency DB
  - [b201432] Big Switch: Retry on 503 errors from backend
  - [f6c47ee] NSX: log request body to NSX as debug
  - [97d622a] Fix metadata agent's auth info caching
  - [255df45] NSX: Correct allowed_address_pair return value on create_port
  - [5bea041] Neutron should not use the neutronclient utils module for import_class
  - [d5314e2] Cisco N1kv plugin to send subtype on network profile creation
  - [f32d1ce] Pass object to policy when finding fields to strip
  - [8b5f6be] Call policy.init() once per API request
  - [9a6d811] Perform policy checks only once on list responses
  - [c48db90] Datacenter moid should not be tuple
  - [161d465] Allow unsharing a network used as gateway/floatingip
  - [9574a2f] Add support for router scheduling in Cisco N1kv Plugin
  - [6f54565] Fix func job hook script permission problems
  - [ea43103] Add hook scripts for the functional infra job
  - [8161cb7] Fixes Hyper-V agent issue on Hyper-V 2008 R2
  - [8e99cfd] Fixes Hyper-V issue due to ML2 RPC versioning
  - [69f9121] Ensure ip6tables are used only if ipv6 is enabled in kernel
  - [399b809] Remove explicit dependency on amqplib
  - [a872143] Clear entries in Cisco N1KV specific tables on rollback
  - [ad82fad] Verify ML2 type driver exists before calling del
  - [af2cc98] Big Switch: Only update hash header on success
  - [b1e5eec] Ignore variable column widths in ovsdb functional tests
  - [4a0210e] VMWare: don't notify on disassociate_floatingips()

Show diffs side-by-side

added added

removed removed

Lines of Context:
126
126
                                    % self._plugin.__class__.__name__)
127
127
        return getattr(self._plugin, native_sorting_attr_name, False)
128
128
 
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
132
 
        authz_check = True
133
 
        try:
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)
139
 
        except KeyError:
140
 
            # The extension was not configured for adding its resources
141
 
            # to the global resource attribute map. Policy check should
142
 
            # not be performed
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,
147
 
                       'attr': attr_name})
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)
152
 
            pass
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.
 
131
 
 
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
 
134
        to see them.
 
135
        """
 
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']:
 
140
                if policy.check(
 
141
                    context,
 
142
                    '%s:%s' % (self._plugin_handlers[self.SHOW], attr_name),
 
143
                    data,
 
144
                    might_not_exist=True):
 
145
                    # this attribute is visible, check next one
 
146
                    continue
 
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
155
151
 
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.
 
154
 
 
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
 
158
 
 
159
        :returns: a view of the object which includes only attributes
 
160
        visible according to API resource declaration and authZ policies.
 
161
        """
 
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)
 
165
 
 
166
    def _filter_attributes(self, context, data, fields_to_strip=None):
158
167
        if not fields_to_strip:
159
 
            fields_to_strip = []
160
 
 
 
168
            return data
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))
164
171
 
165
172
    def _do_field_list(self, original_fields):
166
173
        fields_to_add = None
175
182
        if name in self._member_actions:
176
183
            def _handle_action(request, id, **kwargs):
177
184
                arg_list = [request.context, id]
 
185
                # Ensure policy engine is initialized
 
186
                policy.init()
178
187
                # Fetch the resource and verify if the user can access it
179
188
                try:
180
189
                    resource = self._item(request, id, True)
185
194
                # Explicit comparison with None to distinguish from {}
186
195
                if body is not None:
187
196
                    arg_list.append(body)
188
 
                # TODO(salvatore-orlando): bp/make-authz-ortogonal
189
 
                # The body of the action request should be included
190
 
                # in the info passed to the policy engine
191
197
                # It is ok to raise a 403 because accessibility to the
192
198
                # object was checked earlier in this method
193
199
                policy.enforce(request.context, name, resource)
246
252
                                        self._plugin_handlers[self.SHOW],
247
253
                                        obj,
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
 
259
        # therefore stripped
 
260
        fields_to_strip = fields_to_add or []
 
261
        if obj_list:
 
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
256
 
 
257
272
        return collection
258
273
 
259
274
    def _item(self, request, id, do_authz=False, field_list=None,
284
299
    def index(self, request, **kwargs):
285
300
        """Returns a list of the requested entity."""
286
301
        parent_id = kwargs.get(self._parent_id_name)
 
302
        # Ensure policy engine is initialized
 
303
        policy.init()
287
304
        return self._items(request, True, parent_id)
288
305
 
289
306
    def show(self, request, id, **kwargs):
295
312
            field_list, added_fields = self._do_field_list(
296
313
                api_common.list_args(request, "fields"))
297
314
            parent_id = kwargs.get(self._parent_id_name)
 
315
            # Ensure policy engine is initialized
 
316
            policy.init()
298
317
            return {self._resource:
299
318
                    self._view(request.context,
300
319
                               self._item(request,
316
335
                kwargs = {self._resource: item}
317
336
                if parent_id:
318
337
                    kwargs[self._parent_id_name] = parent_id
319
 
                objs.append(self._view(request.context,
320
 
                                       obj_creator(request.context,
321
 
                                                   **kwargs)))
 
338
                fields_to_strip = self._exclude_attributes_by_policy(
 
339
                    request.context, item)
 
340
                objs.append(self._filter_attributes(
 
341
                    request.context,
 
342
                    obj_creator(request.context, **kwargs),
 
343
                    fields_to_strip=fields_to_strip))
322
344
            return objs
323
345
        # Note(salvatore-orlando): broad catch as in theory a plugin
324
346
        # could raise any kind of exception
363
385
        else:
364
386
            items = [body]
365
387
            bulk = False
 
388
        # Ensure policy engine is initialized
 
389
        policy.init()
366
390
        for item in items:
367
391
            self._validate_network_tenant_ownership(request,
368
392
                                                    item[self._resource])
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)
409
 
                                              for obj in objs]})
 
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)
 
438
                for obj in objs]})
410
439
        else:
411
440
            obj_creator = getattr(self._plugin, action)
412
441
            if self._collection in body:
420
449
 
421
450
                self._nova_notifier.send_network_change(
422
451
                    action, {}, {self._resource: obj})
423
 
                return notify({self._resource: self._view(request.context,
424
 
                                                          obj)})
 
452
                return notify({self._resource: self._view(
 
453
                    request.context, obj)})
425
454
 
426
455
    def delete(self, request, id, **kwargs):
427
456
        """Deletes the specified entity."""
433
462
        action = self._plugin_handlers[self.DELETE]
434
463
 
435
464
        # Check authz
 
465
        policy.init()
436
466
        parent_id = kwargs.get(self._parent_id_name)
437
467
        obj = self._item(request, id, parent_id=parent_id)
438
468
        try:
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
 
518
        policy.init()
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()
491
527
        try:
492
528
            policy.enforce(request.context,
493
529
                           action,