]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fix pecan policy enforcement for GET requests
authorKevin Benton <blak111@gmail.com>
Tue, 15 Sep 2015 17:21:04 +0000 (10:21 -0700)
committerKevin Benton <blak111@gmail.com>
Tue, 15 Sep 2015 18:49:15 +0000 (11:49 -0700)
The policy enforcement hook had no effect on responses.
This patch corrected that. The fix was validated with the
standard API tests.

Change-Id: I014a18474ff79d48de469d7fc2a12c2e195ce22d

neutron/pecan_wsgi/hooks/policy_enforcement.py

index ac151c43560d1822b737b521bd3bb9b076259bed..c55096fc9efde86ab17e93c4eccb407357f91f14 100644 (file)
@@ -75,28 +75,41 @@ class PolicyHook(hooks.PecanHook):
             data = state.response.json
         except simplejson.JSONDecodeError:
             return
-        if not data:
+        action = '%s_%s' % (self.ACTION_MAP[state.request.method],
+                            resource_type)
+        plural = attribute_population._plural(resource_type)
+        if not data or (resource_type not in data and plural not in data):
             return
-        if resource_type in data:
-            # singular response
-            data[resource_type] = self._get_filtered_item(
-                state.request.context, resource_type, data[resource_type])
-        elif attribute_population._plural(resource_type) in data:
-            # plural response
-            plural = attribute_population._plural(resource_type)
-            data[plural] = [self._get_filtered_item(state.request.context,
-                                                    resource_type, item)
-                            for item in data[plural]]
+        is_single = resource_type in data
+        key = resource_type if is_single else plural
+        to_process = [data[resource_type]] if is_single else data[plural]
+        # in the single case, we enforce which raises on violation
+        # in the plural case, we just check so violating items are hidden
+        policy_method = policy.enforce if is_single else policy.check
+        resp = [self._get_filtered_item(state.request, resource_type, item)
+                for item in to_process
+                if (state.request.method != 'GET' or
+                    policy_method(state.request.context, action, item,
+                                  plugin=state.request.plugin,
+                                  pluralized=plural))]
+        if is_single:
+            resp = resp[0]
+        data[key] = resp
         state.response.json = data
 
-    def _get_filtered_item(self, context, resource_type, data):
-        to_exclude = self._exclude_attributes_by_policy(context,
+    def _get_filtered_item(self, request, resource_type, data):
+        to_exclude = self._exclude_attributes_by_policy(request.context,
                                                         resource_type, data)
-        return self._filter_attributes(context, data, to_exclude)
+        return self._filter_attributes(request, data, to_exclude)
 
-    def _filter_attributes(self, context, data, fields_to_strip):
+    def _filter_attributes(self, request, data, fields_to_strip):
+        # TODO(kevinbenton): this works but we didn't allow the plugin to
+        # only fetch the fields we are interested in. consider moving this
+        # to the call
+        user_fields = request.params.getall('fields')
         return dict(item for item in data.items()
-                    if (item[0] not in fields_to_strip))
+                    if (item[0] not in fields_to_strip and
+                        (not user_fields or item[0] in user_fields)))
 
     def _exclude_attributes_by_policy(self, context, resource_type, data):
         """Identifies attributes to exclude according to authZ policies.