pulp / pulpcore

Pulp 3 pulpcore package https://pypi.org/project/pulpcore/
GNU General Public License v2.0
301 stars 116 forks source link

Can't use global checks in boolean expressions in policy #1964

Closed pulpbot closed 2 years ago

pulpbot commented 2 years ago

Author: @goosemania (ttereshc)

Redmine Issue: 8187, https://pulp.plan.io/issues/8187


If the condition contains a boolean expression like below, and even though has_repo_attr_model_or_obj_perms is defined in global checks, it fails.

           {
                "action": ["destroy"],
                "principal": "authenticated",
                "effect": "allow",
                "condition": [
                    "(has_repo_attr_model_or_obj_perms:container.delete_containerrepository_versions or"
                    " has_repo_attr_model_or_obj_perms:container.view_containerrepository)",
                ]
           } 
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]: pulp [8f28125057bf41f1b157a7cb47848fca]: django.request:ERROR: Internal Server Error: /pulp/api/v3/repositories/container/container/46e44a17-dd48-4918-aa99-e54b6ea56b8d/versions/2/
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]: Traceback (most recent call last):
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     response = get_response(request)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     response = self.process_exception_by_middleware(e, request)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     response = wrapped_callback(request, *callback_args, **callback_kwargs)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     return view_func(*args, **kwargs)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     return self.dispatch(request, *args, **kwargs)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     response = self.handle_exception(exc)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     self.raise_uncaught_exception(exc)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     raise exc
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 497, in dispatch
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     self.initial(request, *args, **kwargs)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/home/vagrant/devel/pulpcore/pulpcore/app/viewsets/base.py", line 301, in initial
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     super().initial(request, *args, **kwargs)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 415, in initial
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     self.check_permissions(request)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     if not permission.has_permission(request, self):
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 23, in has_permission
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     return self._evaluate_statements(statements, request, view, action)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 59, in _evaluate_statements
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     matched = self._get_statements_matching_context_conditions(
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 160, in _get_statements_matching_context_conditions
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     passed = self._check_condition(condition, request, view, action)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 181, in _check_condition
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     method = self._get_condition_method(method_name)
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:   File "/usr/local/lib/pulp/lib64/python3.8/site-packages/rest_access_policy/access_policy.py", line 209, in _get_condition_method
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]:     raise AccessPolicyException(
Feb 01 19:17:34 pulp3-source-fedora32.rhgoose.example.com gunicorn[132380]: rest_access_policy.exceptions.AccessPolicyException: condition '(has_repo_attr_model_or_obj_perms' must be a method on the access policy or be defined in the 'reusable_conditions' module

The workaround is to split it into 2 policy statements:

            {
                "action": ["destroy"],
                "principal": "authenticated",
                "effect": "allow",
                "condition": [
                    "has_repo_attr_model_or_obj_perms:container.delete_containerrepository_versions", 
                ]
            },
            {
                "action": ["destroy"],
                "principal": "authenticated",
                "effect": "allow",
                "condition": [
                    "has_repo_attr_model_or_obj_perms:container.delete_containerrepository",
                ]
            },
gerrod3 commented 2 years ago

Global checks can use boolean expressions if you use condition_expression instead of condition. e.g.

         {
              "action": ["destroy"],
              "principal": "authenticated",
              "effect": "allow",
              "condition_expression": [
                  "(has_repo_attr_model_or_obj_perms:container.delete_containerrepository_versions or"
                  " has_repo_attr_model_or_obj_perms:container.view_containerrepository)",
              ]
         } 

Ref: https://rsinger86.github.io/drf-access-policy/object_level_permissions.html