Custom Processors
In situations where custom permission schemes are used, and are not detected by permissions auditor out of the box, you may need to write a custom processor.
Base Processors
All processors inherit from BaseProcessor
.
- class permissions_auditor.processors.base.BaseProcessor
- can_process(view)
Can this processor process the provided view?
- Parameters:
view (function or class) – the view being processed.
- Returns:
whether this processor can process the view. Default:
False
- Return type:
boolean
- get_docstring(view)
Returns any additional information that should be displayed when showing permisison information.
- Parameters:
view (function or class) – the view being processed.
- Returns:
the string to display in the additional info column. Default:
None
- Return type:
str or None
- get_login_required(view)
Returns if a user needs to be logged in to access the view.
- Parameters:
view (function or class) – the view being processed.
- Returns:
whether a user must be logged in to access this view. Default:
False
- Return type:
boolean or None (if unknown)
- get_permission_required(view)
Returns permissions required on the provided view. Must return an iterable.
- Parameters:
view (function or class) – the view being processed.
- Returns:
the permissions required to access the view. Default:
[]
- Return type:
list(str)
Other useful base classes:
- class permissions_auditor.processors.base.BaseFuncViewProcessor
Base class for processing function based views.
- class permissions_auditor.processors.base.BaseCBVProcessor
Base class for processing class based views.
- class permissions_auditor.processors.base.BaseDecoratorProcessor
Base class with utilities for unwrapping decorators.
- class permissions_auditor.processors.base.BaseFilteredMixinProcessor
Base class for parsing mixins on class based views. Set
class_filter
to filter the class names the processor applies to. ONLY checks top level base classes.- Variables:
class_filter – initial value:
None
- get_class_filter()
Override this method to override the class_names attribute. Must return an iterable.
- Returns:
a list of strings containing the full paths of mixins to detect.
- Raises:
ImproperlyConfigured – if the
class_filter
atribute isNone
.
Parsing Mixins
Creating a custom processor for mixins on class based views is fairly straight forward.
In this example, we have a mixin BobRequiredMixin
and a view that uses it, BobsPage
.
The mixin should only allow users with the first name Bob to access the page.
from django.core.exceptions import PermissionDenied
from django.views.generic import TemplateView
class BobRequiredMixin:
def dispatch(self, request, *args, **kwargs):
if self.request.user.first_name != 'Bob':
raise PermissionDenied("You are not Bob")
return super().dispatch(request, *args, **kwargs)
class BobsPage(BobRequiredMixin, TemplateView):
...
Let’s define our processor in processors.py.
from permissions_auditor.processors.base import BaseFilteredMixinProcessor
class BobRequiredMixinProcessor(BaseFilteredMixinProcessor):
class_filter = 'example_project.views.BobRequiredMixin'
def get_login_required(self, view):
return True
def get_docstring(self, view):
return "The user's first name must be Bob to view."
To register our processor, we need to add it to PERMISSIONS_AUDITOR_PROCESSORS in our project settings.
PERMISSIONS_AUDITOR_PROCESSORS = [
...
'example_project.processors.BobRequiredProcessor',
]
When BobsPage
is registered to a URL, we should see this in the admin panel:
Name |
URL |
Permission Required |
Login Required |
Additional Info |
---|---|---|---|---|
BobsPage |
/ |
True |
The user’s first name must be Bob to view. |
Perhaps we want to make our mixin configurable so we can detect different names depending on the view.
We also have multiple people with the same first name, so we also want to check for a permission:
example.view_pages
.
class FirstNameRequiredMixin:
required_first_name = ''
def dispatch(self, request, *args, **kwargs):
if not (self.request.user.has_perm('example_app.view_userpages')
and self.request.user.first_name == self.required_first_name):
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
class GeorgesPage(FirstNameRequiredMixin, TemplateView):
required_first_name = 'George'
...
We’ll modify class_filter
and get_docstring()
from our old processor, and override
get_permission_required()
.
from permissions_auditor.processors.base import BaseFilteredMixinProcessor
class FirstNameRequiredMixinProcessor(BaseFilteredMixinProcessor):
class_filter = 'example_project.views.FirstNameRequiredMixin'
def get_permission_required(self, view):
return ['example.view_pages']
def get_login_required(self, view):
return True
def get_docstring(self, view):
return "The user's first name must be {} to view.".format(view.first_name_required)
Once we register our view to a URL and register the processor, our admin table should look like this:
Name |
URL |
Permission Required |
Login Required |
Additional Info |
---|---|---|---|---|
GeorgesPage |
/ |
example.view_pages |
True |
The user’s first name must be George to view. |
Additional Examples
See the permissions_auditor/processors/
folder in the source code for more examples.