rsinger86 / drf-access-policy

Declarative access policies/permissions modeled after AWS' IAM policies.
https://rsinger86.github.io/drf-access-policy/
MIT License
466 stars 50 forks source link

[BUG] <lambda>() missing 1 required positional argument: 'token' #83

Closed samul-1 closed 2 years ago

samul-1 commented 2 years ago

I had this error in production a couple of times.

The statement that caused it is the following:

{
            "action": ["retrieve", "update", "partial_update"],
            "principal": ["authenticated"],
            "effect": "deny",
            "condition_expression": "not has_teacher_privileges:assess_participations and not is_slot_in_scope",
}
   def has_teacher_privileges(self, request, view, action, privilege):
        from courses.models import Course
        from courses.views import CourseViewSet

        course_pk = (
            view.kwargs.get("pk")
            if isinstance(view, CourseViewSet)
            else view.kwargs.get("course_pk")  # nested view
        )

        try:
            course = Course.objects.get(pk=course_pk)
        except ValueError:
            return False

        return check_privilege(request.user, course, privilege)

    def is_slot_in_scope(self, request, view, action):
        slot = view.get_object()
        return slot.is_in_scope()

This condition expression works most times, but sometimes it errors like I described. I haven't yet been able to identify what causes this, but I don't believe it to be something that has to do with my code. It looks like a bug in drf-access-policy.

Full stack trace:

 Traceback (most recent call last):
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 451, in thread_handler
     raise exc_info[1]
   File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/exception.py", line 42, in inner
     response = await get_response(request)
   File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
     response = await wrapped_callback(
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 414, in __call__
     ret = await asyncio.wait_for(future, timeout=None)
   File "/app/.heroku/python/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
     return await fut
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/current_thread_executor.py", line 22, in run
     result = self.fn(*self.args, **self.kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 455, in thread_handler
     return func(*args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/sentry_sdk/integrations/django/views.py", line 67, in sentry_wrapped_callback
     return callback(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
     return view_func(*args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
     return self.dispatch(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
     response = self.handle_exception(exc)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
     self.raise_uncaught_exception(exc)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
     raise exc
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 497, in dispatch
     self.initial(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py", line 271, in sentry_patched_drf_initial
     return old_drf_initial(self, request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 415, in initial
     self.check_permissions(request)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
     if not permission.has_permission(request, self):
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 52, in has_permission
     allowed = self._evaluate_statements(statements, request, view, action)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 94, in _evaluate_statements
     matched = self._get_statements_matching_conditions(
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 214, in _get_statements_matching_conditions
     passed = bool(boolExpr.parseString(condition)[0])
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 1124, in parse_string
     loc, tokens = self._parse(instring, 0)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3841, in parseImpl
     loc, resultlist = self.exprs[0]._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 849, in _parseNoCache
     tokens = fn(instring, tokens_start, ret_tokens)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 285, in wrapper
     ret = func(*args[limit:])
 TypeError: <lambda>() missing 1 required positional argument: 'token'
 Internal Server Error: /courses/7/events/83P423W/participations/415/slots/3984/
 Traceback (most recent call last):
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 451, in thread_handler
     raise exc_info[1]
   File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/exception.py", line 42, in inner
     response = await get_response(request)
   File "/app/.heroku/python/lib/python3.8/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
     response = await wrapped_callback(
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 414, in __call__
     ret = await asyncio.wait_for(future, timeout=None)
   File "/app/.heroku/python/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
     return await fut
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/current_thread_executor.py", line 22, in run
     result = self.fn(*self.args, **self.kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/asgiref/sync.py", line 455, in thread_handler
     return func(*args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/sentry_sdk/integrations/django/views.py", line 67, in sentry_wrapped_callback
     return callback(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
     return view_func(*args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
     return self.dispatch(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
     response = self.handle_exception(exc)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
     self.raise_uncaught_exception(exc)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
     raise exc
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 497, in dispatch
     self.initial(request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py", line 271, in sentry_patched_drf_initial
     return old_drf_initial(self, request, *args, **kwargs)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 415, in initial
     self.check_permissions(request)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_framework/views.py", line 332, in check_permissions
     if not permission.has_permission(request, self):
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 52, in has_permission
     allowed = self._evaluate_statements(statements, request, view, action)
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 94, in _evaluate_statements
     matched = self._get_statements_matching_conditions(
   File "/app/.heroku/python/lib/python3.8/site-packages/rest_access_policy/access_policy.py", line 214, in _get_statements_matching_conditions
     passed = bool(boolExpr.parseString(condition)[0])
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 1124, in parse_string
     loc, tokens = self._parse(instring, 0)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4767, in parseImpl
     loc, tokens = self_expr_parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 3863, in parseImpl
     loc, exprtokens = e._parse(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 5203, in parseImpl
     return super().parseImpl(instring, loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4352, in parseImpl
     return self.expr._parse(instring, loc, doActions, callPreParse=False)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 810, in _parseNoCache
     loc, tokens = self.parseImpl(instring, pre_loc, doActions)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 4091, in parseImpl
     return e._parse(
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 849, in _parseNoCache
     tokens = fn(instring, tokens_start, ret_tokens)
   File "/app/.heroku/python/lib/python3.8/site-packages/pyparsing/core.py", line 285, in wrapper
     ret = func(*args[limit:])
 TypeError: <lambda>() missing 1 required positional argument: 'token'

What caused this? Is there any issue with the condition(s) I wrote?

glterica commented 2 years ago

I have also just come across this error. It seems to happen when there are many requests at once, but it's also happening quite randomly and I'm having trouble reproducing the error consistently.

Has there been any development on this?

rsinger86 commented 2 years ago

It sounds like some state is unintentionally shared across requests.

Do you think this line could be the source of it? https://github.com/rsinger86/drf-access-policy/blob/master/rest_access_policy/access_policy.py#L209

The boolOperand object instance is shared and one request modifies it while another thinks it's setParseAction mod is still there?

mari8i commented 2 years ago

Yes @rsinger86 that is the problem. I've created a PR #86 that fixes it. Would be great if you could have a look in to that!