Add RolePermission for API endpoints

This commit is contained in:
Oliver Walters 2021-02-26 13:53:23 +11:00
parent 1dfda5b0ed
commit cd8c6fa81a
2 changed files with 89 additions and 1 deletions

View File

@ -20,6 +20,8 @@ from rest_framework.views import APIView
from .views import AjaxView from .views import AjaxView
from .version import inventreeVersion, inventreeInstanceName from .version import inventreeVersion, inventreeInstanceName
from users.models import check_user_role, RuleSet
from plugins import plugins as inventree_plugins from plugins import plugins as inventree_plugins
@ -70,6 +72,85 @@ class AttachmentMixin:
attachment.save() attachment.save()
class RolePermission(permissions.BasePermission):
"""
Role mixin for API endpoints, allowing us to specify the user "role"
which is required for certain operations.
Each endpoint can have one or more of the following actions:
- GET
- POST
- PUT
- PATCH
- DELETE
Specify the required "role" using the role_required attribute.
e.g.
role_required = "part"
The RoleMixin class will then determine if the user has the required permission
to perform the specified action.
For example, a DELETE action will be rejected unless the user has the "part.remove" permission
"""
def has_permission(self, request, view):
"""
Determine if the current user has the specified permissions
"""
# First, check that the user is authenticated!
auth = permissions.IsAuthenticated()
if not auth.has_permission(request, view):
return False
user = request.user
# Superuser can do it all
if False and user.is_superuser:
return True
# Map the request method to a permission type
rolemap = {
'GET': 'view',
'OPTIONS': 'view',
'POST': 'add',
'PUT': 'change',
'PATCH': 'change',
'DELETE': 'delete',
}
permission = rolemap[request.method]
role = getattr(view, 'role_required', None)
if not role:
raise AttributeError(f"'role_required' not specified for view {type(view).__name__}")
roles = []
if type(role) is str:
roles = [role]
elif type(role) in [list, tuple]:
roles = role
else:
raise TypeError(f"'role_required' is of incorrect type ({type(role)}) for view {type(view).__name__}")
for role in roles:
if role not in RuleSet.RULESET_NAMES:
raise ValueError(f"Role '{role}' is not a valid role")
if not check_user_role(user, role, permission):
return False
# All checks passed
return True
class ActionPluginView(APIView): class ActionPluginView(APIView):
""" """
Endpoint for running custom action plugins. Endpoint for running custom action plugins.

View File

@ -29,7 +29,8 @@ from . import serializers as part_serializers
from InvenTree.views import TreeSerializer from InvenTree.views import TreeSerializer
from InvenTree.helpers import str2bool, isNull from InvenTree.helpers import str2bool, isNull
from InvenTree.api import AttachmentMixin from InvenTree.api import AttachmentMixin, RolePermission
from InvenTree.status_codes import BuildStatus from InvenTree.status_codes import BuildStatus
@ -105,6 +106,12 @@ class CategoryList(generics.ListCreateAPIView):
'description', 'description',
] ]
role_required = 'part'
permission_classes = [
RolePermission,
]
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single PartCategory object """ """ API endpoint for detail view of a single PartCategory object """